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.ContentInfo.SOURCE_DRAG_AND_DROP; 21 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 22 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; 23 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 24 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; 25 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; 26 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; 27 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; 28 29 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 30 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 31 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 32 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 33 34 import static java.lang.Math.max; 35 36 import android.animation.AnimatorInflater; 37 import android.animation.StateListAnimator; 38 import android.annotation.AttrRes; 39 import android.annotation.CallSuper; 40 import android.annotation.ColorInt; 41 import android.annotation.DrawableRes; 42 import android.annotation.FloatRange; 43 import android.annotation.IdRes; 44 import android.annotation.IntDef; 45 import android.annotation.IntRange; 46 import android.annotation.LayoutRes; 47 import android.annotation.NonNull; 48 import android.annotation.Nullable; 49 import android.annotation.Size; 50 import android.annotation.StyleRes; 51 import android.annotation.SuppressLint; 52 import android.annotation.TestApi; 53 import android.annotation.UiContext; 54 import android.annotation.UiThread; 55 import android.compat.annotation.UnsupportedAppUsage; 56 import android.content.AutofillOptions; 57 import android.content.ClipData; 58 import android.content.ClipDescription; 59 import android.content.Context; 60 import android.content.ContextWrapper; 61 import android.content.Intent; 62 import android.content.res.ColorStateList; 63 import android.content.res.Configuration; 64 import android.content.res.Resources; 65 import android.content.res.TypedArray; 66 import android.graphics.Bitmap; 67 import android.graphics.BlendMode; 68 import android.graphics.Canvas; 69 import android.graphics.Color; 70 import android.graphics.Insets; 71 import android.graphics.Interpolator; 72 import android.graphics.LinearGradient; 73 import android.graphics.Matrix; 74 import android.graphics.Outline; 75 import android.graphics.Paint; 76 import android.graphics.PixelFormat; 77 import android.graphics.Point; 78 import android.graphics.PorterDuff; 79 import android.graphics.PorterDuffXfermode; 80 import android.graphics.RecordingCanvas; 81 import android.graphics.Rect; 82 import android.graphics.RectF; 83 import android.graphics.Region; 84 import android.graphics.RenderEffect; 85 import android.graphics.RenderNode; 86 import android.graphics.Shader; 87 import android.graphics.drawable.ColorDrawable; 88 import android.graphics.drawable.Drawable; 89 import android.graphics.drawable.GradientDrawable; 90 import android.hardware.display.DisplayManagerGlobal; 91 import android.net.Uri; 92 import android.os.Build; 93 import android.os.Bundle; 94 import android.os.Handler; 95 import android.os.IBinder; 96 import android.os.Message; 97 import android.os.Parcel; 98 import android.os.Parcelable; 99 import android.os.RemoteCallback; 100 import android.os.RemoteException; 101 import android.os.SystemClock; 102 import android.os.Trace; 103 import android.sysprop.DisplayProperties; 104 import android.text.InputType; 105 import android.text.TextUtils; 106 import android.util.AttributeSet; 107 import android.util.FloatProperty; 108 import android.util.LayoutDirection; 109 import android.util.Log; 110 import android.util.LongSparseArray; 111 import android.util.LongSparseLongArray; 112 import android.util.Pair; 113 import android.util.Pools.SynchronizedPool; 114 import android.util.Property; 115 import android.util.SparseArray; 116 import android.util.SparseIntArray; 117 import android.util.StateSet; 118 import android.util.SuperNotCalledException; 119 import android.util.TypedValue; 120 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 121 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 122 import android.view.AccessibilityIterators.TextSegmentIterator; 123 import android.view.AccessibilityIterators.WordTextSegmentIterator; 124 import android.view.ContextMenu.ContextMenuInfo; 125 import android.view.InputDevice.InputSourceClass; 126 import android.view.Window.OnContentApplyWindowInsetsListener; 127 import android.view.WindowInsets.Type; 128 import android.view.WindowInsetsAnimation.Bounds; 129 import android.view.WindowManager.LayoutParams; 130 import android.view.accessibility.AccessibilityEvent; 131 import android.view.accessibility.AccessibilityEventSource; 132 import android.view.accessibility.AccessibilityManager; 133 import android.view.accessibility.AccessibilityNodeIdManager; 134 import android.view.accessibility.AccessibilityNodeInfo; 135 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 136 import android.view.accessibility.AccessibilityNodeProvider; 137 import android.view.accessibility.AccessibilityWindowInfo; 138 import android.view.animation.Animation; 139 import android.view.animation.AnimationUtils; 140 import android.view.animation.Transformation; 141 import android.view.autofill.AutofillId; 142 import android.view.autofill.AutofillManager; 143 import android.view.autofill.AutofillValue; 144 import android.view.contentcapture.ContentCaptureContext; 145 import android.view.contentcapture.ContentCaptureManager; 146 import android.view.contentcapture.ContentCaptureSession; 147 import android.view.displayhash.DisplayHash; 148 import android.view.displayhash.DisplayHashManager; 149 import android.view.displayhash.DisplayHashResultCallback; 150 import android.view.inputmethod.EditorInfo; 151 import android.view.inputmethod.InputConnection; 152 import android.view.inspector.InspectableProperty; 153 import android.view.inspector.InspectableProperty.EnumEntry; 154 import android.view.inspector.InspectableProperty.FlagEntry; 155 import android.view.translation.TranslationCapability; 156 import android.view.translation.TranslationSpec.DataFormat; 157 import android.view.translation.ViewTranslationCallback; 158 import android.view.translation.ViewTranslationRequest; 159 import android.view.translation.ViewTranslationResponse; 160 import android.widget.Checkable; 161 import android.widget.FrameLayout; 162 import android.widget.ScrollBarDrawable; 163 164 import com.android.internal.R; 165 import com.android.internal.util.ArrayUtils; 166 import com.android.internal.util.FrameworkStatsLog; 167 import com.android.internal.util.Preconditions; 168 import com.android.internal.view.ScrollCaptureInternal; 169 import com.android.internal.view.TooltipPopup; 170 import com.android.internal.view.menu.MenuBuilder; 171 import com.android.internal.widget.ScrollBarUtils; 172 173 import com.google.android.collect.Lists; 174 import com.google.android.collect.Maps; 175 176 import java.io.PrintWriter; 177 import java.lang.annotation.Retention; 178 import java.lang.annotation.RetentionPolicy; 179 import java.lang.ref.WeakReference; 180 import java.lang.reflect.Field; 181 import java.lang.reflect.InvocationTargetException; 182 import java.lang.reflect.Method; 183 import java.lang.reflect.Modifier; 184 import java.util.ArrayList; 185 import java.util.Arrays; 186 import java.util.Calendar; 187 import java.util.Collection; 188 import java.util.Collections; 189 import java.util.HashMap; 190 import java.util.List; 191 import java.util.Locale; 192 import java.util.Map; 193 import java.util.concurrent.CopyOnWriteArrayList; 194 import java.util.concurrent.Executor; 195 import java.util.concurrent.atomic.AtomicInteger; 196 import java.util.function.Consumer; 197 import java.util.function.Predicate; 198 199 /** 200 * <p> 201 * This class represents the basic building block for user interface components. A View 202 * occupies a rectangular area on the screen and is responsible for drawing and 203 * event handling. View is the base class for <em>widgets</em>, which are 204 * used to create interactive UI components (buttons, text fields, etc.). The 205 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 206 * are invisible containers that hold other Views (or other ViewGroups) and define 207 * their layout properties. 208 * </p> 209 * 210 * <div class="special reference"> 211 * <h3>Developer Guides</h3> 212 * <p>For information about using this class to develop your application's user interface, 213 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 214 * </div> 215 * 216 * <a name="Using"></a> 217 * <h3>Using Views</h3> 218 * <p> 219 * All of the views in a window are arranged in a single tree. You can add views 220 * either from code or by specifying a tree of views in one or more XML layout 221 * files. There are many specialized subclasses of views that act as controls or 222 * are capable of displaying text, images, or other content. 223 * </p> 224 * <p> 225 * Once you have created a tree of views, there are typically a few types of 226 * common operations you may wish to perform: 227 * <ul> 228 * <li><strong>Set properties:</strong> for example setting the text of a 229 * {@link android.widget.TextView}. The available properties and the methods 230 * that set them will vary among the different subclasses of views. Note that 231 * properties that are known at build time can be set in the XML layout 232 * files.</li> 233 * <li><strong>Set focus:</strong> The framework will handle moving focus in 234 * response to user input. To force focus to a specific view, call 235 * {@link #requestFocus}.</li> 236 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 237 * that will be notified when something interesting happens to the view. For 238 * example, all views will let you set a listener to be notified when the view 239 * gains or loses focus. You can register such a listener using 240 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 241 * Other view subclasses offer more specialized listeners. For example, a Button 242 * exposes a listener to notify clients when the button is clicked.</li> 243 * <li><strong>Set visibility:</strong> You can hide or show views using 244 * {@link #setVisibility(int)}.</li> 245 * </ul> 246 * </p> 247 * <p><em> 248 * Note: The Android framework is responsible for measuring, laying out and 249 * drawing views. You should not call methods that perform these actions on 250 * views yourself unless you are actually implementing a 251 * {@link android.view.ViewGroup}. 252 * </em></p> 253 * 254 * <a name="Lifecycle"></a> 255 * <h3>Implementing a Custom View</h3> 256 * 257 * <p> 258 * To implement a custom view, you will usually begin by providing overrides for 259 * some of the standard methods that the framework calls on all views. You do 260 * not need to override all of these methods. In fact, you can start by just 261 * overriding {@link #onDraw(android.graphics.Canvas)}. 262 * <table border="2" width="85%" align="center" cellpadding="5"> 263 * <thead> 264 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 265 * </thead> 266 * 267 * <tbody> 268 * <tr> 269 * <td rowspan="2">Creation</td> 270 * <td>Constructors</td> 271 * <td>There is a form of the constructor that are called when the view 272 * is created from code and a form that is called when the view is 273 * inflated from a layout file. The second form should parse and apply 274 * any attributes defined in the layout file. 275 * </td> 276 * </tr> 277 * <tr> 278 * <td><code>{@link #onFinishInflate()}</code></td> 279 * <td>Called after a view and all of its children has been inflated 280 * from XML.</td> 281 * </tr> 282 * 283 * <tr> 284 * <td rowspan="3">Layout</td> 285 * <td><code>{@link #onMeasure(int, int)}</code></td> 286 * <td>Called to determine the size requirements for this view and all 287 * of its children. 288 * </td> 289 * </tr> 290 * <tr> 291 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 292 * <td>Called when this view should assign a size and position to all 293 * of its children. 294 * </td> 295 * </tr> 296 * <tr> 297 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 298 * <td>Called when the size of this view has changed. 299 * </td> 300 * </tr> 301 * 302 * <tr> 303 * <td>Drawing</td> 304 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 305 * <td>Called when the view should render its content. 306 * </td> 307 * </tr> 308 * 309 * <tr> 310 * <td rowspan="4">Event processing</td> 311 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 312 * <td>Called when a new hardware key event occurs. 313 * </td> 314 * </tr> 315 * <tr> 316 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 317 * <td>Called when a hardware key up event occurs. 318 * </td> 319 * </tr> 320 * <tr> 321 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 322 * <td>Called when a trackball motion event occurs. 323 * </td> 324 * </tr> 325 * <tr> 326 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 327 * <td>Called when a touch screen motion event occurs. 328 * </td> 329 * </tr> 330 * 331 * <tr> 332 * <td rowspan="2">Focus</td> 333 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 334 * <td>Called when the view gains or loses focus. 335 * </td> 336 * </tr> 337 * 338 * <tr> 339 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 340 * <td>Called when the window containing the view gains or loses focus. 341 * </td> 342 * </tr> 343 * 344 * <tr> 345 * <td rowspan="3">Attaching</td> 346 * <td><code>{@link #onAttachedToWindow()}</code></td> 347 * <td>Called when the view is attached to a window. 348 * </td> 349 * </tr> 350 * 351 * <tr> 352 * <td><code>{@link #onDetachedFromWindow}</code></td> 353 * <td>Called when the view is detached from its window. 354 * </td> 355 * </tr> 356 * 357 * <tr> 358 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 359 * <td>Called when the visibility of the window containing the view 360 * has changed. 361 * </td> 362 * </tr> 363 * </tbody> 364 * 365 * </table> 366 * </p> 367 * 368 * <a name="IDs"></a> 369 * <h3>IDs</h3> 370 * Views may have an integer id associated with them. These ids are typically 371 * assigned in the layout XML files, and are used to find specific views within 372 * the view tree. A common pattern is to: 373 * <ul> 374 * <li>Define a Button in the layout file and assign it a unique ID. 375 * <pre> 376 * <Button 377 * android:id="@+id/my_button" 378 * android:layout_width="wrap_content" 379 * android:layout_height="wrap_content" 380 * android:text="@string/my_button_text"/> 381 * </pre></li> 382 * <li>From the onCreate method of an Activity, find the Button 383 * <pre class="prettyprint"> 384 * Button myButton = findViewById(R.id.my_button); 385 * </pre></li> 386 * </ul> 387 * <p> 388 * View IDs need not be unique throughout the tree, but it is good practice to 389 * ensure that they are at least unique within the part of the tree you are 390 * searching. 391 * </p> 392 * 393 * <a name="Position"></a> 394 * <h3>Position</h3> 395 * <p> 396 * The geometry of a view is that of a rectangle. A view has a location, 397 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 398 * two dimensions, expressed as a width and a height. The unit for location 399 * and dimensions is the pixel. 400 * </p> 401 * 402 * <p> 403 * It is possible to retrieve the location of a view by invoking the methods 404 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 405 * coordinate of the rectangle representing the view. The latter returns the 406 * top, or Y, coordinate of the rectangle representing the view. These methods 407 * both return the location of the view relative to its parent. For instance, 408 * when getLeft() returns 20, that means the view is located 20 pixels to the 409 * right of the left edge of its direct parent. 410 * </p> 411 * 412 * <p> 413 * In addition, several convenience methods are offered to avoid unnecessary 414 * computations, namely {@link #getRight()} and {@link #getBottom()}. 415 * These methods return the coordinates of the right and bottom edges of the 416 * rectangle representing the view. For instance, calling {@link #getRight()} 417 * is similar to the following computation: <code>getLeft() + getWidth()</code> 418 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 419 * </p> 420 * 421 * <a name="SizePaddingMargins"></a> 422 * <h3>Size, padding and margins</h3> 423 * <p> 424 * The size of a view is expressed with a width and a height. A view actually 425 * possess two pairs of width and height values. 426 * </p> 427 * 428 * <p> 429 * The first pair is known as <em>measured width</em> and 430 * <em>measured height</em>. These dimensions define how big a view wants to be 431 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 432 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 433 * and {@link #getMeasuredHeight()}. 434 * </p> 435 * 436 * <p> 437 * The second pair is simply known as <em>width</em> and <em>height</em>, or 438 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 439 * dimensions define the actual size of the view on screen, at drawing time and 440 * after layout. These values may, but do not have to, be different from the 441 * measured width and height. The width and height can be obtained by calling 442 * {@link #getWidth()} and {@link #getHeight()}. 443 * </p> 444 * 445 * <p> 446 * To measure its dimensions, a view takes into account its padding. The padding 447 * is expressed in pixels for the left, top, right and bottom parts of the view. 448 * Padding can be used to offset the content of the view by a specific amount of 449 * pixels. For instance, a left padding of 2 will push the view's content by 450 * 2 pixels to the right of the left edge. Padding can be set using the 451 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 452 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 453 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 454 * {@link #getPaddingEnd()}. 455 * </p> 456 * 457 * <p> 458 * Even though a view can define a padding, it does not provide any support for 459 * margins. However, view groups provide such a support. Refer to 460 * {@link android.view.ViewGroup} and 461 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 462 * </p> 463 * 464 * <a name="Layout"></a> 465 * <h3>Layout</h3> 466 * <p> 467 * Layout is a two pass process: a measure pass and a layout pass. The measuring 468 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 469 * of the view tree. Each view pushes dimension specifications down the tree 470 * during the recursion. At the end of the measure pass, every view has stored 471 * its measurements. The second pass happens in 472 * {@link #layout(int,int,int,int)} and is also top-down. During 473 * this pass each parent is responsible for positioning all of its children 474 * using the sizes computed in the measure pass. 475 * </p> 476 * 477 * <p> 478 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 479 * {@link #getMeasuredHeight()} values must be set, along with those for all of 480 * that view's descendants. A view's measured width and measured height values 481 * must respect the constraints imposed by the view's parents. This guarantees 482 * that at the end of the measure pass, all parents accept all of their 483 * children's measurements. A parent view may call measure() more than once on 484 * its children. For example, the parent may measure each child once with 485 * unspecified dimensions to find out how big they want to be, then call 486 * measure() on them again with actual numbers if the sum of all the children's 487 * unconstrained sizes is too big or too small. 488 * </p> 489 * 490 * <p> 491 * The measure pass uses two classes to communicate dimensions. The 492 * {@link MeasureSpec} class is used by views to tell their parents how they 493 * want to be measured and positioned. The base LayoutParams class just 494 * describes how big the view wants to be for both width and height. For each 495 * dimension, it can specify one of: 496 * <ul> 497 * <li> an exact number 498 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 499 * (minus padding) 500 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 501 * enclose its content (plus padding). 502 * </ul> 503 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 504 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 505 * an X and Y value. 506 * </p> 507 * 508 * <p> 509 * MeasureSpecs are used to push requirements down the tree from parent to 510 * child. A MeasureSpec can be in one of three modes: 511 * <ul> 512 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 513 * of a child view. For example, a LinearLayout may call measure() on its child 514 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 515 * tall the child view wants to be given a width of 240 pixels. 516 * <li>EXACTLY: This is used by the parent to impose an exact size on the 517 * child. The child must use this size, and guarantee that all of its 518 * descendants will fit within this size. 519 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 520 * child. The child must guarantee that it and all of its descendants will fit 521 * within this size. 522 * </ul> 523 * </p> 524 * 525 * <p> 526 * To initiate a layout, call {@link #requestLayout}. This method is typically 527 * called by a view on itself when it believes that it can no longer fit within 528 * its current bounds. 529 * </p> 530 * 531 * <a name="Drawing"></a> 532 * <h3>Drawing</h3> 533 * <p> 534 * Drawing is handled by walking the tree and recording the drawing commands of 535 * any View that needs to update. After this, the drawing commands of the 536 * entire tree are issued to screen, clipped to the newly damaged area. 537 * </p> 538 * 539 * <p> 540 * The tree is largely recorded and drawn in order, with parents drawn before 541 * (i.e., behind) their children, with siblings drawn in the order they appear 542 * in the tree. If you set a background drawable for a View, then the View will 543 * draw it before calling back to its <code>onDraw()</code> method. The child 544 * drawing order can be overridden with 545 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 546 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 547 * </p> 548 * 549 * <p> 550 * To force a view to draw, call {@link #invalidate()}. 551 * </p> 552 * 553 * <a name="EventHandlingThreading"></a> 554 * <h3>Event Handling and Threading</h3> 555 * <p> 556 * The basic cycle of a view is as follows: 557 * <ol> 558 * <li>An event comes in and is dispatched to the appropriate view. The view 559 * handles the event and notifies any listeners.</li> 560 * <li>If in the course of processing the event, the view's bounds may need 561 * to be changed, the view will call {@link #requestLayout()}.</li> 562 * <li>Similarly, if in the course of processing the event the view's appearance 563 * may need to be changed, the view will call {@link #invalidate()}.</li> 564 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 565 * the framework will take care of measuring, laying out, and drawing the tree 566 * as appropriate.</li> 567 * </ol> 568 * </p> 569 * 570 * <p><em>Note: The entire view tree is single threaded. You must always be on 571 * the UI thread when calling any method on any view.</em> 572 * If you are doing work on other threads and want to update the state of a view 573 * from that thread, you should use a {@link Handler}. 574 * </p> 575 * 576 * <a name="FocusHandling"></a> 577 * <h3>Focus Handling</h3> 578 * <p> 579 * The framework will handle routine focus movement in response to user input. 580 * This includes changing the focus as views are removed or hidden, or as new 581 * views become available. Views indicate their willingness to take focus 582 * through the {@link #isFocusable} method. To change whether a view can take 583 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 584 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 585 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 586 * </p> 587 * <p> 588 * Focus movement is based on an algorithm which finds the nearest neighbor in a 589 * given direction. In rare cases, the default algorithm may not match the 590 * intended behavior of the developer. In these situations, you can provide 591 * explicit overrides by using these XML attributes in the layout file: 592 * <pre> 593 * nextFocusDown 594 * nextFocusLeft 595 * nextFocusRight 596 * nextFocusUp 597 * </pre> 598 * </p> 599 * 600 * 601 * <p> 602 * To get a particular view to take focus, call {@link #requestFocus()}. 603 * </p> 604 * 605 * <a name="TouchMode"></a> 606 * <h3>Touch Mode</h3> 607 * <p> 608 * When a user is navigating a user interface via directional keys such as a D-pad, it is 609 * necessary to give focus to actionable items such as buttons so the user can see 610 * what will take input. If the device has touch capabilities, however, and the user 611 * begins interacting with the interface by touching it, it is no longer necessary to 612 * always highlight, or give focus to, a particular view. This motivates a mode 613 * for interaction named 'touch mode'. 614 * </p> 615 * <p> 616 * For a touch capable device, once the user touches the screen, the device 617 * will enter touch mode. From this point onward, only views for which 618 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 619 * Other views that are touchable, like buttons, will not take focus when touched; they will 620 * only fire the on click listeners. 621 * </p> 622 * <p> 623 * Any time a user hits a directional key, such as a D-pad direction, the view device will 624 * exit touch mode, and find a view to take focus, so that the user may resume interacting 625 * with the user interface without touching the screen again. 626 * </p> 627 * <p> 628 * The touch mode state is maintained across {@link android.app.Activity}s. Call 629 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 630 * </p> 631 * 632 * <a name="Scrolling"></a> 633 * <h3>Scrolling</h3> 634 * <p> 635 * The framework provides basic support for views that wish to internally 636 * scroll their content. This includes keeping track of the X and Y scroll 637 * offset as well as mechanisms for drawing scrollbars. See 638 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 639 * {@link #awakenScrollBars()} for more details. 640 * </p> 641 * 642 * <a name="Tags"></a> 643 * <h3>Tags</h3> 644 * <p> 645 * Unlike IDs, tags are not used to identify views. Tags are essentially an 646 * extra piece of information that can be associated with a view. They are most 647 * often used as a convenience to store data related to views in the views 648 * themselves rather than by putting them in a separate structure. 649 * </p> 650 * <p> 651 * Tags may be specified with character sequence values in layout XML as either 652 * a single tag using the {@link android.R.styleable#View_tag android:tag} 653 * attribute or multiple tags using the {@code <tag>} child element: 654 * <pre> 655 * <View ... 656 * android:tag="@string/mytag_value" /> 657 * <View ...> 658 * <tag android:id="@+id/mytag" 659 * android:value="@string/mytag_value" /> 660 * </View> 661 * </pre> 662 * </p> 663 * <p> 664 * Tags may also be specified with arbitrary objects from code using 665 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 666 * </p> 667 * 668 * <a name="Themes"></a> 669 * <h3>Themes</h3> 670 * <p> 671 * By default, Views are created using the theme of the Context object supplied 672 * to their constructor; however, a different theme may be specified by using 673 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 674 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 675 * code. 676 * </p> 677 * <p> 678 * When the {@link android.R.styleable#View_theme android:theme} attribute is 679 * used in XML, the specified theme is applied on top of the inflation 680 * context's theme (see {@link LayoutInflater}) and used for the view itself as 681 * well as any child elements. 682 * </p> 683 * <p> 684 * In the following example, both views will be created using the Material dark 685 * color scheme; however, because an overlay theme is used which only defines a 686 * subset of attributes, the value of 687 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 688 * the inflation context's theme (e.g. the Activity theme) will be preserved. 689 * <pre> 690 * <LinearLayout 691 * ... 692 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 693 * <View ...> 694 * </LinearLayout> 695 * </pre> 696 * </p> 697 * 698 * <a name="Properties"></a> 699 * <h3>Properties</h3> 700 * <p> 701 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 702 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 703 * available both in the {@link Property} form as well as in similarly-named setter/getter 704 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 705 * be used to set persistent state associated with these rendering-related properties on the view. 706 * The properties and methods can also be used in conjunction with 707 * {@link android.animation.Animator Animator}-based animations, described more in the 708 * <a href="#Animation">Animation</a> section. 709 * </p> 710 * 711 * <a name="Animation"></a> 712 * <h3>Animation</h3> 713 * <p> 714 * Starting with Android 3.0, the preferred way of animating views is to use the 715 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 716 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 717 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 718 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 719 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 720 * makes animating these View properties particularly easy and efficient. 721 * </p> 722 * <p> 723 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 724 * You can attach an {@link Animation} object to a view using 725 * {@link #setAnimation(Animation)} or 726 * {@link #startAnimation(Animation)}. The animation can alter the scale, 727 * rotation, translation and alpha of a view over time. If the animation is 728 * attached to a view that has children, the animation will affect the entire 729 * subtree rooted by that node. When an animation is started, the framework will 730 * take care of redrawing the appropriate views until the animation completes. 731 * </p> 732 * 733 * <a name="Security"></a> 734 * <h3>Security</h3> 735 * <p> 736 * Sometimes it is essential that an application be able to verify that an action 737 * is being performed with the full knowledge and consent of the user, such as 738 * granting a permission request, making a purchase or clicking on an advertisement. 739 * Unfortunately, a malicious application could try to spoof the user into 740 * performing these actions, unaware, by concealing the intended purpose of the view. 741 * As a remedy, the framework offers a touch filtering mechanism that can be used to 742 * improve the security of views that provide access to sensitive functionality. 743 * </p><p> 744 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 745 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 746 * will discard touches that are received whenever the view's window is obscured by 747 * another visible window. As a result, the view will not receive touches whenever a 748 * toast, dialog or other window appears above the view's window. 749 * </p><p> 750 * For more fine-grained control over security, consider overriding the 751 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 752 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 753 * </p> 754 * 755 * @attr ref android.R.styleable#View_accessibilityHeading 756 * @attr ref android.R.styleable#View_allowClickWhenDisabled 757 * @attr ref android.R.styleable#View_alpha 758 * @attr ref android.R.styleable#View_background 759 * @attr ref android.R.styleable#View_clickable 760 * @attr ref android.R.styleable#View_clipToOutline 761 * @attr ref android.R.styleable#View_contentDescription 762 * @attr ref android.R.styleable#View_drawingCacheQuality 763 * @attr ref android.R.styleable#View_duplicateParentState 764 * @attr ref android.R.styleable#View_id 765 * @attr ref android.R.styleable#View_requiresFadingEdge 766 * @attr ref android.R.styleable#View_fadeScrollbars 767 * @attr ref android.R.styleable#View_fadingEdgeLength 768 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 769 * @attr ref android.R.styleable#View_fitsSystemWindows 770 * @attr ref android.R.styleable#View_isScrollContainer 771 * @attr ref android.R.styleable#View_focusable 772 * @attr ref android.R.styleable#View_focusableInTouchMode 773 * @attr ref android.R.styleable#View_focusedByDefault 774 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 775 * @attr ref android.R.styleable#View_keepScreenOn 776 * @attr ref android.R.styleable#View_keyboardNavigationCluster 777 * @attr ref android.R.styleable#View_layerType 778 * @attr ref android.R.styleable#View_layoutDirection 779 * @attr ref android.R.styleable#View_longClickable 780 * @attr ref android.R.styleable#View_minHeight 781 * @attr ref android.R.styleable#View_minWidth 782 * @attr ref android.R.styleable#View_nextClusterForward 783 * @attr ref android.R.styleable#View_nextFocusDown 784 * @attr ref android.R.styleable#View_nextFocusLeft 785 * @attr ref android.R.styleable#View_nextFocusRight 786 * @attr ref android.R.styleable#View_nextFocusUp 787 * @attr ref android.R.styleable#View_onClick 788 * @attr ref android.R.styleable#View_outlineSpotShadowColor 789 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 790 * @attr ref android.R.styleable#View_padding 791 * @attr ref android.R.styleable#View_paddingHorizontal 792 * @attr ref android.R.styleable#View_paddingVertical 793 * @attr ref android.R.styleable#View_paddingBottom 794 * @attr ref android.R.styleable#View_paddingLeft 795 * @attr ref android.R.styleable#View_paddingRight 796 * @attr ref android.R.styleable#View_paddingTop 797 * @attr ref android.R.styleable#View_paddingStart 798 * @attr ref android.R.styleable#View_paddingEnd 799 * @attr ref android.R.styleable#View_saveEnabled 800 * @attr ref android.R.styleable#View_rotation 801 * @attr ref android.R.styleable#View_rotationX 802 * @attr ref android.R.styleable#View_rotationY 803 * @attr ref android.R.styleable#View_scaleX 804 * @attr ref android.R.styleable#View_scaleY 805 * @attr ref android.R.styleable#View_scrollX 806 * @attr ref android.R.styleable#View_scrollY 807 * @attr ref android.R.styleable#View_scrollbarSize 808 * @attr ref android.R.styleable#View_scrollbarStyle 809 * @attr ref android.R.styleable#View_scrollbars 810 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 811 * @attr ref android.R.styleable#View_scrollbarFadeDuration 812 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 813 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 814 * @attr ref android.R.styleable#View_scrollbarThumbVertical 815 * @attr ref android.R.styleable#View_scrollbarTrackVertical 816 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 817 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 818 * @attr ref android.R.styleable#View_stateListAnimator 819 * @attr ref android.R.styleable#View_transitionName 820 * @attr ref android.R.styleable#View_soundEffectsEnabled 821 * @attr ref android.R.styleable#View_tag 822 * @attr ref android.R.styleable#View_textAlignment 823 * @attr ref android.R.styleable#View_textDirection 824 * @attr ref android.R.styleable#View_transformPivotX 825 * @attr ref android.R.styleable#View_transformPivotY 826 * @attr ref android.R.styleable#View_translationX 827 * @attr ref android.R.styleable#View_translationY 828 * @attr ref android.R.styleable#View_translationZ 829 * @attr ref android.R.styleable#View_visibility 830 * @attr ref android.R.styleable#View_theme 831 * 832 * @see android.view.ViewGroup 833 */ 834 @UiThread 835 public class View implements Drawable.Callback, KeyEvent.Callback, 836 AccessibilityEventSource { 837 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 838 private static final boolean DBG = false; 839 840 /** @hide */ 841 public static boolean DEBUG_DRAW = false; 842 843 /** 844 * The logging tag used by this class with android.util.Log. 845 */ 846 protected static final String VIEW_LOG_TAG = "View"; 847 848 /** 849 * The logging tag used by this class when logging verbose, autofill-related messages. 850 */ 851 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 852 // set if a session is not started. 853 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 854 855 /** 856 * The logging tag used by this class when logging content capture-related messages. 857 */ 858 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 859 860 private static final boolean DEBUG_CONTENT_CAPTURE = false; 861 862 /** 863 * When set to true, this view will save its attribute data. 864 * 865 * @hide 866 */ 867 public static boolean sDebugViewAttributes = false; 868 869 /** 870 * When set to this application package view will save its attribute data. 871 * 872 * @hide 873 */ 874 public static String sDebugViewAttributesApplicationPackage; 875 876 /** 877 * Used to mark a View that has no ID. 878 */ 879 public static final int NO_ID = -1; 880 881 /** 882 * Last ID that is given to Views that are no part of activities. 883 * 884 * {@hide} 885 */ 886 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 887 888 /** 889 * Attribute to find the autofilled highlight 890 * 891 * @see #getAutofilledDrawable() 892 */ 893 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 894 new int[]{android.R.attr.autofilledHighlight}; 895 896 /** 897 * Signals that compatibility booleans have been initialized according to 898 * target SDK versions. 899 */ 900 private static boolean sCompatibilityDone = false; 901 902 /** 903 * Use the old (broken) way of building MeasureSpecs. 904 */ 905 private static boolean sUseBrokenMakeMeasureSpec = false; 906 907 /** 908 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 909 */ 910 static boolean sUseZeroUnspecifiedMeasureSpec = false; 911 912 /** 913 * Ignore any optimizations using the measure cache. 914 */ 915 private static boolean sIgnoreMeasureCache = false; 916 917 /** 918 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 919 */ 920 private static boolean sAlwaysRemeasureExactly = false; 921 922 /** 923 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 924 * without throwing 925 */ 926 static boolean sTextureViewIgnoresDrawableSetters = false; 927 928 /** 929 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 930 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 931 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 932 * check is implemented for backwards compatibility. 933 * 934 * {@hide} 935 */ 936 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 937 938 /** 939 * Prior to N, when drag enters into child of a view that has already received an 940 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 941 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 942 * false from its event handler for these events. 943 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 944 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 945 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 946 */ 947 static boolean sCascadedDragDrop; 948 949 /** 950 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 951 * to determine things like whether or not to permit item click events. We can't break 952 * apps that do this just because more things (clickable things) are now auto-focusable 953 * and they would get different results, so give old behavior to old apps. 954 */ 955 static boolean sHasFocusableExcludeAutoFocusable; 956 957 /** 958 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 959 * made focusable by default. As a result, apps could (incorrectly) change the clickable 960 * setting of views off the UI thread. Now that clickable can effect the focusable state, 961 * changing the clickable attribute off the UI thread will cause an exception (since changing 962 * the focusable state checks). In order to prevent apps from crashing, we will handle this 963 * specific case and just not notify parents on new focusables resulting from marking views 964 * clickable from outside the UI thread. 965 */ 966 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 967 968 /** 969 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 970 * Float.NaN. If the app is targetting P or later then passing these values will result in an 971 * exception being thrown. If the app is targetting an earlier SDK version, then we will 972 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 973 * these bogus values. 974 */ 975 private static boolean sThrowOnInvalidFloatProperties; 976 977 /** 978 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 979 * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead. 980 */ 981 private static boolean sAcceptZeroSizeDragShadow; 982 983 /** 984 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 985 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 986 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 987 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 988 * thus, the hierarchical dispatching mechanism was hard to use for apps. 989 * <p> 990 * In order to make window inset dispatching work properly, we dispatch window insets 991 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 992 */ 993 static boolean sBrokenInsetsDispatch; 994 995 /** 996 * Prior to Q, calling 997 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 998 * did not call update the window format so the opacity of the background was not correctly 999 * applied to the window. Some applications rely on this misbehavior to work properly. 1000 * <p> 1001 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 1002 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 1003 * which updates the window format. 1004 * @hide 1005 */ 1006 protected static boolean sBrokenWindowBackground; 1007 1008 /** 1009 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 1010 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 1011 * calling {@link #requestLayout} when they need to relayout based on an insets change. 1012 */ 1013 static boolean sForceLayoutWhenInsetsChanged; 1014 1015 /** @hide */ 1016 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 1017 @Retention(RetentionPolicy.SOURCE) 1018 public @interface Focusable {} 1019 1020 /** 1021 * This view does not want keystrokes. 1022 * <p> 1023 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1024 * android:focusable}. 1025 */ 1026 public static final int NOT_FOCUSABLE = 0x00000000; 1027 1028 /** 1029 * This view wants keystrokes. 1030 * <p> 1031 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1032 * android:focusable}. 1033 */ 1034 public static final int FOCUSABLE = 0x00000001; 1035 1036 /** 1037 * This view determines focusability automatically. This is the default. 1038 * <p> 1039 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1040 * android:focusable}. 1041 */ 1042 public static final int FOCUSABLE_AUTO = 0x00000010; 1043 1044 /** 1045 * Mask for use with setFlags indicating bits used for focus. 1046 */ 1047 private static final int FOCUSABLE_MASK = 0x00000011; 1048 1049 /** 1050 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1051 */ 1052 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1053 1054 /** @hide */ 1055 @IntDef({VISIBLE, INVISIBLE, GONE}) 1056 @Retention(RetentionPolicy.SOURCE) 1057 public @interface Visibility {} 1058 1059 /** 1060 * This view is visible. 1061 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1062 * android:visibility}. 1063 */ 1064 public static final int VISIBLE = 0x00000000; 1065 1066 /** 1067 * This view is invisible, but it still takes up space for layout purposes. 1068 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1069 * android:visibility}. 1070 */ 1071 public static final int INVISIBLE = 0x00000004; 1072 1073 /** 1074 * This view is invisible, and it doesn't take any space for layout 1075 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1076 * android:visibility}. 1077 */ 1078 public static final int GONE = 0x00000008; 1079 1080 /** 1081 * Mask for use with setFlags indicating bits used for visibility. 1082 * {@hide} 1083 */ 1084 static final int VISIBILITY_MASK = 0x0000000C; 1085 1086 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1087 1088 /** 1089 * Hint indicating that this view can be autofilled with an email address. 1090 * 1091 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1092 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1093 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1094 * 1095 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1096 */ 1097 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1098 1099 /** 1100 * Hint indicating that this view can be autofilled with a user's real name. 1101 * 1102 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1103 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1104 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1105 * 1106 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1107 */ 1108 public static final String AUTOFILL_HINT_NAME = "name"; 1109 1110 /** 1111 * Hint indicating that this view can be autofilled with a username. 1112 * 1113 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1114 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1115 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1116 * 1117 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1118 */ 1119 public static final String AUTOFILL_HINT_USERNAME = "username"; 1120 1121 /** 1122 * Hint indicating that this view can be autofilled with a password. 1123 * 1124 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1125 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1126 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1127 * 1128 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1129 */ 1130 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1131 1132 /** 1133 * Hint indicating that this view can be autofilled with a phone number. 1134 * 1135 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1136 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1137 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1138 * 1139 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1140 */ 1141 public static final String AUTOFILL_HINT_PHONE = "phone"; 1142 1143 /** 1144 * Hint indicating that this view can be autofilled with a postal address. 1145 * 1146 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1147 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1148 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1149 * 1150 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1151 */ 1152 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1153 1154 /** 1155 * Hint indicating that this view can be autofilled with a postal code. 1156 * 1157 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1158 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1159 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1160 * 1161 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1162 */ 1163 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1164 1165 /** 1166 * Hint indicating that this view can be autofilled with a credit card number. 1167 * 1168 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1169 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1170 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1171 * 1172 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1173 */ 1174 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1175 1176 /** 1177 * Hint indicating that this view can be autofilled with a credit card security code. 1178 * 1179 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1180 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1181 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1182 * 1183 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1184 */ 1185 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1186 1187 /** 1188 * Hint indicating that this view can be autofilled with a credit card expiration date. 1189 * 1190 * <p>It should be used when the credit card expiration date is represented by just one view; 1191 * if it is represented by more than one (for example, one view for the month and another view 1192 * for the year), then each of these views should use the hint specific for the unit 1193 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1194 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1195 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1196 * 1197 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1198 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1199 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1200 * 1201 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1202 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1203 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1204 * the following options: 1205 * 1206 * <ul> 1207 * <li>{@code "04/2020"} 1208 * <li>{@code "4/2020"} 1209 * <li>{@code "2020/04"} 1210 * <li>{@code "2020/4"} 1211 * <li>{@code "April/2020"} 1212 * <li>{@code "Apr/2020"} 1213 * </ul> 1214 * 1215 * <p>You define a date autofill value for the view by overriding the following methods: 1216 * 1217 * <ol> 1218 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1219 * <li>{@link #getAutofillValue()} to return a 1220 * {@link AutofillValue#forDate(long) date autofillvalue}. 1221 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1222 * </ol> 1223 * 1224 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1225 */ 1226 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1227 "creditCardExpirationDate"; 1228 1229 /** 1230 * Hint indicating that this view can be autofilled with a credit card expiration month. 1231 * 1232 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1233 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1234 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1235 * 1236 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1237 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1238 * ambiguity when the autofill service provides a value for it. To understand why a 1239 * value can be ambiguous, consider "January", which could be represented as either of 1240 * 1241 * <ul> 1242 * <li>{@code "1"}: recommended way. 1243 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1244 * <li>{@code "January"}: full name, in English. 1245 * <li>{@code "jan"}: abbreviated name, in English. 1246 * <li>{@code "Janeiro"}: full name, in another language. 1247 * </ul> 1248 * 1249 * <p>Another recommended approach is to use a date autofill value - see 1250 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1251 * 1252 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1253 */ 1254 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1255 "creditCardExpirationMonth"; 1256 1257 /** 1258 * Hint indicating that this view can be autofilled with a credit card expiration year. 1259 * 1260 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1261 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1262 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1263 * 1264 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1265 */ 1266 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1267 "creditCardExpirationYear"; 1268 1269 /** 1270 * Hint indicating that this view can be autofilled with a credit card expiration day. 1271 * 1272 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1273 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1274 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1275 * 1276 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1277 */ 1278 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1279 1280 /** 1281 * Hints for the autofill services that describes the content of the view. 1282 */ 1283 private @Nullable String[] mAutofillHints; 1284 1285 /** 1286 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1287 */ 1288 private AutofillId mAutofillId; 1289 1290 /** @hide */ 1291 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1292 AUTOFILL_TYPE_NONE, 1293 AUTOFILL_TYPE_TEXT, 1294 AUTOFILL_TYPE_TOGGLE, 1295 AUTOFILL_TYPE_LIST, 1296 AUTOFILL_TYPE_DATE, 1297 }) 1298 @Retention(RetentionPolicy.SOURCE) 1299 public @interface AutofillType {} 1300 1301 /** 1302 * Autofill type for views that cannot be autofilled. 1303 * 1304 * <p>Typically used when the view is read-only; for example, a text label. 1305 * 1306 * @see #getAutofillType() 1307 */ 1308 public static final int AUTOFILL_TYPE_NONE = 0; 1309 1310 /** 1311 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1312 * 1313 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1314 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1315 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1316 * 1317 * @see #getAutofillType() 1318 */ 1319 public static final int AUTOFILL_TYPE_TEXT = 1; 1320 1321 /** 1322 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1323 * 1324 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1325 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1326 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1327 * 1328 * @see #getAutofillType() 1329 */ 1330 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1331 1332 /** 1333 * Autofill type for a selection list field, which is filled by an {@code int} 1334 * representing the element index inside the list (starting at {@code 0}). 1335 * 1336 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1337 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1338 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1339 * 1340 * <p>The available options in the selection list are typically provided by 1341 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1342 * 1343 * @see #getAutofillType() 1344 */ 1345 public static final int AUTOFILL_TYPE_LIST = 3; 1346 1347 /** 1348 * Autofill type for a field that contains a date, which is represented by a long representing 1349 * the number of milliseconds since the standard base time known as "the epoch", namely 1350 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1351 * 1352 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1353 * {@link AutofillValue#forDate(long)}, and the values passed to 1354 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1355 * 1356 * @see #getAutofillType() 1357 */ 1358 public static final int AUTOFILL_TYPE_DATE = 4; 1359 1360 1361 /** @hide */ 1362 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1363 IMPORTANT_FOR_AUTOFILL_AUTO, 1364 IMPORTANT_FOR_AUTOFILL_YES, 1365 IMPORTANT_FOR_AUTOFILL_NO, 1366 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1367 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1368 }) 1369 @Retention(RetentionPolicy.SOURCE) 1370 public @interface AutofillImportance {} 1371 1372 /** 1373 * Automatically determine whether a view is important for autofill. 1374 * 1375 * @see #isImportantForAutofill() 1376 * @see #setImportantForAutofill(int) 1377 */ 1378 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1379 1380 /** 1381 * The view is important for autofill, and its children (if any) will be traversed. 1382 * 1383 * @see #isImportantForAutofill() 1384 * @see #setImportantForAutofill(int) 1385 */ 1386 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1387 1388 /** 1389 * The view is not important for autofill, but its children (if any) will be traversed. 1390 * 1391 * @see #isImportantForAutofill() 1392 * @see #setImportantForAutofill(int) 1393 */ 1394 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1395 1396 /** 1397 * The view is important for autofill, but its children (if any) will not be traversed. 1398 * 1399 * @see #isImportantForAutofill() 1400 * @see #setImportantForAutofill(int) 1401 */ 1402 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1403 1404 /** 1405 * The view is not important for autofill, and its children (if any) will not be traversed. 1406 * 1407 * @see #isImportantForAutofill() 1408 * @see #setImportantForAutofill(int) 1409 */ 1410 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1411 1412 /** @hide */ 1413 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1414 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1415 }) 1416 @Retention(RetentionPolicy.SOURCE) 1417 public @interface AutofillFlags {} 1418 1419 /** 1420 * Flag requesting you to add views that are marked as not important for autofill 1421 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1422 */ 1423 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1424 1425 /** @hide */ 1426 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1427 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1428 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1429 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1430 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1431 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1432 }) 1433 @Retention(RetentionPolicy.SOURCE) 1434 public @interface ContentCaptureImportance {} 1435 1436 /** 1437 * Automatically determine whether a view is important for content capture. 1438 * 1439 * @see #isImportantForContentCapture() 1440 * @see #setImportantForContentCapture(int) 1441 */ 1442 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1443 1444 /** 1445 * The view is important for content capture, and its children (if any) will be traversed. 1446 * 1447 * @see #isImportantForContentCapture() 1448 * @see #setImportantForContentCapture(int) 1449 */ 1450 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1451 1452 /** 1453 * The view is not important for content capture, but its children (if any) will be traversed. 1454 * 1455 * @see #isImportantForContentCapture() 1456 * @see #setImportantForContentCapture(int) 1457 */ 1458 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1459 1460 /** 1461 * The view is important for content capture, but its children (if any) will not be traversed. 1462 * 1463 * @see #isImportantForContentCapture() 1464 * @see #setImportantForContentCapture(int) 1465 */ 1466 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1467 1468 /** 1469 * The view is not important for content capture, and its children (if any) will not be 1470 * traversed. 1471 * 1472 * @see #isImportantForContentCapture() 1473 * @see #setImportantForContentCapture(int) 1474 */ 1475 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1476 1477 /** {@hide} */ 1478 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1479 value = { 1480 SCROLL_CAPTURE_HINT_AUTO, 1481 SCROLL_CAPTURE_HINT_EXCLUDE, 1482 SCROLL_CAPTURE_HINT_INCLUDE, 1483 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1484 }) 1485 @Retention(RetentionPolicy.SOURCE) 1486 public @interface ScrollCaptureHint {} 1487 1488 /** 1489 * The content of this view will be considered for scroll capture if scrolling is possible. 1490 * 1491 * @see #getScrollCaptureHint() 1492 * @see #setScrollCaptureHint(int) 1493 */ 1494 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1495 1496 /** 1497 * Explicitly exclude this view as a potential scroll capture target. The system will not 1498 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1499 * takes precedence over. 1500 * 1501 * @see #getScrollCaptureHint() 1502 * @see #setScrollCaptureHint(int) 1503 */ 1504 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1505 1506 /** 1507 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1508 * capture target, this view will be prioritized before others without this flag. Mutually 1509 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1510 * 1511 * @see #getScrollCaptureHint() 1512 * @see #setScrollCaptureHint(int) 1513 */ 1514 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1515 1516 /** 1517 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1518 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1519 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1520 * 1521 * @see #getScrollCaptureHint() 1522 * @see #setScrollCaptureHint(int) 1523 */ 1524 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1525 1526 /** 1527 * This view is enabled. Interpretation varies by subclass. 1528 * Use with ENABLED_MASK when calling setFlags. 1529 * {@hide} 1530 */ 1531 static final int ENABLED = 0x00000000; 1532 1533 /** 1534 * This view is disabled. Interpretation varies by subclass. 1535 * Use with ENABLED_MASK when calling setFlags. 1536 * {@hide} 1537 */ 1538 static final int DISABLED = 0x00000020; 1539 1540 /** 1541 * Mask for use with setFlags indicating bits used for indicating whether 1542 * this view is enabled 1543 * {@hide} 1544 */ 1545 static final int ENABLED_MASK = 0x00000020; 1546 1547 /** 1548 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1549 * called and further optimizations will be performed. It is okay to have 1550 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1551 * {@hide} 1552 */ 1553 static final int WILL_NOT_DRAW = 0x00000080; 1554 1555 /** 1556 * Mask for use with setFlags indicating bits used for indicating whether 1557 * this view is will draw 1558 * {@hide} 1559 */ 1560 static final int DRAW_MASK = 0x00000080; 1561 1562 /** 1563 * <p>This view doesn't show scrollbars.</p> 1564 * {@hide} 1565 */ 1566 static final int SCROLLBARS_NONE = 0x00000000; 1567 1568 /** 1569 * <p>This view shows horizontal scrollbars.</p> 1570 * {@hide} 1571 */ 1572 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1573 1574 /** 1575 * <p>This view shows vertical scrollbars.</p> 1576 * {@hide} 1577 */ 1578 static final int SCROLLBARS_VERTICAL = 0x00000200; 1579 1580 /** 1581 * <p>Mask for use with setFlags indicating bits used for indicating which 1582 * scrollbars are enabled.</p> 1583 * {@hide} 1584 */ 1585 static final int SCROLLBARS_MASK = 0x00000300; 1586 1587 /** 1588 * Indicates that the view should filter touches when its window is obscured. 1589 * Refer to the class comments for more information about this security feature. 1590 * {@hide} 1591 */ 1592 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1593 1594 /** 1595 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1596 * that they are optional and should be skipped if the window has 1597 * requested system UI flags that ignore those insets for layout. 1598 * <p> 1599 * This is only used for support library as of Android R. The framework now uses 1600 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1601 * insets path that loses insets information. 1602 */ 1603 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1604 1605 /** 1606 * <p>This view doesn't show fading edges.</p> 1607 * {@hide} 1608 */ 1609 static final int FADING_EDGE_NONE = 0x00000000; 1610 1611 /** 1612 * <p>This view shows horizontal fading edges.</p> 1613 * {@hide} 1614 */ 1615 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1616 1617 /** 1618 * <p>This view shows vertical fading edges.</p> 1619 * {@hide} 1620 */ 1621 static final int FADING_EDGE_VERTICAL = 0x00002000; 1622 1623 /** 1624 * <p>Mask for use with setFlags indicating bits used for indicating which 1625 * fading edges are enabled.</p> 1626 * {@hide} 1627 */ 1628 static final int FADING_EDGE_MASK = 0x00003000; 1629 1630 /** 1631 * <p>Indicates this view can be clicked. When clickable, a View reacts 1632 * to clicks by notifying the OnClickListener.<p> 1633 * {@hide} 1634 */ 1635 static final int CLICKABLE = 0x00004000; 1636 1637 /** 1638 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1639 * {@hide} 1640 */ 1641 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1642 1643 /** 1644 * <p>Indicates that no icicle should be saved for this view.<p> 1645 * {@hide} 1646 */ 1647 static final int SAVE_DISABLED = 0x000010000; 1648 1649 /** 1650 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1651 * property.</p> 1652 * {@hide} 1653 */ 1654 static final int SAVE_DISABLED_MASK = 0x000010000; 1655 1656 /** 1657 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1658 * {@hide} 1659 */ 1660 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1661 1662 /** 1663 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1664 * {@hide} 1665 */ 1666 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1667 1668 /** @hide */ 1669 @Retention(RetentionPolicy.SOURCE) 1670 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1671 DRAWING_CACHE_QUALITY_LOW, 1672 DRAWING_CACHE_QUALITY_HIGH, 1673 DRAWING_CACHE_QUALITY_AUTO 1674 }) 1675 public @interface DrawingCacheQuality {} 1676 1677 /** 1678 * <p>Enables low quality mode for the drawing cache.</p> 1679 * 1680 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1681 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1682 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1683 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1684 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1685 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1686 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1687 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1688 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1689 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1690 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1691 * reports or unit testing the {@link PixelCopy} API is recommended. 1692 */ 1693 @Deprecated 1694 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1695 1696 /** 1697 * <p>Enables high quality mode for the drawing cache.</p> 1698 * 1699 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1700 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1701 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1702 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1703 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1704 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1705 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1706 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1707 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1708 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1709 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1710 * reports or unit testing the {@link PixelCopy} API is recommended. 1711 */ 1712 @Deprecated 1713 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1714 1715 /** 1716 * <p>Enables automatic quality mode for the drawing cache.</p> 1717 * 1718 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1719 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1720 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1721 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1722 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1723 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1724 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1725 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1726 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1727 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1728 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1729 * reports or unit testing the {@link PixelCopy} API is recommended. 1730 */ 1731 @Deprecated 1732 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1733 1734 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1735 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1736 }; 1737 1738 /** 1739 * <p>Mask for use with setFlags indicating bits used for the cache 1740 * quality property.</p> 1741 * {@hide} 1742 */ 1743 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1744 1745 /** 1746 * <p> 1747 * Indicates this view can be long clicked. When long clickable, a View 1748 * reacts to long clicks by notifying the OnLongClickListener or showing a 1749 * context menu. 1750 * </p> 1751 * {@hide} 1752 */ 1753 static final int LONG_CLICKABLE = 0x00200000; 1754 1755 /** 1756 * <p>Indicates that this view gets its drawable states from its direct parent 1757 * and ignores its original internal states.</p> 1758 * 1759 * @hide 1760 */ 1761 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1762 1763 /** 1764 * <p> 1765 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1766 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1767 * OnContextClickListener. 1768 * </p> 1769 * {@hide} 1770 */ 1771 static final int CONTEXT_CLICKABLE = 0x00800000; 1772 1773 /** @hide */ 1774 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1775 SCROLLBARS_INSIDE_OVERLAY, 1776 SCROLLBARS_INSIDE_INSET, 1777 SCROLLBARS_OUTSIDE_OVERLAY, 1778 SCROLLBARS_OUTSIDE_INSET 1779 }) 1780 @Retention(RetentionPolicy.SOURCE) 1781 public @interface ScrollBarStyle {} 1782 1783 /** 1784 * The scrollbar style to display the scrollbars inside the content area, 1785 * without increasing the padding. The scrollbars will be overlaid with 1786 * translucency on the view's content. 1787 */ 1788 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1789 1790 /** 1791 * The scrollbar style to display the scrollbars inside the padded area, 1792 * increasing the padding of the view. The scrollbars will not overlap the 1793 * content area of the view. 1794 */ 1795 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1796 1797 /** 1798 * The scrollbar style to display the scrollbars at the edge of the view, 1799 * without increasing the padding. The scrollbars will be overlaid with 1800 * translucency. 1801 */ 1802 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1803 1804 /** 1805 * The scrollbar style to display the scrollbars at the edge of the view, 1806 * increasing the padding of the view. The scrollbars will only overlap the 1807 * background, if any. 1808 */ 1809 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1810 1811 /** 1812 * Mask to check if the scrollbar style is overlay or inset. 1813 * {@hide} 1814 */ 1815 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1816 1817 /** 1818 * Mask to check if the scrollbar style is inside or outside. 1819 * {@hide} 1820 */ 1821 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1822 1823 /** 1824 * Mask for scrollbar style. 1825 * {@hide} 1826 */ 1827 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1828 1829 /** 1830 * View flag indicating that the screen should remain on while the 1831 * window containing this view is visible to the user. This effectively 1832 * takes care of automatically setting the WindowManager's 1833 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1834 */ 1835 public static final int KEEP_SCREEN_ON = 0x04000000; 1836 1837 /** 1838 * View flag indicating whether this view should have sound effects enabled 1839 * for events such as clicking and touching. 1840 */ 1841 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1842 1843 /** 1844 * View flag indicating whether this view should have haptic feedback 1845 * enabled for events such as long presses. 1846 */ 1847 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1848 1849 /** 1850 * <p>Indicates that the view hierarchy should stop saving state when 1851 * it reaches this view. If state saving is initiated immediately at 1852 * the view, it will be allowed. 1853 * {@hide} 1854 */ 1855 static final int PARENT_SAVE_DISABLED = 0x20000000; 1856 1857 /** 1858 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1859 * {@hide} 1860 */ 1861 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1862 1863 private static Paint sDebugPaint; 1864 1865 /** 1866 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1867 * {@hide} 1868 */ 1869 static final int TOOLTIP = 0x40000000; 1870 1871 /** @hide */ 1872 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1873 FOCUSABLES_ALL, 1874 FOCUSABLES_TOUCH_MODE 1875 }) 1876 @Retention(RetentionPolicy.SOURCE) 1877 public @interface FocusableMode {} 1878 1879 /** 1880 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1881 * should add all focusable Views regardless if they are focusable in touch mode. 1882 */ 1883 public static final int FOCUSABLES_ALL = 0x00000000; 1884 1885 /** 1886 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1887 * should add only Views focusable in touch mode. 1888 */ 1889 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1890 1891 /** @hide */ 1892 @IntDef(prefix = { "FOCUS_" }, value = { 1893 FOCUS_BACKWARD, 1894 FOCUS_FORWARD, 1895 FOCUS_LEFT, 1896 FOCUS_UP, 1897 FOCUS_RIGHT, 1898 FOCUS_DOWN 1899 }) 1900 @Retention(RetentionPolicy.SOURCE) 1901 public @interface FocusDirection {} 1902 1903 /** @hide */ 1904 @IntDef(prefix = { "FOCUS_" }, value = { 1905 FOCUS_LEFT, 1906 FOCUS_UP, 1907 FOCUS_RIGHT, 1908 FOCUS_DOWN 1909 }) 1910 @Retention(RetentionPolicy.SOURCE) 1911 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1912 1913 /** 1914 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1915 * item. 1916 */ 1917 public static final int FOCUS_BACKWARD = 0x00000001; 1918 1919 /** 1920 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1921 * item. 1922 */ 1923 public static final int FOCUS_FORWARD = 0x00000002; 1924 1925 /** 1926 * Use with {@link #focusSearch(int)}. Move focus to the left. 1927 */ 1928 public static final int FOCUS_LEFT = 0x00000011; 1929 1930 /** 1931 * Use with {@link #focusSearch(int)}. Move focus up. 1932 */ 1933 public static final int FOCUS_UP = 0x00000021; 1934 1935 /** 1936 * Use with {@link #focusSearch(int)}. Move focus to the right. 1937 */ 1938 public static final int FOCUS_RIGHT = 0x00000042; 1939 1940 /** 1941 * Use with {@link #focusSearch(int)}. Move focus down. 1942 */ 1943 public static final int FOCUS_DOWN = 0x00000082; 1944 1945 /** 1946 * Bits of {@link #getMeasuredWidthAndState()} and 1947 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1948 */ 1949 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1950 1951 /** 1952 * Bits of {@link #getMeasuredWidthAndState()} and 1953 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1954 */ 1955 public static final int MEASURED_STATE_MASK = 0xff000000; 1956 1957 /** 1958 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1959 * for functions that combine both width and height into a single int, 1960 * such as {@link #getMeasuredState()} and the childState argument of 1961 * {@link #resolveSizeAndState(int, int, int)}. 1962 */ 1963 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1964 1965 /** 1966 * Bit of {@link #getMeasuredWidthAndState()} and 1967 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1968 * is smaller that the space the view would like to have. 1969 */ 1970 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1971 1972 /** 1973 * Base View state sets 1974 */ 1975 // Singles 1976 /** 1977 * Indicates the view has no states set. States are used with 1978 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1979 * view depending on its state. 1980 * 1981 * @see android.graphics.drawable.Drawable 1982 * @see #getDrawableState() 1983 */ 1984 protected static final int[] EMPTY_STATE_SET; 1985 /** 1986 * Indicates the view is enabled. States are used with 1987 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1988 * view depending on its state. 1989 * 1990 * @see android.graphics.drawable.Drawable 1991 * @see #getDrawableState() 1992 */ 1993 protected static final int[] ENABLED_STATE_SET; 1994 /** 1995 * Indicates the view is focused. States are used with 1996 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1997 * view depending on its state. 1998 * 1999 * @see android.graphics.drawable.Drawable 2000 * @see #getDrawableState() 2001 */ 2002 protected static final int[] FOCUSED_STATE_SET; 2003 /** 2004 * Indicates the view is selected. States are used with 2005 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2006 * view depending on its state. 2007 * 2008 * @see android.graphics.drawable.Drawable 2009 * @see #getDrawableState() 2010 */ 2011 protected static final int[] SELECTED_STATE_SET; 2012 /** 2013 * Indicates the view is pressed. States are used with 2014 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2015 * view depending on its state. 2016 * 2017 * @see android.graphics.drawable.Drawable 2018 * @see #getDrawableState() 2019 */ 2020 protected static final int[] PRESSED_STATE_SET; 2021 /** 2022 * Indicates the view's window has focus. States are used with 2023 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2024 * view depending on its state. 2025 * 2026 * @see android.graphics.drawable.Drawable 2027 * @see #getDrawableState() 2028 */ 2029 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2030 // Doubles 2031 /** 2032 * Indicates the view is enabled and has the focus. 2033 * 2034 * @see #ENABLED_STATE_SET 2035 * @see #FOCUSED_STATE_SET 2036 */ 2037 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2038 /** 2039 * Indicates the view is enabled and selected. 2040 * 2041 * @see #ENABLED_STATE_SET 2042 * @see #SELECTED_STATE_SET 2043 */ 2044 protected static final int[] ENABLED_SELECTED_STATE_SET; 2045 /** 2046 * Indicates the view is enabled and that its window has focus. 2047 * 2048 * @see #ENABLED_STATE_SET 2049 * @see #WINDOW_FOCUSED_STATE_SET 2050 */ 2051 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2052 /** 2053 * Indicates the view is focused and selected. 2054 * 2055 * @see #FOCUSED_STATE_SET 2056 * @see #SELECTED_STATE_SET 2057 */ 2058 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2059 /** 2060 * Indicates the view has the focus and that its window has the focus. 2061 * 2062 * @see #FOCUSED_STATE_SET 2063 * @see #WINDOW_FOCUSED_STATE_SET 2064 */ 2065 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2066 /** 2067 * Indicates the view is selected and that its window has the focus. 2068 * 2069 * @see #SELECTED_STATE_SET 2070 * @see #WINDOW_FOCUSED_STATE_SET 2071 */ 2072 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2073 // Triples 2074 /** 2075 * Indicates the view is enabled, focused and selected. 2076 * 2077 * @see #ENABLED_STATE_SET 2078 * @see #FOCUSED_STATE_SET 2079 * @see #SELECTED_STATE_SET 2080 */ 2081 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2082 /** 2083 * Indicates the view is enabled, focused and its window has the focus. 2084 * 2085 * @see #ENABLED_STATE_SET 2086 * @see #FOCUSED_STATE_SET 2087 * @see #WINDOW_FOCUSED_STATE_SET 2088 */ 2089 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2090 /** 2091 * Indicates the view is enabled, selected and its window has the focus. 2092 * 2093 * @see #ENABLED_STATE_SET 2094 * @see #SELECTED_STATE_SET 2095 * @see #WINDOW_FOCUSED_STATE_SET 2096 */ 2097 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2098 /** 2099 * Indicates the view is focused, selected and its window has the focus. 2100 * 2101 * @see #FOCUSED_STATE_SET 2102 * @see #SELECTED_STATE_SET 2103 * @see #WINDOW_FOCUSED_STATE_SET 2104 */ 2105 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2106 /** 2107 * Indicates the view is enabled, focused, selected and its window 2108 * has the focus. 2109 * 2110 * @see #ENABLED_STATE_SET 2111 * @see #FOCUSED_STATE_SET 2112 * @see #SELECTED_STATE_SET 2113 * @see #WINDOW_FOCUSED_STATE_SET 2114 */ 2115 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2116 /** 2117 * Indicates the view is pressed and its window has the focus. 2118 * 2119 * @see #PRESSED_STATE_SET 2120 * @see #WINDOW_FOCUSED_STATE_SET 2121 */ 2122 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2123 /** 2124 * Indicates the view is pressed and selected. 2125 * 2126 * @see #PRESSED_STATE_SET 2127 * @see #SELECTED_STATE_SET 2128 */ 2129 protected static final int[] PRESSED_SELECTED_STATE_SET; 2130 /** 2131 * Indicates the view is pressed, selected and its window has the focus. 2132 * 2133 * @see #PRESSED_STATE_SET 2134 * @see #SELECTED_STATE_SET 2135 * @see #WINDOW_FOCUSED_STATE_SET 2136 */ 2137 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2138 /** 2139 * Indicates the view is pressed and focused. 2140 * 2141 * @see #PRESSED_STATE_SET 2142 * @see #FOCUSED_STATE_SET 2143 */ 2144 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2145 /** 2146 * Indicates the view is pressed, focused and its window has the focus. 2147 * 2148 * @see #PRESSED_STATE_SET 2149 * @see #FOCUSED_STATE_SET 2150 * @see #WINDOW_FOCUSED_STATE_SET 2151 */ 2152 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2153 /** 2154 * Indicates the view is pressed, focused and selected. 2155 * 2156 * @see #PRESSED_STATE_SET 2157 * @see #SELECTED_STATE_SET 2158 * @see #FOCUSED_STATE_SET 2159 */ 2160 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2161 /** 2162 * Indicates the view is pressed, focused, selected and its window has the focus. 2163 * 2164 * @see #PRESSED_STATE_SET 2165 * @see #FOCUSED_STATE_SET 2166 * @see #SELECTED_STATE_SET 2167 * @see #WINDOW_FOCUSED_STATE_SET 2168 */ 2169 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2170 /** 2171 * Indicates the view is pressed and enabled. 2172 * 2173 * @see #PRESSED_STATE_SET 2174 * @see #ENABLED_STATE_SET 2175 */ 2176 protected static final int[] PRESSED_ENABLED_STATE_SET; 2177 /** 2178 * Indicates the view is pressed, enabled and its window has the focus. 2179 * 2180 * @see #PRESSED_STATE_SET 2181 * @see #ENABLED_STATE_SET 2182 * @see #WINDOW_FOCUSED_STATE_SET 2183 */ 2184 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2185 /** 2186 * Indicates the view is pressed, enabled and selected. 2187 * 2188 * @see #PRESSED_STATE_SET 2189 * @see #ENABLED_STATE_SET 2190 * @see #SELECTED_STATE_SET 2191 */ 2192 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2193 /** 2194 * Indicates the view is pressed, enabled, selected and its window has the 2195 * focus. 2196 * 2197 * @see #PRESSED_STATE_SET 2198 * @see #ENABLED_STATE_SET 2199 * @see #SELECTED_STATE_SET 2200 * @see #WINDOW_FOCUSED_STATE_SET 2201 */ 2202 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2203 /** 2204 * Indicates the view is pressed, enabled and focused. 2205 * 2206 * @see #PRESSED_STATE_SET 2207 * @see #ENABLED_STATE_SET 2208 * @see #FOCUSED_STATE_SET 2209 */ 2210 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2211 /** 2212 * Indicates the view is pressed, enabled, focused and its window has the 2213 * focus. 2214 * 2215 * @see #PRESSED_STATE_SET 2216 * @see #ENABLED_STATE_SET 2217 * @see #FOCUSED_STATE_SET 2218 * @see #WINDOW_FOCUSED_STATE_SET 2219 */ 2220 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2221 /** 2222 * Indicates the view is pressed, enabled, focused and selected. 2223 * 2224 * @see #PRESSED_STATE_SET 2225 * @see #ENABLED_STATE_SET 2226 * @see #SELECTED_STATE_SET 2227 * @see #FOCUSED_STATE_SET 2228 */ 2229 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2230 /** 2231 * Indicates the view is pressed, enabled, focused, selected and its window 2232 * has the focus. 2233 * 2234 * @see #PRESSED_STATE_SET 2235 * @see #ENABLED_STATE_SET 2236 * @see #SELECTED_STATE_SET 2237 * @see #FOCUSED_STATE_SET 2238 * @see #WINDOW_FOCUSED_STATE_SET 2239 */ 2240 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2241 2242 static { 2243 EMPTY_STATE_SET = StateSet.get(0); 2244 2245 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2246 2247 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2248 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2249 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2250 2251 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2252 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2253 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2254 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2255 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2256 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2257 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2258 | StateSet.VIEW_STATE_FOCUSED); 2259 2260 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2261 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2262 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2263 ENABLED_SELECTED_STATE_SET = StateSet.get( 2264 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2265 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2266 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2267 | StateSet.VIEW_STATE_ENABLED); 2268 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2269 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2270 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2271 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2272 | StateSet.VIEW_STATE_ENABLED); 2273 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2274 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2275 | StateSet.VIEW_STATE_ENABLED); 2276 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2277 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2278 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2279 2280 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2281 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2282 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2283 PRESSED_SELECTED_STATE_SET = StateSet.get( 2284 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2285 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2286 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2287 | StateSet.VIEW_STATE_PRESSED); 2288 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2289 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2290 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2291 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2292 | StateSet.VIEW_STATE_PRESSED); 2293 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2294 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2295 | StateSet.VIEW_STATE_PRESSED); 2296 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2297 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2298 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2299 PRESSED_ENABLED_STATE_SET = StateSet.get( 2300 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2301 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2302 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2303 | StateSet.VIEW_STATE_PRESSED); 2304 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2305 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2306 | StateSet.VIEW_STATE_PRESSED); 2307 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2308 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2309 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2310 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2311 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2312 | StateSet.VIEW_STATE_PRESSED); 2313 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2314 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2315 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2316 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2317 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2318 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2319 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2320 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2321 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2322 | StateSet.VIEW_STATE_PRESSED); 2323 } 2324 2325 /** 2326 * Accessibility event types that are dispatched for text population. 2327 */ 2328 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2329 AccessibilityEvent.TYPE_VIEW_CLICKED 2330 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2331 | AccessibilityEvent.TYPE_VIEW_SELECTED 2332 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2333 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2334 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2335 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2336 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2337 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2338 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2339 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2340 2341 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2342 2343 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2344 2345 /** 2346 * Temporary Rect currently for use in setBackground(). This will probably 2347 * be extended in the future to hold our own class with more than just 2348 * a Rect. :) 2349 */ 2350 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2351 2352 /** 2353 * Map used to store views' tags. 2354 */ 2355 @UnsupportedAppUsage 2356 private SparseArray<Object> mKeyedTags; 2357 2358 /** 2359 * The next available accessibility id. 2360 */ 2361 private static int sNextAccessibilityViewId; 2362 2363 /** 2364 * The animation currently associated with this view. 2365 * @hide 2366 */ 2367 protected Animation mCurrentAnimation = null; 2368 2369 /** 2370 * Width as measured during measure pass. 2371 * {@hide} 2372 */ 2373 @ViewDebug.ExportedProperty(category = "measurement") 2374 @UnsupportedAppUsage 2375 int mMeasuredWidth; 2376 2377 /** 2378 * Height as measured during measure pass. 2379 * {@hide} 2380 */ 2381 @ViewDebug.ExportedProperty(category = "measurement") 2382 @UnsupportedAppUsage 2383 int mMeasuredHeight; 2384 2385 /** 2386 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2387 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2388 * its display list. This flag, used only when hw accelerated, allows us to clear the 2389 * flag while retaining this information until it's needed (at getDisplayList() time and 2390 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2391 * 2392 * {@hide} 2393 */ 2394 @UnsupportedAppUsage 2395 boolean mRecreateDisplayList = false; 2396 2397 /** 2398 * The view's identifier. 2399 * {@hide} 2400 * 2401 * @see #setId(int) 2402 * @see #getId() 2403 */ 2404 @IdRes 2405 @ViewDebug.ExportedProperty(resolveId = true) 2406 int mID = NO_ID; 2407 2408 /** The ID of this view for autofill purposes. 2409 * <ul> 2410 * <li>== {@link #NO_ID}: ID has not been assigned yet 2411 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2412 * unique in the process. This might change 2413 * over activity lifecycle events. 2414 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2415 * unique in the activity. This stays the same 2416 * over activity lifecycle events. 2417 */ 2418 private int mAutofillViewId = NO_ID; 2419 2420 // ID for accessibility purposes. This ID must be unique for every window 2421 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2422 private int mAccessibilityViewId = NO_ID; 2423 2424 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2425 2426 /** 2427 * The view's tag. 2428 * {@hide} 2429 * 2430 * @see #setTag(Object) 2431 * @see #getTag() 2432 */ 2433 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2434 protected Object mTag = null; 2435 2436 /* 2437 * Masks for mPrivateFlags, as generated by dumpFlags(): 2438 * 2439 * |-------|-------|-------|-------| 2440 * 1 PFLAG_WANTS_FOCUS 2441 * 1 PFLAG_FOCUSED 2442 * 1 PFLAG_SELECTED 2443 * 1 PFLAG_IS_ROOT_NAMESPACE 2444 * 1 PFLAG_HAS_BOUNDS 2445 * 1 PFLAG_DRAWN 2446 * 1 PFLAG_DRAW_ANIMATION 2447 * 1 PFLAG_SKIP_DRAW 2448 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2449 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2450 * 1 PFLAG_MEASURED_DIMENSION_SET 2451 * 1 PFLAG_FORCE_LAYOUT 2452 * 1 PFLAG_LAYOUT_REQUIRED 2453 * 1 PFLAG_PRESSED 2454 * 1 PFLAG_DRAWING_CACHE_VALID 2455 * 1 PFLAG_ANIMATION_STARTED 2456 * 1 PFLAG_SAVE_STATE_CALLED 2457 * 1 PFLAG_ALPHA_SET 2458 * 1 PFLAG_SCROLL_CONTAINER 2459 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2460 * 1 PFLAG_DIRTY 2461 * 1 PFLAG_DIRTY_MASK 2462 * 1 PFLAG_OPAQUE_BACKGROUND 2463 * 1 PFLAG_OPAQUE_SCROLLBARS 2464 * 11 PFLAG_OPAQUE_MASK 2465 * 1 PFLAG_PREPRESSED 2466 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2467 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2468 * 1 PFLAG_HOVERED 2469 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2470 * 1 PFLAG_ACTIVATED 2471 * 1 PFLAG_INVALIDATED 2472 * |-------|-------|-------|-------| 2473 */ 2474 /** {@hide} */ 2475 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2476 /** {@hide} */ 2477 static final int PFLAG_FOCUSED = 0x00000002; 2478 /** {@hide} */ 2479 static final int PFLAG_SELECTED = 0x00000004; 2480 /** {@hide} */ 2481 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2482 /** {@hide} */ 2483 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2484 /** {@hide} */ 2485 static final int PFLAG_DRAWN = 0x00000020; 2486 /** 2487 * When this flag is set, this view is running an animation on behalf of its 2488 * children and should therefore not cancel invalidate requests, even if they 2489 * lie outside of this view's bounds. 2490 * 2491 * {@hide} 2492 */ 2493 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2494 /** {@hide} */ 2495 static final int PFLAG_SKIP_DRAW = 0x00000080; 2496 /** {@hide} */ 2497 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2498 /** {@hide} */ 2499 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2500 /** {@hide} */ 2501 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2502 /** {@hide} */ 2503 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2504 /** {@hide} */ 2505 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2506 2507 private static final int PFLAG_PRESSED = 0x00004000; 2508 2509 /** {@hide} */ 2510 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2511 /** 2512 * Flag used to indicate that this view should be drawn once more (and only once 2513 * more) after its animation has completed. 2514 * {@hide} 2515 */ 2516 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2517 2518 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2519 2520 /** 2521 * Indicates that the View returned true when onSetAlpha() was called and that 2522 * the alpha must be restored. 2523 * {@hide} 2524 */ 2525 static final int PFLAG_ALPHA_SET = 0x00040000; 2526 2527 /** 2528 * Set by {@link #setScrollContainer(boolean)}. 2529 */ 2530 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2531 2532 /** 2533 * Set by {@link #setScrollContainer(boolean)}. 2534 */ 2535 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2536 2537 /** 2538 * View flag indicating whether this view was invalidated (fully or partially.) 2539 * 2540 * @hide 2541 */ 2542 static final int PFLAG_DIRTY = 0x00200000; 2543 2544 /** 2545 * Mask for {@link #PFLAG_DIRTY}. 2546 * 2547 * @hide 2548 */ 2549 static final int PFLAG_DIRTY_MASK = 0x00200000; 2550 2551 /** 2552 * Indicates whether the background is opaque. 2553 * 2554 * @hide 2555 */ 2556 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2557 2558 /** 2559 * Indicates whether the scrollbars are opaque. 2560 * 2561 * @hide 2562 */ 2563 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2564 2565 /** 2566 * Indicates whether the view is opaque. 2567 * 2568 * @hide 2569 */ 2570 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2571 2572 /** 2573 * Indicates a prepressed state; 2574 * the short time between ACTION_DOWN and recognizing 2575 * a 'real' press. Prepressed is used to recognize quick taps 2576 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2577 * 2578 * @hide 2579 */ 2580 private static final int PFLAG_PREPRESSED = 0x02000000; 2581 2582 /** 2583 * Indicates whether the view is temporarily detached. 2584 * 2585 * @hide 2586 */ 2587 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2588 2589 /** 2590 * Indicates that we should awaken scroll bars once attached 2591 * 2592 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2593 * during window attachment and it is no longer needed. Feel free to repurpose it. 2594 * 2595 * @hide 2596 */ 2597 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2598 2599 /** 2600 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2601 * @hide 2602 */ 2603 private static final int PFLAG_HOVERED = 0x10000000; 2604 2605 /** 2606 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2607 */ 2608 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2609 2610 /** {@hide} */ 2611 static final int PFLAG_ACTIVATED = 0x40000000; 2612 2613 /** 2614 * Indicates that this view was specifically invalidated, not just dirtied because some 2615 * child view was invalidated. The flag is used to determine when we need to recreate 2616 * a view's display list (as opposed to just returning a reference to its existing 2617 * display list). 2618 * 2619 * @hide 2620 */ 2621 static final int PFLAG_INVALIDATED = 0x80000000; 2622 2623 /* End of masks for mPrivateFlags */ 2624 2625 /* 2626 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2627 * 2628 * |-------|-------|-------|-------| 2629 * 1 PFLAG2_DRAG_CAN_ACCEPT 2630 * 1 PFLAG2_DRAG_HOVERED 2631 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2632 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2633 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2634 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2635 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2636 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2637 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2638 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2639 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2640 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2641 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2642 * 111 PFLAG2_TEXT_DIRECTION_MASK 2643 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2644 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2645 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2646 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2647 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2648 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2649 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2650 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2651 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2652 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2653 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2654 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2655 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2656 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2657 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2658 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2659 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2660 * 1 PFLAG2_VIEW_QUICK_REJECTED 2661 * 1 PFLAG2_PADDING_RESOLVED 2662 * 1 PFLAG2_DRAWABLE_RESOLVED 2663 * 1 PFLAG2_HAS_TRANSIENT_STATE 2664 * |-------|-------|-------|-------| 2665 */ 2666 2667 /** 2668 * Indicates that this view has reported that it can accept the current drag's content. 2669 * Cleared when the drag operation concludes. 2670 * @hide 2671 */ 2672 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2673 2674 /** 2675 * Indicates that this view is currently directly under the drag location in a 2676 * drag-and-drop operation involving content that it can accept. Cleared when 2677 * the drag exits the view, or when the drag operation concludes. 2678 * @hide 2679 */ 2680 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2681 2682 /** @hide */ 2683 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2684 LAYOUT_DIRECTION_LTR, 2685 LAYOUT_DIRECTION_RTL, 2686 LAYOUT_DIRECTION_INHERIT, 2687 LAYOUT_DIRECTION_LOCALE 2688 }) 2689 @Retention(RetentionPolicy.SOURCE) 2690 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2691 public @interface LayoutDir {} 2692 2693 /** @hide */ 2694 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2695 LAYOUT_DIRECTION_LTR, 2696 LAYOUT_DIRECTION_RTL 2697 }) 2698 @Retention(RetentionPolicy.SOURCE) 2699 public @interface ResolvedLayoutDir {} 2700 2701 /** 2702 * A flag to indicate that the layout direction of this view has not been defined yet. 2703 * @hide 2704 */ 2705 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2706 2707 /** 2708 * Horizontal layout direction of this view is from Left to Right. 2709 * Use with {@link #setLayoutDirection}. 2710 */ 2711 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2712 2713 /** 2714 * Horizontal layout direction of this view is from Right to Left. 2715 * Use with {@link #setLayoutDirection}. 2716 */ 2717 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2718 2719 /** 2720 * Horizontal layout direction of this view is inherited from its parent. 2721 * Use with {@link #setLayoutDirection}. 2722 */ 2723 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2724 2725 /** 2726 * Horizontal layout direction of this view is from deduced from the default language 2727 * script for the locale. Use with {@link #setLayoutDirection}. 2728 */ 2729 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2730 2731 /** 2732 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2733 * @hide 2734 */ 2735 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2736 2737 /** 2738 * Mask for use with private flags indicating bits used for horizontal layout direction. 2739 * @hide 2740 */ 2741 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2742 2743 /** 2744 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2745 * right-to-left direction. 2746 * @hide 2747 */ 2748 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2749 2750 /** 2751 * Indicates whether the view horizontal layout direction has been resolved. 2752 * @hide 2753 */ 2754 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2755 2756 /** 2757 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2758 * @hide 2759 */ 2760 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2761 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2762 2763 /* 2764 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2765 * flag value. 2766 * @hide 2767 */ 2768 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2769 LAYOUT_DIRECTION_LTR, 2770 LAYOUT_DIRECTION_RTL, 2771 LAYOUT_DIRECTION_INHERIT, 2772 LAYOUT_DIRECTION_LOCALE 2773 }; 2774 2775 /** 2776 * Default horizontal layout direction. 2777 */ 2778 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2779 2780 /** 2781 * Default horizontal layout direction. 2782 * @hide 2783 */ 2784 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2785 2786 /** 2787 * Text direction is inherited through {@link ViewGroup} 2788 */ 2789 public static final int TEXT_DIRECTION_INHERIT = 0; 2790 2791 /** 2792 * Text direction is using "first strong algorithm". The first strong directional character 2793 * determines the paragraph direction. If there is no strong directional character, the 2794 * paragraph direction is the view's resolved layout direction. 2795 */ 2796 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2797 2798 /** 2799 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2800 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2801 * If there are neither, the paragraph direction is the view's resolved layout direction. 2802 */ 2803 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2804 2805 /** 2806 * Text direction is forced to LTR. 2807 */ 2808 public static final int TEXT_DIRECTION_LTR = 3; 2809 2810 /** 2811 * Text direction is forced to RTL. 2812 */ 2813 public static final int TEXT_DIRECTION_RTL = 4; 2814 2815 /** 2816 * Text direction is coming from the system Locale. 2817 */ 2818 public static final int TEXT_DIRECTION_LOCALE = 5; 2819 2820 /** 2821 * Text direction is using "first strong algorithm". The first strong directional character 2822 * determines the paragraph direction. If there is no strong directional character, the 2823 * paragraph direction is LTR. 2824 */ 2825 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2826 2827 /** 2828 * Text direction is using "first strong algorithm". The first strong directional character 2829 * determines the paragraph direction. If there is no strong directional character, the 2830 * paragraph direction is RTL. 2831 */ 2832 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2833 2834 /** 2835 * Default text direction is inherited 2836 */ 2837 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2838 2839 /** 2840 * Default resolved text direction 2841 * @hide 2842 */ 2843 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2844 2845 /** 2846 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2847 * @hide 2848 */ 2849 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2850 2851 /** 2852 * Mask for use with private flags indicating bits used for text direction. 2853 * @hide 2854 */ 2855 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2856 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2857 2858 /** 2859 * Array of text direction flags for mapping attribute "textDirection" to correct 2860 * flag value. 2861 * @hide 2862 */ 2863 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2864 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2865 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2866 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2867 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2868 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2869 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2870 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2871 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2872 }; 2873 2874 /** 2875 * Indicates whether the view text direction has been resolved. 2876 * @hide 2877 */ 2878 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2879 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2880 2881 /** 2882 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2883 * @hide 2884 */ 2885 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2886 2887 /** 2888 * Mask for use with private flags indicating bits used for resolved text direction. 2889 * @hide 2890 */ 2891 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2892 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2893 2894 /** 2895 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2896 * @hide 2897 */ 2898 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2899 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2900 2901 /** @hide */ 2902 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2903 TEXT_ALIGNMENT_INHERIT, 2904 TEXT_ALIGNMENT_GRAVITY, 2905 TEXT_ALIGNMENT_CENTER, 2906 TEXT_ALIGNMENT_TEXT_START, 2907 TEXT_ALIGNMENT_TEXT_END, 2908 TEXT_ALIGNMENT_VIEW_START, 2909 TEXT_ALIGNMENT_VIEW_END 2910 }) 2911 @Retention(RetentionPolicy.SOURCE) 2912 public @interface TextAlignment {} 2913 2914 /** 2915 * Default text alignment. The text alignment of this View is inherited from its parent. 2916 * Use with {@link #setTextAlignment(int)} 2917 */ 2918 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2919 2920 /** 2921 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2922 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 2923 * 2924 * Use with {@link #setTextAlignment(int)} 2925 */ 2926 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2927 2928 /** 2929 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2930 * 2931 * Use with {@link #setTextAlignment(int)} 2932 */ 2933 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2934 2935 /** 2936 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2937 * 2938 * Use with {@link #setTextAlignment(int)} 2939 */ 2940 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2941 2942 /** 2943 * Center the paragraph, e.g. ALIGN_CENTER. 2944 * 2945 * Use with {@link #setTextAlignment(int)} 2946 */ 2947 public static final int TEXT_ALIGNMENT_CENTER = 4; 2948 2949 /** 2950 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 2951 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2952 * 2953 * Use with {@link #setTextAlignment(int)} 2954 */ 2955 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2956 2957 /** 2958 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 2959 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2960 * 2961 * Use with {@link #setTextAlignment(int)} 2962 */ 2963 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2964 2965 /** 2966 * Default text alignment is inherited 2967 */ 2968 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2969 2970 /** 2971 * Default resolved text alignment 2972 * @hide 2973 */ 2974 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2975 2976 /** 2977 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2978 * @hide 2979 */ 2980 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2981 2982 /** 2983 * Mask for use with private flags indicating bits used for text alignment. 2984 * @hide 2985 */ 2986 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2987 2988 /** 2989 * Array of text direction flags for mapping attribute "textAlignment" to correct 2990 * flag value. 2991 * @hide 2992 */ 2993 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2994 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2995 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2996 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2997 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2998 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2999 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3000 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 3001 }; 3002 3003 /** 3004 * Indicates whether the view text alignment has been resolved. 3005 * @hide 3006 */ 3007 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3008 3009 /** 3010 * Bit shift to get the resolved text alignment. 3011 * @hide 3012 */ 3013 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 3014 3015 /** 3016 * Mask for use with private flags indicating bits used for text alignment. 3017 * @hide 3018 */ 3019 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 3020 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3021 3022 /** 3023 * Indicates whether if the view text alignment has been resolved to gravity 3024 */ 3025 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3026 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3027 3028 // Accessiblity constants for mPrivateFlags2 3029 3030 /** 3031 * Shift for the bits in {@link #mPrivateFlags2} related to the 3032 * "importantForAccessibility" attribute. 3033 */ 3034 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3035 3036 /** 3037 * Automatically determine whether a view is important for accessibility. 3038 */ 3039 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3040 3041 /** 3042 * The view is important for accessibility. 3043 */ 3044 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3045 3046 /** 3047 * The view is not important for accessibility. 3048 */ 3049 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3050 3051 /** 3052 * The view is not important for accessibility, nor are any of its 3053 * descendant views. 3054 */ 3055 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3056 3057 /** 3058 * The default whether the view is important for accessibility. 3059 */ 3060 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3061 3062 /** 3063 * Mask for obtaining the bits which specify how to determine 3064 * whether a view is important for accessibility. 3065 */ 3066 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3067 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3068 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3069 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3070 3071 /** 3072 * Shift for the bits in {@link #mPrivateFlags2} related to the 3073 * "accessibilityLiveRegion" attribute. 3074 */ 3075 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3076 3077 /** 3078 * Live region mode specifying that accessibility services should not 3079 * automatically announce changes to this view. This is the default live 3080 * region mode for most views. 3081 * <p> 3082 * Use with {@link #setAccessibilityLiveRegion(int)}. 3083 */ 3084 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3085 3086 /** 3087 * Live region mode specifying that accessibility services should announce 3088 * changes to this view. 3089 * <p> 3090 * Use with {@link #setAccessibilityLiveRegion(int)}. 3091 */ 3092 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3093 3094 /** 3095 * Live region mode specifying that accessibility services should interrupt 3096 * ongoing speech to immediately announce changes to this view. 3097 * <p> 3098 * Use with {@link #setAccessibilityLiveRegion(int)}. 3099 */ 3100 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3101 3102 /** 3103 * The default whether the view is important for accessibility. 3104 */ 3105 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3106 3107 /** 3108 * Mask for obtaining the bits which specify a view's accessibility live 3109 * region mode. 3110 */ 3111 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3112 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3113 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3114 3115 /** 3116 * Flag indicating whether a view has accessibility focus. 3117 */ 3118 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3119 3120 /** 3121 * Flag whether the accessibility state of the subtree rooted at this view changed. 3122 */ 3123 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3124 3125 /** 3126 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3127 * is used to check whether later changes to the view's transform should invalidate the 3128 * view to force the quickReject test to run again. 3129 */ 3130 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3131 3132 /** 3133 * Flag indicating that start/end padding has been resolved into left/right padding 3134 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3135 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3136 * during measurement. In some special cases this is required such as when an adapter-based 3137 * view measures prospective children without attaching them to a window. 3138 */ 3139 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3140 3141 /** 3142 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3143 */ 3144 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3145 3146 /** 3147 * Indicates that the view is tracking some sort of transient state 3148 * that the app should not need to be aware of, but that the framework 3149 * should take special care to preserve. 3150 */ 3151 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3152 3153 /** 3154 * Group of bits indicating that RTL properties resolution is done. 3155 */ 3156 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3157 PFLAG2_TEXT_DIRECTION_RESOLVED | 3158 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3159 PFLAG2_PADDING_RESOLVED | 3160 PFLAG2_DRAWABLE_RESOLVED; 3161 3162 // There are a couple of flags left in mPrivateFlags2 3163 3164 /* End of masks for mPrivateFlags2 */ 3165 3166 /* 3167 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3168 * 3169 * |-------|-------|-------|-------| 3170 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3171 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3172 * 1 PFLAG3_IS_LAID_OUT 3173 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3174 * 1 PFLAG3_CALLED_SUPER 3175 * 1 PFLAG3_APPLYING_INSETS 3176 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3177 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3178 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3179 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3180 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3181 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3182 * 1 PFLAG3_SCROLL_INDICATOR_START 3183 * 1 PFLAG3_SCROLL_INDICATOR_END 3184 * 1 PFLAG3_ASSIST_BLOCKED 3185 * 1 PFLAG3_CLUSTER 3186 * 1 PFLAG3_IS_AUTOFILLED 3187 * 1 PFLAG3_FINGER_DOWN 3188 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3189 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3190 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3191 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3192 * 1 PFLAG3_TEMPORARY_DETACH 3193 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3194 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3195 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3196 * 1 PFLAG3_AGGREGATED_VISIBLE 3197 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3198 * 1 PFLAG3_ACCESSIBILITY_HEADING 3199 * |-------|-------|-------|-------| 3200 */ 3201 3202 /** 3203 * Flag indicating that view has a transform animation set on it. This is used to track whether 3204 * an animation is cleared between successive frames, in order to tell the associated 3205 * DisplayList to clear its animation matrix. 3206 */ 3207 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3208 3209 /** 3210 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3211 * animation is cleared between successive frames, in order to tell the associated 3212 * DisplayList to restore its alpha value. 3213 */ 3214 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3215 3216 /** 3217 * Flag indicating that the view has been through at least one layout since it 3218 * was last attached to a window. 3219 */ 3220 static final int PFLAG3_IS_LAID_OUT = 0x4; 3221 3222 /** 3223 * Flag indicating that a call to measure() was skipped and should be done 3224 * instead when layout() is invoked. 3225 */ 3226 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3227 3228 /** 3229 * Flag indicating that an overridden method correctly called down to 3230 * the superclass implementation as required by the API spec. 3231 */ 3232 static final int PFLAG3_CALLED_SUPER = 0x10; 3233 3234 /** 3235 * Flag indicating that we're in the process of applying window insets. 3236 */ 3237 static final int PFLAG3_APPLYING_INSETS = 0x20; 3238 3239 /** 3240 * Flag indicating that we're in the process of fitting system windows using the old method. 3241 */ 3242 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3243 3244 /** 3245 * Flag indicating that nested scrolling is enabled for this view. 3246 * The view will optionally cooperate with views up its parent chain to allow for 3247 * integrated nested scrolling along the same axis. 3248 */ 3249 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3250 3251 /** 3252 * Flag indicating that the bottom scroll indicator should be displayed 3253 * when this view can scroll up. 3254 */ 3255 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3256 3257 /** 3258 * Flag indicating that the bottom scroll indicator should be displayed 3259 * when this view can scroll down. 3260 */ 3261 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3262 3263 /** 3264 * Flag indicating that the left scroll indicator should be displayed 3265 * when this view can scroll left. 3266 */ 3267 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3268 3269 /** 3270 * Flag indicating that the right scroll indicator should be displayed 3271 * when this view can scroll right. 3272 */ 3273 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3274 3275 /** 3276 * Flag indicating that the start scroll indicator should be displayed 3277 * when this view can scroll in the start direction. 3278 */ 3279 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3280 3281 /** 3282 * Flag indicating that the end scroll indicator should be displayed 3283 * when this view can scroll in the end direction. 3284 */ 3285 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3286 3287 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3288 3289 static final int SCROLL_INDICATORS_NONE = 0x0000; 3290 3291 /** 3292 * Mask for use with setFlags indicating bits used for indicating which 3293 * scroll indicators are enabled. 3294 */ 3295 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3296 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3297 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3298 | PFLAG3_SCROLL_INDICATOR_END; 3299 3300 /** 3301 * Left-shift required to translate between public scroll indicator flags 3302 * and internal PFLAGS3 flags. When used as a right-shift, translates 3303 * PFLAGS3 flags to public flags. 3304 */ 3305 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3306 3307 /** @hide */ 3308 @Retention(RetentionPolicy.SOURCE) 3309 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3310 SCROLL_INDICATOR_TOP, 3311 SCROLL_INDICATOR_BOTTOM, 3312 SCROLL_INDICATOR_LEFT, 3313 SCROLL_INDICATOR_RIGHT, 3314 SCROLL_INDICATOR_START, 3315 SCROLL_INDICATOR_END, 3316 }) 3317 public @interface ScrollIndicators {} 3318 3319 /** 3320 * Scroll indicator direction for the top edge of the view. 3321 * 3322 * @see #setScrollIndicators(int) 3323 * @see #setScrollIndicators(int, int) 3324 * @see #getScrollIndicators() 3325 */ 3326 public static final int SCROLL_INDICATOR_TOP = 3327 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3328 3329 /** 3330 * Scroll indicator direction for the bottom edge of the view. 3331 * 3332 * @see #setScrollIndicators(int) 3333 * @see #setScrollIndicators(int, int) 3334 * @see #getScrollIndicators() 3335 */ 3336 public static final int SCROLL_INDICATOR_BOTTOM = 3337 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3338 3339 /** 3340 * Scroll indicator direction for the left edge of the view. 3341 * 3342 * @see #setScrollIndicators(int) 3343 * @see #setScrollIndicators(int, int) 3344 * @see #getScrollIndicators() 3345 */ 3346 public static final int SCROLL_INDICATOR_LEFT = 3347 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3348 3349 /** 3350 * Scroll indicator direction for the right edge of the view. 3351 * 3352 * @see #setScrollIndicators(int) 3353 * @see #setScrollIndicators(int, int) 3354 * @see #getScrollIndicators() 3355 */ 3356 public static final int SCROLL_INDICATOR_RIGHT = 3357 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3358 3359 /** 3360 * Scroll indicator direction for the starting edge of the view. 3361 * <p> 3362 * Resolved according to the view's layout direction, see 3363 * {@link #getLayoutDirection()} for more information. 3364 * 3365 * @see #setScrollIndicators(int) 3366 * @see #setScrollIndicators(int, int) 3367 * @see #getScrollIndicators() 3368 */ 3369 public static final int SCROLL_INDICATOR_START = 3370 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3371 3372 /** 3373 * Scroll indicator direction for the ending edge of the view. 3374 * <p> 3375 * Resolved according to the view's layout direction, see 3376 * {@link #getLayoutDirection()} for more information. 3377 * 3378 * @see #setScrollIndicators(int) 3379 * @see #setScrollIndicators(int, int) 3380 * @see #getScrollIndicators() 3381 */ 3382 public static final int SCROLL_INDICATOR_END = 3383 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3384 3385 /** 3386 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3387 * into this view.<p> 3388 */ 3389 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3390 3391 /** 3392 * Flag indicating that the view is a root of a keyboard navigation cluster. 3393 * 3394 * @see #isKeyboardNavigationCluster() 3395 * @see #setKeyboardNavigationCluster(boolean) 3396 */ 3397 private static final int PFLAG3_CLUSTER = 0x8000; 3398 3399 /** 3400 * Flag indicating that the view is autofilled 3401 * 3402 * @see #isAutofilled() 3403 * @see #setAutofilled(boolean, boolean) 3404 */ 3405 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3406 3407 /** 3408 * Indicates that the user is currently touching the screen. 3409 * Currently used for the tooltip positioning only. 3410 */ 3411 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3412 3413 /** 3414 * Flag indicating that this view is the default-focus view. 3415 * 3416 * @see #isFocusedByDefault() 3417 * @see #setFocusedByDefault(boolean) 3418 */ 3419 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3420 3421 /** 3422 * Shift for the bits in {@link #mPrivateFlags3} related to the 3423 * "importantForAutofill" attribute. 3424 */ 3425 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3426 3427 /** 3428 * Mask for obtaining the bits which specify how to determine 3429 * whether a view is important for autofill. 3430 */ 3431 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3432 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3433 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3434 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3435 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3436 3437 /** 3438 * Whether this view has rendered elements that overlap (see {@link 3439 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3440 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3441 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3442 * determined by whatever {@link #hasOverlappingRendering()} returns. 3443 */ 3444 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3445 3446 /** 3447 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3448 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3449 */ 3450 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3451 3452 /** 3453 * Flag indicating that the view is temporarily detached from the parent view. 3454 * 3455 * @see #onStartTemporaryDetach() 3456 * @see #onFinishTemporaryDetach() 3457 */ 3458 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3459 3460 /** 3461 * Flag indicating that the view does not wish to be revealed within its parent 3462 * hierarchy when it gains focus. Expressed in the negative since the historical 3463 * default behavior is to reveal on focus; this flag suppresses that behavior. 3464 * 3465 * @see #setRevealOnFocusHint(boolean) 3466 * @see #getRevealOnFocusHint() 3467 */ 3468 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3469 3470 /** 3471 * Flag indicating that when layout is completed we should notify 3472 * that the view was entered for autofill purposes. To minimize 3473 * showing autofill for views not visible to the user we evaluate 3474 * user visibility which cannot be done until the view is laid out. 3475 */ 3476 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3477 3478 /** 3479 * Works like focusable for screen readers, but without the side effects on input focus. 3480 * @see #setScreenReaderFocusable(boolean) 3481 */ 3482 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3483 3484 /** 3485 * The last aggregated visibility. Used to detect when it truly changes. 3486 */ 3487 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3488 3489 /** 3490 * Used to indicate that {@link #mAutofillId} was explicitly set through 3491 * {@link #setAutofillId(AutofillId)}. 3492 */ 3493 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3494 3495 /** 3496 * Indicates if the View is a heading for accessibility purposes 3497 */ 3498 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3499 3500 /* End of masks for mPrivateFlags3 */ 3501 3502 /* 3503 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3504 * 3505 * |-------|-------|-------|-------| 3506 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3507 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3508 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3509 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3510 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3511 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3512 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3513 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3514 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3515 * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED 3516 * 1 PFLAG4_DETACHED 3517 * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE 3518 * 1 PFLAG4_DRAG_A11Y_STARTED 3519 * |-------|-------|-------|-------| 3520 */ 3521 3522 /** 3523 * Mask for obtaining the bits which specify how to determine 3524 * whether a view is important for autofill. 3525 * 3526 * <p>NOTE: the important for content capture values were the first flags added and are set in 3527 * the rightmost position, so we don't need to shift them 3528 */ 3529 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3530 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3531 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3532 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3533 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3534 3535 /* 3536 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3537 * should be called. 3538 * 3539 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3540 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3541 */ 3542 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3543 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3544 3545 /* 3546 * Flags used to cache the value returned by isImportantForContentCapture while the view 3547 * hierarchy is being traversed. 3548 */ 3549 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3550 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3551 3552 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3553 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3554 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3555 3556 /** 3557 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3558 */ 3559 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3560 3561 /** 3562 * Flag indicating the field should not have yellow highlight when autofilled. 3563 */ 3564 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3565 3566 /** 3567 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3568 */ 3569 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3570 3571 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3572 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3573 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3574 3575 /** 3576 * Indicates if the view can receive click events when disabled. 3577 */ 3578 private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; 3579 3580 /** 3581 * Indicates if the view is just detached. 3582 */ 3583 private static final int PFLAG4_DETACHED = 0x000002000; 3584 3585 /** 3586 * Indicates that the view has transient state because the system is translating it. 3587 */ 3588 private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; 3589 3590 /** 3591 * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START} 3592 */ 3593 private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; 3594 3595 /* End of masks for mPrivateFlags4 */ 3596 3597 /** @hide */ 3598 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3599 /** @hide */ 3600 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3601 /** @hide */ 3602 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3603 3604 /** @hide */ 3605 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3606 VIEW_STRUCTURE_FOR_ASSIST, 3607 VIEW_STRUCTURE_FOR_AUTOFILL, 3608 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3609 }) 3610 @Retention(RetentionPolicy.SOURCE) 3611 public @interface ViewStructureType {} 3612 3613 /** 3614 * Always allow a user to over-scroll this view, provided it is a 3615 * view that can scroll. 3616 * 3617 * @see #getOverScrollMode() 3618 * @see #setOverScrollMode(int) 3619 */ 3620 public static final int OVER_SCROLL_ALWAYS = 0; 3621 3622 /** 3623 * Allow a user to over-scroll this view only if the content is large 3624 * enough to meaningfully scroll, provided it is a view that can scroll. 3625 * 3626 * @see #getOverScrollMode() 3627 * @see #setOverScrollMode(int) 3628 */ 3629 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3630 3631 /** 3632 * Never allow a user to over-scroll this view. 3633 * 3634 * @see #getOverScrollMode() 3635 * @see #setOverScrollMode(int) 3636 */ 3637 public static final int OVER_SCROLL_NEVER = 2; 3638 3639 /** 3640 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3641 * requested the system UI (status bar) to be visible (the default). 3642 * 3643 * @see #setSystemUiVisibility(int) 3644 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 3645 * instead. 3646 */ 3647 @Deprecated 3648 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3649 3650 /** 3651 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3652 * system UI to enter an unobtrusive "low profile" mode. 3653 * 3654 * <p>This is for use in games, book readers, video players, or any other 3655 * "immersive" application where the usual system chrome is deemed too distracting. 3656 * 3657 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3658 * 3659 * @see #setSystemUiVisibility(int) 3660 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 3661 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 3662 * {@link Type#systemBars()}. 3663 */ 3664 @Deprecated 3665 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3666 3667 /** 3668 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3669 * system navigation be temporarily hidden. 3670 * 3671 * <p>This is an even less obtrusive state than that called for by 3672 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3673 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3674 * those to disappear. This is useful (in conjunction with the 3675 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3676 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3677 * window flags) for displaying content using every last pixel on the display. 3678 * 3679 * <p>There is a limitation: because navigation controls are so important, the least user 3680 * interaction will cause them to reappear immediately. When this happens, both 3681 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3682 * so that both elements reappear at the same time. 3683 * 3684 * @see #setSystemUiVisibility(int) 3685 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 3686 * instead. 3687 */ 3688 @Deprecated 3689 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3690 3691 /** 3692 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3693 * into the normal fullscreen mode so that its content can take over the screen 3694 * while still allowing the user to interact with the application. 3695 * 3696 * <p>This has the same visual effect as 3697 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3698 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3699 * meaning that non-critical screen decorations (such as the status bar) will be 3700 * hidden while the user is in the View's window, focusing the experience on 3701 * that content. Unlike the window flag, if you are using ActionBar in 3702 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3703 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3704 * hide the action bar. 3705 * 3706 * <p>This approach to going fullscreen is best used over the window flag when 3707 * it is a transient state -- that is, the application does this at certain 3708 * points in its user interaction where it wants to allow the user to focus 3709 * on content, but not as a continuous state. For situations where the application 3710 * would like to simply stay full screen the entire time (such as a game that 3711 * wants to take over the screen), the 3712 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3713 * is usually a better approach. The state set here will be removed by the system 3714 * in various situations (such as the user moving to another application) like 3715 * the other system UI states. 3716 * 3717 * <p>When using this flag, the application should provide some easy facility 3718 * for the user to go out of it. A common example would be in an e-book 3719 * reader, where tapping on the screen brings back whatever screen and UI 3720 * decorations that had been hidden while the user was immersed in reading 3721 * the book. 3722 * 3723 * @see #setSystemUiVisibility(int) 3724 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 3725 * instead. 3726 */ 3727 @Deprecated 3728 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3729 3730 /** 3731 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3732 * flags, we would like a stable view of the content insets given to 3733 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3734 * will always represent the worst case that the application can expect 3735 * as a continuous state. In the stock Android UI this is the space for 3736 * the system bar, nav bar, and status bar, but not more transient elements 3737 * such as an input method. 3738 * 3739 * The stable layout your UI sees is based on the system UI modes you can 3740 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3741 * then you will get a stable layout for changes of the 3742 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3743 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3744 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3745 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3746 * with a stable layout. (Note that you should avoid using 3747 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3748 * 3749 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3750 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3751 * then a hidden status bar will be considered a "stable" state for purposes 3752 * here. This allows your UI to continually hide the status bar, while still 3753 * using the system UI flags to hide the action bar while still retaining 3754 * a stable layout. Note that changing the window fullscreen flag will never 3755 * provide a stable layout for a clean transition. 3756 * 3757 * <p>If you are using ActionBar in 3758 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3759 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3760 * insets it adds to those given to the application. 3761 * 3762 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 3763 * insets that don't change when system bars change visibility state. 3764 */ 3765 @Deprecated 3766 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3767 3768 /** 3769 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3770 * to be laid out as if it has requested 3771 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3772 * allows it to avoid artifacts when switching in and out of that mode, at 3773 * the expense that some of its user interface may be covered by screen 3774 * decorations when they are shown. You can perform layout of your inner 3775 * UI elements to account for the navigation system UI through the 3776 * {@link #fitSystemWindows(Rect)} method. 3777 * 3778 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3779 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 3780 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3781 */ 3782 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3783 3784 /** 3785 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3786 * to be laid out as if it has requested 3787 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3788 * allows it to avoid artifacts when switching in and out of that mode, at 3789 * the expense that some of its user interface may be covered by screen 3790 * decorations when they are shown. You can perform layout of your inner 3791 * UI elements to account for non-fullscreen system UI through the 3792 * {@link #fitSystemWindows(Rect)} method. 3793 * 3794 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3795 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3796 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3797 * layoutInDisplayCutoutMode} is 3798 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3799 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3800 * 3801 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3802 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3803 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3804 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3805 * 3806 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3807 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 3808 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3809 */ 3810 @Deprecated 3811 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3812 3813 /** 3814 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3815 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3816 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3817 * user interaction. 3818 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3819 * has an effect when used in combination with that flag.</p> 3820 * 3821 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead. 3822 */ 3823 @Deprecated 3824 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3825 3826 /** 3827 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3828 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3829 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3830 * experience while also hiding the system bars. If this flag is not set, 3831 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3832 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3833 * if the user swipes from the top of the screen. 3834 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3835 * system gestures, such as swiping from the top of the screen. These transient system bars 3836 * will overlay app's content, may have some degree of transparency, and will automatically 3837 * hide after a short timeout. 3838 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3839 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3840 * with one or both of those flags.</p> 3841 * 3842 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 3843 */ 3844 @Deprecated 3845 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3846 3847 /** 3848 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3849 * is compatible with light status bar backgrounds. 3850 * 3851 * <p>For this to take effect, the window must request 3852 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3853 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3854 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3855 * FLAG_TRANSLUCENT_STATUS}. 3856 * 3857 * @see android.R.attr#windowLightStatusBar 3858 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 3859 */ 3860 @Deprecated 3861 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3862 3863 /** 3864 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3865 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3866 */ 3867 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3868 3869 /** 3870 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3871 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3872 */ 3873 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3874 3875 /** 3876 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3877 * that is compatible with light navigation bar backgrounds. 3878 * 3879 * <p>For this to take effect, the window must request 3880 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3881 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3882 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3883 * FLAG_TRANSLUCENT_NAVIGATION}. 3884 * 3885 * @see android.R.attr#windowLightNavigationBar 3886 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 3887 */ 3888 @Deprecated 3889 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3890 3891 /** 3892 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3893 */ 3894 @Deprecated 3895 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3896 3897 /** 3898 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3899 */ 3900 @Deprecated 3901 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 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 make the status bar not expandable. Unless you also 3910 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3911 */ 3912 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3913 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3914 3915 /** 3916 * @hide 3917 * 3918 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3919 * out of the public fields to keep the undefined bits out of the developer's way. 3920 * 3921 * Flag to hide notification icons and scrolling ticker text. 3922 */ 3923 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 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 disable incoming notification alerts. This will not block 3932 * icons, but it will block sound, vibrating and other visual or aural notifications. 3933 */ 3934 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3935 3936 /** 3937 * @hide 3938 * 3939 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3940 * out of the public fields to keep the undefined bits out of the developer's way. 3941 * 3942 * Flag to hide only the scrolling ticker. Note that 3943 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3944 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3945 */ 3946 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 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 the center system info area. 3955 */ 3956 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3957 3958 /** 3959 * @hide 3960 * 3961 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3962 * out of the public fields to keep the undefined bits out of the developer's way. 3963 * 3964 * Flag to hide only the home button. Don't use this 3965 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3966 */ 3967 @UnsupportedAppUsage 3968 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3969 3970 /** 3971 * @hide 3972 * 3973 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3974 * out of the public fields to keep the undefined bits out of the developer's way. 3975 * 3976 * Flag to hide only the back button. Don't use this 3977 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3978 */ 3979 @UnsupportedAppUsage 3980 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3981 3982 /** 3983 * @hide 3984 * 3985 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3986 * out of the public fields to keep the undefined bits out of the developer's way. 3987 * 3988 * Flag to hide only the clock. You might use this if your activity has 3989 * its own clock making the status bar's clock redundant. 3990 */ 3991 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3992 3993 /** 3994 * @hide 3995 * 3996 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3997 * out of the public fields to keep the undefined bits out of the developer's way. 3998 * 3999 * Flag to hide only the recent apps button. Don't use this 4000 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4001 */ 4002 @UnsupportedAppUsage 4003 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 4004 4005 /** 4006 * @hide 4007 * 4008 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4009 * out of the public fields to keep the undefined bits out of the developer's way. 4010 * 4011 * Flag to disable the global search gesture. Don't use this 4012 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4013 */ 4014 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 4015 4016 /** 4017 * @hide 4018 * 4019 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4020 * out of the public fields to keep the undefined bits out of the developer's way. 4021 * 4022 * Flag to disable the ongoing call chip. 4023 */ 4024 public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; 4025 4026 /** 4027 * @hide 4028 */ 4029 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4030 4031 /** 4032 * These are the system UI flags that can be cleared by events outside 4033 * of an application. Currently this is just the ability to tap on the 4034 * screen while hiding the navigation bar to have it return. 4035 * @hide 4036 */ 4037 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4038 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4039 | SYSTEM_UI_FLAG_FULLSCREEN; 4040 4041 /** 4042 * Flags that can impact the layout in relation to system UI. 4043 * 4044 * @deprecated System UI layout flags are deprecated. 4045 */ 4046 @Deprecated 4047 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4048 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4049 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4050 4051 /** @hide */ 4052 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4053 FIND_VIEWS_WITH_TEXT, 4054 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4055 }) 4056 @Retention(RetentionPolicy.SOURCE) 4057 public @interface FindViewFlags {} 4058 4059 /** 4060 * Find views that render the specified text. 4061 * 4062 * @see #findViewsWithText(ArrayList, CharSequence, int) 4063 */ 4064 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4065 4066 /** 4067 * Find find views that contain the specified content description. 4068 * 4069 * @see #findViewsWithText(ArrayList, CharSequence, int) 4070 */ 4071 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4072 4073 /** 4074 * Find views that contain {@link AccessibilityNodeProvider}. Such 4075 * a View is a root of virtual view hierarchy and may contain the searched 4076 * text. If this flag is set Views with providers are automatically 4077 * added and it is a responsibility of the client to call the APIs of 4078 * the provider to determine whether the virtual tree rooted at this View 4079 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4080 * representing the virtual views with this text. 4081 * 4082 * @see #findViewsWithText(ArrayList, CharSequence, int) 4083 * 4084 * @hide 4085 */ 4086 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4087 4088 /** 4089 * The undefined cursor position. 4090 * 4091 * @hide 4092 */ 4093 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4094 4095 /** 4096 * Indicates that the screen has changed state and is now off. 4097 * 4098 * @see #onScreenStateChanged(int) 4099 */ 4100 public static final int SCREEN_STATE_OFF = 0x0; 4101 4102 /** 4103 * Indicates that the screen has changed state and is now on. 4104 * 4105 * @see #onScreenStateChanged(int) 4106 */ 4107 public static final int SCREEN_STATE_ON = 0x1; 4108 4109 /** 4110 * Indicates no axis of view scrolling. 4111 */ 4112 public static final int SCROLL_AXIS_NONE = 0; 4113 4114 /** 4115 * Indicates scrolling along the horizontal axis. 4116 */ 4117 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4118 4119 /** 4120 * Indicates scrolling along the vertical axis. 4121 */ 4122 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4123 4124 /** 4125 * Controls the over-scroll mode for this view. 4126 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4127 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4128 * and {@link #OVER_SCROLL_NEVER}. 4129 */ 4130 private int mOverScrollMode; 4131 4132 /** 4133 * The parent this view is attached to. 4134 * {@hide} 4135 * 4136 * @see #getParent() 4137 */ 4138 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4139 protected ViewParent mParent; 4140 4141 /** 4142 * {@hide} 4143 * 4144 * Not available for general use. If you need help, hang up and then dial one of the following 4145 * public APIs: 4146 * 4147 * @see #isAttachedToWindow() for current attach state 4148 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4149 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4150 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4151 * @see #getHandler() for posting messages to this view's UI thread/looper 4152 * @see #getParent() for interacting with the parent chain 4153 * @see #getWindowToken() for the current window token 4154 * @see #getRootView() for the view at the root of the attached hierarchy 4155 * @see #getDisplay() for the Display this view is presented on 4156 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4157 * @see #hasWindowFocus() for whether the attached window is currently focused 4158 * @see #getWindowVisibility() for checking the visibility of the attached window 4159 */ 4160 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4161 AttachInfo mAttachInfo; 4162 4163 /** 4164 * {@hide} 4165 */ 4166 @ViewDebug.ExportedProperty(flagMapping = { 4167 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4168 name = "FORCE_LAYOUT"), 4169 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4170 name = "LAYOUT_REQUIRED"), 4171 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4172 name = "DRAWING_CACHE_INVALID", outputIf = false), 4173 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4174 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4175 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4176 }, formatToHexString = true) 4177 4178 /* @hide */ 4179 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4180 public int mPrivateFlags; 4181 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4182 int mPrivateFlags2; 4183 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4184 int mPrivateFlags3; 4185 4186 private int mPrivateFlags4; 4187 4188 /** 4189 * This view's request for the visibility of the status bar. 4190 * @hide 4191 */ 4192 @ViewDebug.ExportedProperty(flagMapping = { 4193 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4194 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4195 name = "LOW_PROFILE"), 4196 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4197 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4198 name = "HIDE_NAVIGATION"), 4199 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4200 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4201 name = "FULLSCREEN"), 4202 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4203 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4204 name = "LAYOUT_STABLE"), 4205 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4206 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4207 name = "LAYOUT_HIDE_NAVIGATION"), 4208 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4209 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4210 name = "LAYOUT_FULLSCREEN"), 4211 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4212 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4213 name = "IMMERSIVE"), 4214 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4215 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4216 name = "IMMERSIVE_STICKY"), 4217 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4218 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4219 name = "LIGHT_STATUS_BAR"), 4220 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4221 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4222 name = "LIGHT_NAVIGATION_BAR"), 4223 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4224 equals = STATUS_BAR_DISABLE_EXPAND, 4225 name = "STATUS_BAR_DISABLE_EXPAND"), 4226 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4227 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4228 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4229 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4230 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4231 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4232 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4233 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4234 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4235 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4236 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4237 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4238 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4239 equals = STATUS_BAR_DISABLE_HOME, 4240 name = "STATUS_BAR_DISABLE_HOME"), 4241 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4242 equals = STATUS_BAR_DISABLE_BACK, 4243 name = "STATUS_BAR_DISABLE_BACK"), 4244 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4245 equals = STATUS_BAR_DISABLE_CLOCK, 4246 name = "STATUS_BAR_DISABLE_CLOCK"), 4247 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4248 equals = STATUS_BAR_DISABLE_RECENT, 4249 name = "STATUS_BAR_DISABLE_RECENT"), 4250 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4251 equals = STATUS_BAR_DISABLE_SEARCH, 4252 name = "STATUS_BAR_DISABLE_SEARCH"), 4253 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4254 equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4255 name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") 4256 }, formatToHexString = true) 4257 @SystemUiVisibility 4258 int mSystemUiVisibility; 4259 4260 /** 4261 * @hide 4262 */ 4263 @IntDef(flag = true, prefix = "", value = { 4264 SYSTEM_UI_FLAG_LOW_PROFILE, 4265 SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4266 SYSTEM_UI_FLAG_FULLSCREEN, 4267 SYSTEM_UI_FLAG_LAYOUT_STABLE, 4268 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4269 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4270 SYSTEM_UI_FLAG_IMMERSIVE, 4271 SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4272 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4273 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4274 STATUS_BAR_DISABLE_EXPAND, 4275 STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4276 STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4277 STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4278 STATUS_BAR_DISABLE_SYSTEM_INFO, 4279 STATUS_BAR_DISABLE_HOME, 4280 STATUS_BAR_DISABLE_BACK, 4281 STATUS_BAR_DISABLE_CLOCK, 4282 STATUS_BAR_DISABLE_RECENT, 4283 STATUS_BAR_DISABLE_SEARCH, 4284 STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4285 }) 4286 @Retention(RetentionPolicy.SOURCE) 4287 public @interface SystemUiVisibility {} 4288 4289 /** 4290 * Reference count for transient state. 4291 * @see #setHasTransientState(boolean) 4292 */ 4293 int mTransientStateCount = 0; 4294 4295 /** 4296 * Count of how many windows this view has been attached to. 4297 */ 4298 int mWindowAttachCount; 4299 4300 /** 4301 * The layout parameters associated with this view and used by the parent 4302 * {@link android.view.ViewGroup} to determine how this view should be 4303 * laid out. 4304 * 4305 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4306 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4307 * state correctness of the class. 4308 * {@hide} 4309 */ 4310 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4311 protected ViewGroup.LayoutParams mLayoutParams; 4312 4313 /** 4314 * The view flags hold various views states. 4315 * 4316 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4317 * triggering updates. 4318 * {@hide} 4319 */ 4320 @ViewDebug.ExportedProperty(formatToHexString = true) 4321 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4322 int mViewFlags; 4323 4324 static class TransformationInfo { 4325 /** 4326 * The transform matrix for the View. This transform is calculated internally 4327 * based on the translation, rotation, and scale properties. 4328 * 4329 * Do *not* use this variable directly; instead call getMatrix(), which will 4330 * load the value from the View's RenderNode. 4331 */ 4332 private final Matrix mMatrix = new Matrix(); 4333 4334 /** 4335 * The inverse transform matrix for the View. This transform is calculated 4336 * internally based on the translation, rotation, and scale properties. 4337 * 4338 * Do *not* use this variable directly; instead call getInverseMatrix(), 4339 * which will load the value from the View's RenderNode. 4340 */ 4341 private Matrix mInverseMatrix; 4342 4343 /** 4344 * The opacity of the View. This is a value from 0 to 1, where 0 means 4345 * completely transparent and 1 means completely opaque. 4346 */ 4347 @ViewDebug.ExportedProperty 4348 private float mAlpha = 1f; 4349 4350 /** 4351 * The opacity of the view as manipulated by the Fade transition. This is a 4352 * property only used by transitions, which is composited with the other alpha 4353 * values to calculate the final visual alpha value. 4354 */ 4355 float mTransitionAlpha = 1f; 4356 } 4357 4358 /** @hide */ 4359 @UnsupportedAppUsage 4360 public TransformationInfo mTransformationInfo; 4361 4362 /** 4363 * Current clip bounds. to which all drawing of this view are constrained. 4364 */ 4365 @ViewDebug.ExportedProperty(category = "drawing") 4366 Rect mClipBounds = null; 4367 4368 private boolean mLastIsOpaque; 4369 4370 /** 4371 * The distance in pixels from the left edge of this view's parent 4372 * to the left edge of this view. 4373 * {@hide} 4374 */ 4375 @ViewDebug.ExportedProperty(category = "layout") 4376 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4377 protected int mLeft; 4378 /** 4379 * The distance in pixels from the left edge of this view's parent 4380 * to the right edge of this view. 4381 * {@hide} 4382 */ 4383 @ViewDebug.ExportedProperty(category = "layout") 4384 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4385 protected int mRight; 4386 /** 4387 * The distance in pixels from the top edge of this view's parent 4388 * to the top edge of this view. 4389 * {@hide} 4390 */ 4391 @ViewDebug.ExportedProperty(category = "layout") 4392 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4393 protected int mTop; 4394 /** 4395 * The distance in pixels from the top edge of this view's parent 4396 * to the bottom edge of this view. 4397 * {@hide} 4398 */ 4399 @ViewDebug.ExportedProperty(category = "layout") 4400 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4401 protected int mBottom; 4402 4403 /** 4404 * The offset, in pixels, by which the content of this view is scrolled 4405 * horizontally. 4406 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4407 * accessing these directly. 4408 * {@hide} 4409 */ 4410 @ViewDebug.ExportedProperty(category = "scrolling") 4411 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4412 protected int mScrollX; 4413 /** 4414 * The offset, in pixels, by which the content of this view is scrolled 4415 * vertically. 4416 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4417 * accessing these directly. 4418 * {@hide} 4419 */ 4420 @ViewDebug.ExportedProperty(category = "scrolling") 4421 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4422 protected int mScrollY; 4423 4424 /** 4425 * The final computed left padding in pixels that is used for drawing. This is the distance in 4426 * pixels between the left edge of this view and the left edge of its content. 4427 * {@hide} 4428 */ 4429 @ViewDebug.ExportedProperty(category = "padding") 4430 @UnsupportedAppUsage 4431 protected int mPaddingLeft = 0; 4432 /** 4433 * The final computed right padding in pixels that is used for drawing. This is the distance in 4434 * pixels between the right edge of this view and the right edge of its content. 4435 * {@hide} 4436 */ 4437 @ViewDebug.ExportedProperty(category = "padding") 4438 @UnsupportedAppUsage 4439 protected int mPaddingRight = 0; 4440 /** 4441 * The final computed top padding in pixels that is used for drawing. This is the distance in 4442 * pixels between the top edge of this view and the top edge of its content. 4443 * {@hide} 4444 */ 4445 @ViewDebug.ExportedProperty(category = "padding") 4446 @UnsupportedAppUsage 4447 protected int mPaddingTop; 4448 /** 4449 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4450 * pixels between the bottom edge of this view and the bottom edge of its content. 4451 * {@hide} 4452 */ 4453 @ViewDebug.ExportedProperty(category = "padding") 4454 @UnsupportedAppUsage 4455 protected int mPaddingBottom; 4456 4457 /** 4458 * The layout insets in pixels, that is the distance in pixels between the 4459 * visible edges of this view its bounds. 4460 */ 4461 private Insets mLayoutInsets; 4462 4463 /** 4464 * Briefly describes the state of the view and is primarily used for accessibility support. 4465 */ 4466 private CharSequence mStateDescription; 4467 4468 /** 4469 * Briefly describes the view and is primarily used for accessibility support. 4470 */ 4471 private CharSequence mContentDescription; 4472 4473 /** 4474 * If this view represents a distinct part of the window, it can have a title that labels the 4475 * area. 4476 */ 4477 private CharSequence mAccessibilityPaneTitle; 4478 4479 /** 4480 * Specifies the id of a view for which this view serves as a label for 4481 * accessibility purposes. 4482 */ 4483 private int mLabelForId = View.NO_ID; 4484 4485 /** 4486 * Predicate for matching labeled view id with its label for 4487 * accessibility purposes. 4488 */ 4489 private MatchLabelForPredicate mMatchLabelForPredicate; 4490 4491 /** 4492 * Specifies a view before which this one is visited in accessibility traversal. 4493 */ 4494 private int mAccessibilityTraversalBeforeId = NO_ID; 4495 4496 /** 4497 * Specifies a view after which this one is visited in accessibility traversal. 4498 */ 4499 private int mAccessibilityTraversalAfterId = NO_ID; 4500 4501 /** 4502 * Predicate for matching a view by its id. 4503 */ 4504 private MatchIdPredicate mMatchIdPredicate; 4505 4506 /** 4507 * The right padding after RTL resolution, but before taking account of scroll bars. 4508 * 4509 * @hide 4510 */ 4511 @ViewDebug.ExportedProperty(category = "padding") 4512 protected int mUserPaddingRight; 4513 4514 /** 4515 * The resolved bottom padding before taking account of scroll bars. 4516 * 4517 * @hide 4518 */ 4519 @ViewDebug.ExportedProperty(category = "padding") 4520 protected int mUserPaddingBottom; 4521 4522 /** 4523 * The left padding after RTL resolution, but before taking account of scroll bars. 4524 * 4525 * @hide 4526 */ 4527 @ViewDebug.ExportedProperty(category = "padding") 4528 protected int mUserPaddingLeft; 4529 4530 /** 4531 * Cache the paddingStart set by the user to append to the scrollbar's size. 4532 * 4533 */ 4534 @ViewDebug.ExportedProperty(category = "padding") 4535 int mUserPaddingStart; 4536 4537 /** 4538 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4539 * 4540 */ 4541 @ViewDebug.ExportedProperty(category = "padding") 4542 int mUserPaddingEnd; 4543 4544 /** 4545 * The left padding as set by a setter method, a background's padding, or via XML property 4546 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4547 * 4548 * @hide 4549 */ 4550 int mUserPaddingLeftInitial; 4551 4552 /** 4553 * The right padding as set by a setter method, a background's padding, or via XML property 4554 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4555 * 4556 * @hide 4557 */ 4558 int mUserPaddingRightInitial; 4559 4560 /** 4561 * Default undefined padding 4562 */ 4563 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4564 4565 /** 4566 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4567 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4568 */ 4569 private boolean mLeftPaddingDefined = false; 4570 4571 /** 4572 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4573 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4574 */ 4575 private boolean mRightPaddingDefined = false; 4576 4577 /** 4578 * @hide 4579 */ 4580 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4581 /** 4582 * @hide 4583 */ 4584 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4585 4586 private LongSparseLongArray mMeasureCache; 4587 4588 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4589 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4590 private Drawable mBackground; 4591 private TintInfo mBackgroundTint; 4592 4593 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4594 private ForegroundInfo mForegroundInfo; 4595 4596 private Drawable mScrollIndicatorDrawable; 4597 4598 /** 4599 * RenderNode used for backgrounds. 4600 * <p> 4601 * When non-null and valid, this is expected to contain an up-to-date copy 4602 * of the background drawable. It is cleared on temporary detach, and reset 4603 * on cleanup. 4604 * @hide 4605 */ 4606 RenderNode mBackgroundRenderNode; 4607 4608 @UnsupportedAppUsage 4609 private int mBackgroundResource; 4610 private boolean mBackgroundSizeChanged; 4611 4612 /** The default focus highlight. 4613 * @see #mDefaultFocusHighlightEnabled 4614 * @see Drawable#hasFocusStateSpecified() 4615 */ 4616 private Drawable mDefaultFocusHighlight; 4617 private Drawable mDefaultFocusHighlightCache; 4618 private boolean mDefaultFocusHighlightSizeChanged; 4619 /** 4620 * True if the default focus highlight is needed on the target device. 4621 */ 4622 private static boolean sUseDefaultFocusHighlight; 4623 4624 /** 4625 * True if zero-sized views can be focused. 4626 */ 4627 private static boolean sCanFocusZeroSized; 4628 4629 /** 4630 * Always assign focus if a focusable View is available. 4631 */ 4632 private static boolean sAlwaysAssignFocus; 4633 4634 private String mTransitionName; 4635 4636 static class TintInfo { 4637 ColorStateList mTintList; 4638 BlendMode mBlendMode; 4639 boolean mHasTintMode; 4640 boolean mHasTintList; 4641 } 4642 4643 private static class ForegroundInfo { 4644 private Drawable mDrawable; 4645 private TintInfo mTintInfo; 4646 private int mGravity = Gravity.FILL; 4647 private boolean mInsidePadding = true; 4648 private boolean mBoundsChanged = true; 4649 private final Rect mSelfBounds = new Rect(); 4650 private final Rect mOverlayBounds = new Rect(); 4651 } 4652 4653 static class ListenerInfo { 4654 4655 @UnsupportedAppUsage ListenerInfo()4656 ListenerInfo() { 4657 } 4658 4659 /** 4660 * Listener used to dispatch focus change events. 4661 * This field should be made private, so it is hidden from the SDK. 4662 * {@hide} 4663 */ 4664 @UnsupportedAppUsage 4665 protected OnFocusChangeListener mOnFocusChangeListener; 4666 4667 /** 4668 * Listeners for layout change events. 4669 */ 4670 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4671 4672 protected OnScrollChangeListener mOnScrollChangeListener; 4673 4674 /** 4675 * Listeners for attach events. 4676 */ 4677 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4678 4679 /** 4680 * Listener used to dispatch click events. 4681 * This field should be made private, so it is hidden from the SDK. 4682 * {@hide} 4683 */ 4684 @UnsupportedAppUsage 4685 public OnClickListener mOnClickListener; 4686 4687 /** 4688 * Listener used to dispatch long click events. 4689 * This field should be made private, so it is hidden from the SDK. 4690 * {@hide} 4691 */ 4692 @UnsupportedAppUsage 4693 protected OnLongClickListener mOnLongClickListener; 4694 4695 /** 4696 * Listener used to dispatch context click events. This field should be made private, so it 4697 * is hidden from the SDK. 4698 * {@hide} 4699 */ 4700 protected OnContextClickListener mOnContextClickListener; 4701 4702 /** 4703 * Listener used to build the context menu. 4704 * This field should be made private, so it is hidden from the SDK. 4705 * {@hide} 4706 */ 4707 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4708 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4709 4710 @UnsupportedAppUsage 4711 private OnKeyListener mOnKeyListener; 4712 4713 @UnsupportedAppUsage 4714 private OnTouchListener mOnTouchListener; 4715 4716 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4717 private OnHoverListener mOnHoverListener; 4718 4719 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4720 private OnGenericMotionListener mOnGenericMotionListener; 4721 4722 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4723 private OnDragListener mOnDragListener; 4724 4725 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4726 4727 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4728 4729 OnCapturedPointerListener mOnCapturedPointerListener; 4730 4731 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4732 4733 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 4734 4735 /** 4736 * This lives here since it's only valid for interactive views. This list is null until the 4737 * first use. 4738 */ 4739 private List<Rect> mSystemGestureExclusionRects = null; 4740 4741 /** 4742 * Used to track {@link #mSystemGestureExclusionRects} 4743 */ 4744 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4745 4746 /** 4747 * Allows the application to implement custom scroll capture support. 4748 */ 4749 ScrollCaptureCallback mScrollCaptureCallback; 4750 4751 @Nullable 4752 private OnReceiveContentListener mOnReceiveContentListener; 4753 } 4754 4755 @UnsupportedAppUsage 4756 ListenerInfo mListenerInfo; 4757 4758 private static class TooltipInfo { 4759 /** 4760 * Text to be displayed in a tooltip popup. 4761 */ 4762 @Nullable 4763 CharSequence mTooltipText; 4764 4765 /** 4766 * View-relative position of the tooltip anchor point. 4767 */ 4768 int mAnchorX; 4769 int mAnchorY; 4770 4771 /** 4772 * The tooltip popup. 4773 */ 4774 @Nullable 4775 TooltipPopup mTooltipPopup; 4776 4777 /** 4778 * Set to true if the tooltip was shown as a result of a long click. 4779 */ 4780 boolean mTooltipFromLongClick; 4781 4782 /** 4783 * Keep these Runnables so that they can be used to reschedule. 4784 */ 4785 Runnable mShowTooltipRunnable; 4786 Runnable mHideTooltipRunnable; 4787 4788 /** 4789 * Hover move is ignored if it is within this distance in pixels from the previous one. 4790 */ 4791 int mHoverSlop; 4792 4793 /** 4794 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4795 * different from the previously stored position. Ignoring insignificant changes 4796 * filters out the jitter which is typical for such input sources as stylus. 4797 * 4798 * @return True if the position has been updated. 4799 */ updateAnchorPos(MotionEvent event)4800 private boolean updateAnchorPos(MotionEvent event) { 4801 final int newAnchorX = (int) event.getX(); 4802 final int newAnchorY = (int) event.getY(); 4803 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4804 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4805 return false; 4806 } 4807 mAnchorX = newAnchorX; 4808 mAnchorY = newAnchorY; 4809 return true; 4810 } 4811 4812 /** 4813 * Clear the anchor position to ensure that the next change is considered significant. 4814 */ clearAnchorPos()4815 private void clearAnchorPos() { 4816 mAnchorX = Integer.MAX_VALUE; 4817 mAnchorY = Integer.MAX_VALUE; 4818 } 4819 } 4820 4821 TooltipInfo mTooltipInfo; 4822 4823 // Temporary values used to hold (x,y) coordinates when delegating from the 4824 // two-arg performLongClick() method to the legacy no-arg version. 4825 private float mLongClickX = Float.NaN; 4826 private float mLongClickY = Float.NaN; 4827 4828 /** 4829 * The application environment this view lives in. 4830 * This field should be made private, so it is hidden from the SDK. 4831 * {@hide} 4832 */ 4833 @ViewDebug.ExportedProperty(deepExport = true) 4834 @UnsupportedAppUsage 4835 @UiContext 4836 protected Context mContext; 4837 4838 @UnsupportedAppUsage 4839 private final Resources mResources; 4840 4841 @UnsupportedAppUsage 4842 private ScrollabilityCache mScrollCache; 4843 4844 private int[] mDrawableState = null; 4845 4846 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4847 4848 /** 4849 * Animator that automatically runs based on state changes. 4850 */ 4851 private StateListAnimator mStateListAnimator; 4852 4853 /** 4854 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4855 * the user may specify which view to go to next. 4856 */ 4857 private int mNextFocusLeftId = View.NO_ID; 4858 4859 /** 4860 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4861 * the user may specify which view to go to next. 4862 */ 4863 private int mNextFocusRightId = View.NO_ID; 4864 4865 /** 4866 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4867 * the user may specify which view to go to next. 4868 */ 4869 private int mNextFocusUpId = View.NO_ID; 4870 4871 /** 4872 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4873 * the user may specify which view to go to next. 4874 */ 4875 private int mNextFocusDownId = View.NO_ID; 4876 4877 /** 4878 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4879 * the user may specify which view to go to next. 4880 */ 4881 int mNextFocusForwardId = View.NO_ID; 4882 4883 /** 4884 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4885 * 4886 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4887 */ 4888 int mNextClusterForwardId = View.NO_ID; 4889 4890 /** 4891 * Whether this View should use a default focus highlight when it gets focused but doesn't 4892 * have {@link android.R.attr#state_focused} defined in its background. 4893 */ 4894 boolean mDefaultFocusHighlightEnabled = true; 4895 4896 private CheckForLongPress mPendingCheckForLongPress; 4897 @UnsupportedAppUsage 4898 private CheckForTap mPendingCheckForTap = null; 4899 private PerformClick mPerformClick; 4900 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4901 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 4902 private UnsetPressedState mUnsetPressedState; 4903 4904 /** 4905 * Whether the long press's action has been invoked. The tap's action is invoked on the 4906 * up event while a long press is invoked as soon as the long press duration is reached, so 4907 * a long press could be performed before the tap is checked, in which case the tap's action 4908 * should not be invoked. 4909 */ 4910 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4911 private boolean mHasPerformedLongPress; 4912 4913 /** 4914 * Whether a context click button is currently pressed down. This is true when the stylus is 4915 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4916 * pressed. This is false once the button is released or if the stylus has been lifted. 4917 */ 4918 private boolean mInContextButtonPress; 4919 4920 /** 4921 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4922 * true after a stylus button press has occured, when the next up event should not be recognized 4923 * as a tap. 4924 */ 4925 private boolean mIgnoreNextUpEvent; 4926 4927 /** 4928 * The minimum height of the view. We'll try our best to have the height 4929 * of this view to at least this amount. 4930 */ 4931 @ViewDebug.ExportedProperty(category = "measurement") 4932 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4933 private int mMinHeight; 4934 4935 /** 4936 * The minimum width of the view. We'll try our best to have the width 4937 * of this view to at least this amount. 4938 */ 4939 @ViewDebug.ExportedProperty(category = "measurement") 4940 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4941 private int mMinWidth; 4942 4943 /** 4944 * The delegate to handle touch events that are physically in this view 4945 * but should be handled by another view. 4946 */ 4947 private TouchDelegate mTouchDelegate = null; 4948 4949 /** 4950 * While touch exploration is in use, set to true when hovering across boundaries and 4951 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 4952 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 4953 * {@link MotionEvent#ACTION_HOVER_EXIT}. 4954 * Note that children of view group are excluded in the touch area. 4955 * @see #dispatchTouchExplorationHoverEvent 4956 */ 4957 private boolean mHoveringTouchDelegate = false; 4958 4959 /** 4960 * Solid color to use as a background when creating the drawing cache. Enables 4961 * the cache to use 16 bit bitmaps instead of 32 bit. 4962 */ 4963 private int mDrawingCacheBackgroundColor = 0; 4964 4965 /** 4966 * Special tree observer used when mAttachInfo is null. 4967 */ 4968 private ViewTreeObserver mFloatingTreeObserver; 4969 4970 /** 4971 * Cache the touch slop from the context that created the view. 4972 */ 4973 private int mTouchSlop; 4974 4975 /** 4976 * Cache the ambiguous gesture multiplier from the context that created the view. 4977 */ 4978 private float mAmbiguousGestureMultiplier; 4979 4980 /** 4981 * Object that handles automatic animation of view properties. 4982 */ 4983 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4984 private ViewPropertyAnimator mAnimator = null; 4985 4986 /** 4987 * List of registered FrameMetricsObservers. 4988 */ 4989 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4990 4991 /** 4992 * Flag indicating that a drag can cross window boundaries. When 4993 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4994 * with this flag set, all visible applications with targetSdkVersion >= 4995 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4996 * in the drag operation and receive the dragged content. 4997 * 4998 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4999 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 5000 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 5001 */ 5002 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 5003 5004 /** 5005 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5006 * request read access to the content URI(s) contained in the {@link ClipData} object. 5007 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5008 */ 5009 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5010 5011 /** 5012 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5013 * request write access to the content URI(s) contained in the {@link ClipData} object. 5014 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5015 */ 5016 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5017 5018 /** 5019 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5020 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5021 * reboots until explicitly revoked with 5022 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5023 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5024 */ 5025 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5026 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5027 5028 /** 5029 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5030 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5031 * match against the original granted URI. 5032 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5033 */ 5034 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5035 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5036 5037 /** 5038 * Flag indicating that the drag shadow will be opaque. When 5039 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5040 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5041 */ 5042 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5043 5044 /** 5045 * Flag indicating that the drag was initiated with 5046 * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. When 5047 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called, this 5048 * is used by the system to perform a drag without animations. 5049 */ 5050 public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; 5051 5052 /** 5053 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5054 */ 5055 private float mVerticalScrollFactor; 5056 5057 /** 5058 * Position of the vertical scroll bar. 5059 */ 5060 @UnsupportedAppUsage 5061 private int mVerticalScrollbarPosition; 5062 5063 /** 5064 * Position the scroll bar at the default position as determined by the system. 5065 */ 5066 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5067 5068 /** 5069 * Position the scroll bar along the left edge. 5070 */ 5071 public static final int SCROLLBAR_POSITION_LEFT = 1; 5072 5073 /** 5074 * Position the scroll bar along the right edge. 5075 */ 5076 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5077 5078 /** 5079 * Indicates that the view does not have a layer. 5080 * 5081 * @see #getLayerType() 5082 * @see #setLayerType(int, android.graphics.Paint) 5083 * @see #LAYER_TYPE_SOFTWARE 5084 * @see #LAYER_TYPE_HARDWARE 5085 */ 5086 public static final int LAYER_TYPE_NONE = 0; 5087 5088 /** 5089 * <p>Indicates that the view has a software layer. A software layer is backed 5090 * by a bitmap and causes the view to be rendered using Android's software 5091 * rendering pipeline, even if hardware acceleration is enabled.</p> 5092 * 5093 * <p>Software layers have various usages:</p> 5094 * <p>When the application is not using hardware acceleration, a software layer 5095 * is useful to apply a specific color filter and/or blending mode and/or 5096 * translucency to a view and all its children.</p> 5097 * <p>When the application is using hardware acceleration, a software layer 5098 * is useful to render drawing primitives not supported by the hardware 5099 * accelerated pipeline. It can also be used to cache a complex view tree 5100 * into a texture and reduce the complexity of drawing operations. For instance, 5101 * when animating a complex view tree with a translation, a software layer can 5102 * be used to render the view tree only once.</p> 5103 * <p>Software layers should be avoided when the affected view tree updates 5104 * often. Every update will require to re-render the software layer, which can 5105 * potentially be slow (particularly when hardware acceleration is turned on 5106 * since the layer will have to be uploaded into a hardware texture after every 5107 * update.)</p> 5108 * 5109 * @see #getLayerType() 5110 * @see #setLayerType(int, android.graphics.Paint) 5111 * @see #LAYER_TYPE_NONE 5112 * @see #LAYER_TYPE_HARDWARE 5113 */ 5114 public static final int LAYER_TYPE_SOFTWARE = 1; 5115 5116 /** 5117 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5118 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5119 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5120 * rendering pipeline, but only if hardware acceleration is turned on for the 5121 * view hierarchy. When hardware acceleration is turned off, hardware layers 5122 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5123 * 5124 * <p>A hardware layer is useful to apply a specific color filter and/or 5125 * blending mode and/or translucency to a view and all its children.</p> 5126 * <p>A hardware layer can be used to cache a complex view tree into a 5127 * texture and reduce the complexity of drawing operations. For instance, 5128 * when animating a complex view tree with a translation, a hardware layer can 5129 * be used to render the view tree only once.</p> 5130 * <p>A hardware layer can also be used to increase the rendering quality when 5131 * rotation transformations are applied on a view. It can also be used to 5132 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5133 * 5134 * @see #getLayerType() 5135 * @see #setLayerType(int, android.graphics.Paint) 5136 * @see #LAYER_TYPE_NONE 5137 * @see #LAYER_TYPE_SOFTWARE 5138 */ 5139 public static final int LAYER_TYPE_HARDWARE = 2; 5140 5141 /** @hide */ 5142 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5143 LAYER_TYPE_NONE, 5144 LAYER_TYPE_SOFTWARE, 5145 LAYER_TYPE_HARDWARE 5146 }) 5147 @Retention(RetentionPolicy.SOURCE) 5148 public @interface LayerType {} 5149 5150 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 5151 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 5152 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 5153 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 5154 }) 5155 int mLayerType = LAYER_TYPE_NONE; 5156 Paint mLayerPaint; 5157 5158 /** 5159 * Set to true when drawing cache is enabled and cannot be created. 5160 * 5161 * @hide 5162 */ 5163 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5164 public boolean mCachingFailed; 5165 @UnsupportedAppUsage 5166 private Bitmap mDrawingCache; 5167 @UnsupportedAppUsage 5168 private Bitmap mUnscaledDrawingCache; 5169 5170 /** 5171 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5172 * <p> 5173 * When non-null and valid, this is expected to contain an up-to-date copy 5174 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5175 * cleanup. 5176 */ 5177 @UnsupportedAppUsage 5178 final RenderNode mRenderNode; 5179 5180 /** 5181 * Set to true when the view is sending hover accessibility events because it 5182 * is the innermost hovered view. 5183 */ 5184 private boolean mSendingHoverAccessibilityEvents; 5185 5186 /** 5187 * Delegate for injecting accessibility functionality. 5188 */ 5189 @UnsupportedAppUsage 5190 AccessibilityDelegate mAccessibilityDelegate; 5191 5192 /** 5193 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5194 * and add/remove objects to/from the overlay directly through the Overlay methods. 5195 */ 5196 ViewOverlay mOverlay; 5197 5198 /** 5199 * The currently active parent view for receiving delegated nested scrolling events. 5200 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5201 * by {@link #stopNestedScroll()} at the same point where we clear 5202 * requestDisallowInterceptTouchEvent. 5203 */ 5204 private ViewParent mNestedScrollingParent; 5205 5206 /** 5207 * Consistency verifier for debugging purposes. 5208 * @hide 5209 */ 5210 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5211 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5212 new InputEventConsistencyVerifier(this, 0) : null; 5213 5214 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5215 5216 private int[] mTempNestedScrollConsumed; 5217 5218 /** 5219 * An overlay is going to draw this View instead of being drawn as part of this 5220 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5221 * when this view is invalidated. 5222 */ 5223 GhostView mGhostView; 5224 5225 /** 5226 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5227 * @hide 5228 */ 5229 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5230 public String[] mAttributes; 5231 5232 /** 5233 * Maps a Resource id to its name. 5234 */ 5235 private static SparseArray<String> mAttributeMap; 5236 5237 /** 5238 * Queue of pending runnables. Used to postpone calls to post() until this 5239 * view is attached and has a handler. 5240 */ 5241 private HandlerActionQueue mRunQueue; 5242 5243 /** 5244 * The pointer icon when the mouse hovers on this view. The default is null. 5245 */ 5246 private PointerIcon mPointerIcon; 5247 5248 /** 5249 * @hide 5250 */ 5251 @UnsupportedAppUsage 5252 String mStartActivityRequestWho; 5253 5254 @Nullable 5255 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5256 5257 /** Used to delay visibility updates sent to the autofill manager */ 5258 private Handler mVisibilityChangeForAutofillHandler; 5259 5260 /** 5261 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5262 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5263 */ 5264 @Nullable 5265 private ContentCaptureSession mContentCaptureSession; 5266 5267 /** 5268 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5269 */ 5270 private boolean mContentCaptureSessionCached; 5271 5272 @LayoutRes 5273 private int mSourceLayoutId = ID_NULL; 5274 5275 @Nullable 5276 private SparseIntArray mAttributeSourceResId; 5277 5278 @Nullable 5279 private SparseArray<int[]> mAttributeResolutionStacks; 5280 5281 @StyleRes 5282 private int mExplicitStyle; 5283 5284 /** 5285 * Specifies which input source classes should provide unbuffered input events to this view 5286 * 5287 * @see View#requestUnbufferedDispatch(int) 5288 */ 5289 @InputSourceClass 5290 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5291 5292 @Nullable 5293 private String[] mReceiveContentMimeTypes; 5294 5295 @Nullable 5296 private ViewTranslationCallback mViewTranslationCallback; 5297 5298 @Nullable 5299 5300 private ViewTranslationResponse mViewTranslationResponse; 5301 5302 /** 5303 * Simple constructor to use when creating a view from code. 5304 * 5305 * @param context The Context the view is running in, through which it can 5306 * access the current theme, resources, etc. 5307 */ View(Context context)5308 public View(Context context) { 5309 mContext = context; 5310 mResources = context != null ? context.getResources() : null; 5311 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5312 // Set some flags defaults 5313 mPrivateFlags2 = 5314 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5315 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5316 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5317 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5318 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5319 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5320 5321 final ViewConfiguration configuration = ViewConfiguration.get(context); 5322 mTouchSlop = configuration.getScaledTouchSlop(); 5323 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5324 5325 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5326 mUserPaddingStart = UNDEFINED_PADDING; 5327 mUserPaddingEnd = UNDEFINED_PADDING; 5328 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5329 5330 if (!sCompatibilityDone && context != null) { 5331 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5332 5333 // Older apps may need this compatibility hack for measurement. 5334 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5335 5336 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5337 // of whether a layout was requested on that View. 5338 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 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 = targetSdkVersion < Build.VERSION_CODES.R; 5379 5380 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5381 5382 GradientDrawable.sWrapNegativeAngleMeasurements = 5383 targetSdkVersion >= Build.VERSION_CODES.Q; 5384 5385 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5386 5387 sCompatibilityDone = true; 5388 } 5389 } 5390 5391 /** 5392 * Constructor that is called when inflating a view from XML. This is called 5393 * when a view is being constructed from an XML file, supplying attributes 5394 * that were specified in the XML file. This version uses a default style of 5395 * 0, so the only attribute values applied are those in the Context's Theme 5396 * and the given AttributeSet. 5397 * 5398 * <p> 5399 * The method onFinishInflate() will be called after all children have been 5400 * added. 5401 * 5402 * @param context The Context the view is running in, through which it can 5403 * access the current theme, resources, etc. 5404 * @param attrs The attributes of the XML tag that is inflating the view. 5405 * @see #View(Context, AttributeSet, int) 5406 */ 5407 public View(Context context, @Nullable AttributeSet attrs) { 5408 this(context, attrs, 0); 5409 } 5410 5411 /** 5412 * Perform inflation from XML and apply a class-specific base style from a 5413 * theme attribute. This constructor of View allows subclasses to use their 5414 * own base style when they are inflating. For example, a Button class's 5415 * constructor would call this version of the super class constructor and 5416 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5417 * allows the theme's button style to modify all of the base view attributes 5418 * (in particular its background) as well as the Button class's attributes. 5419 * 5420 * @param context The Context the view is running in, through which it can 5421 * access the current theme, resources, etc. 5422 * @param attrs The attributes of the XML tag that is inflating the view. 5423 * @param defStyleAttr An attribute in the current theme that contains a 5424 * reference to a style resource that supplies default values for 5425 * the view. Can be 0 to not look for defaults. 5426 * @see #View(Context, AttributeSet) 5427 */ 5428 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5429 this(context, attrs, defStyleAttr, 0); 5430 } 5431 5432 /** 5433 * Perform inflation from XML and apply a class-specific base style from a 5434 * theme attribute or style resource. This constructor of View allows 5435 * subclasses to use their own base style when they are inflating. 5436 * <p> 5437 * When determining the final value of a particular attribute, there are 5438 * four inputs that come into play: 5439 * <ol> 5440 * <li>Any attribute values in the given AttributeSet. 5441 * <li>The style resource specified in the AttributeSet (named "style"). 5442 * <li>The default style specified by <var>defStyleAttr</var>. 5443 * <li>The default style specified by <var>defStyleRes</var>. 5444 * <li>The base values in this theme. 5445 * </ol> 5446 * <p> 5447 * Each of these inputs is considered in-order, with the first listed taking 5448 * precedence over the following ones. In other words, if in the 5449 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5450 * , then the button's text will <em>always</em> be black, regardless of 5451 * what is specified in any of the styles. 5452 * 5453 * @param context The Context the view is running in, through which it can 5454 * access the current theme, resources, etc. 5455 * @param attrs The attributes of the XML tag that is inflating the view. 5456 * @param defStyleAttr An attribute in the current theme that contains a 5457 * reference to a style resource that supplies default values for 5458 * the view. Can be 0 to not look for defaults. 5459 * @param defStyleRes A resource identifier of a style resource that 5460 * supplies default values for the view, used only if 5461 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5462 * to not look for defaults. 5463 * @see #View(Context, AttributeSet, int) 5464 */ 5465 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5466 this(context); 5467 5468 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5469 5470 final TypedArray a = context.obtainStyledAttributes( 5471 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5472 5473 retrieveExplicitStyle(context.getTheme(), attrs); 5474 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5475 defStyleAttr, defStyleRes); 5476 5477 if (sDebugViewAttributes) { 5478 saveAttributeData(attrs, a); 5479 } 5480 5481 Drawable background = null; 5482 5483 int leftPadding = -1; 5484 int topPadding = -1; 5485 int rightPadding = -1; 5486 int bottomPadding = -1; 5487 int startPadding = UNDEFINED_PADDING; 5488 int endPadding = UNDEFINED_PADDING; 5489 5490 int padding = -1; 5491 int paddingHorizontal = -1; 5492 int paddingVertical = -1; 5493 5494 int viewFlagValues = 0; 5495 int viewFlagMasks = 0; 5496 5497 boolean setScrollContainer = false; 5498 5499 int x = 0; 5500 int y = 0; 5501 5502 float tx = 0; 5503 float ty = 0; 5504 float tz = 0; 5505 float elevation = 0; 5506 float rotation = 0; 5507 float rotationX = 0; 5508 float rotationY = 0; 5509 float sx = 1f; 5510 float sy = 1f; 5511 boolean transformSet = false; 5512 5513 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5514 int overScrollMode = mOverScrollMode; 5515 boolean initializeScrollbars = false; 5516 boolean initializeScrollIndicators = false; 5517 5518 boolean startPaddingDefined = false; 5519 boolean endPaddingDefined = false; 5520 boolean leftPaddingDefined = false; 5521 boolean rightPaddingDefined = false; 5522 5523 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5524 5525 // Set default values. 5526 viewFlagValues |= FOCUSABLE_AUTO; 5527 viewFlagMasks |= FOCUSABLE_AUTO; 5528 5529 final int N = a.getIndexCount(); 5530 for (int i = 0; i < N; i++) { 5531 int attr = a.getIndex(i); 5532 switch (attr) { 5533 case com.android.internal.R.styleable.View_background: 5534 background = a.getDrawable(attr); 5535 break; 5536 case com.android.internal.R.styleable.View_padding: 5537 padding = a.getDimensionPixelSize(attr, -1); 5538 mUserPaddingLeftInitial = padding; 5539 mUserPaddingRightInitial = padding; 5540 leftPaddingDefined = true; 5541 rightPaddingDefined = true; 5542 break; 5543 case com.android.internal.R.styleable.View_paddingHorizontal: 5544 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5545 mUserPaddingLeftInitial = paddingHorizontal; 5546 mUserPaddingRightInitial = paddingHorizontal; 5547 leftPaddingDefined = true; 5548 rightPaddingDefined = true; 5549 break; 5550 case com.android.internal.R.styleable.View_paddingVertical: 5551 paddingVertical = a.getDimensionPixelSize(attr, -1); 5552 break; 5553 case com.android.internal.R.styleable.View_paddingLeft: 5554 leftPadding = a.getDimensionPixelSize(attr, -1); 5555 mUserPaddingLeftInitial = leftPadding; 5556 leftPaddingDefined = true; 5557 break; 5558 case com.android.internal.R.styleable.View_paddingTop: 5559 topPadding = a.getDimensionPixelSize(attr, -1); 5560 break; 5561 case com.android.internal.R.styleable.View_paddingRight: 5562 rightPadding = a.getDimensionPixelSize(attr, -1); 5563 mUserPaddingRightInitial = rightPadding; 5564 rightPaddingDefined = true; 5565 break; 5566 case com.android.internal.R.styleable.View_paddingBottom: 5567 bottomPadding = a.getDimensionPixelSize(attr, -1); 5568 break; 5569 case com.android.internal.R.styleable.View_paddingStart: 5570 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5571 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5572 break; 5573 case com.android.internal.R.styleable.View_paddingEnd: 5574 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5575 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5576 break; 5577 case com.android.internal.R.styleable.View_scrollX: 5578 x = a.getDimensionPixelOffset(attr, 0); 5579 break; 5580 case com.android.internal.R.styleable.View_scrollY: 5581 y = a.getDimensionPixelOffset(attr, 0); 5582 break; 5583 case com.android.internal.R.styleable.View_alpha: 5584 setAlpha(a.getFloat(attr, 1f)); 5585 break; 5586 case com.android.internal.R.styleable.View_transformPivotX: 5587 setPivotX(a.getDimension(attr, 0)); 5588 break; 5589 case com.android.internal.R.styleable.View_transformPivotY: 5590 setPivotY(a.getDimension(attr, 0)); 5591 break; 5592 case com.android.internal.R.styleable.View_translationX: 5593 tx = a.getDimension(attr, 0); 5594 transformSet = true; 5595 break; 5596 case com.android.internal.R.styleable.View_translationY: 5597 ty = a.getDimension(attr, 0); 5598 transformSet = true; 5599 break; 5600 case com.android.internal.R.styleable.View_translationZ: 5601 tz = a.getDimension(attr, 0); 5602 transformSet = true; 5603 break; 5604 case com.android.internal.R.styleable.View_elevation: 5605 elevation = a.getDimension(attr, 0); 5606 transformSet = true; 5607 break; 5608 case com.android.internal.R.styleable.View_rotation: 5609 rotation = a.getFloat(attr, 0); 5610 transformSet = true; 5611 break; 5612 case com.android.internal.R.styleable.View_rotationX: 5613 rotationX = a.getFloat(attr, 0); 5614 transformSet = true; 5615 break; 5616 case com.android.internal.R.styleable.View_rotationY: 5617 rotationY = a.getFloat(attr, 0); 5618 transformSet = true; 5619 break; 5620 case com.android.internal.R.styleable.View_scaleX: 5621 sx = a.getFloat(attr, 1f); 5622 transformSet = true; 5623 break; 5624 case com.android.internal.R.styleable.View_scaleY: 5625 sy = a.getFloat(attr, 1f); 5626 transformSet = true; 5627 break; 5628 case com.android.internal.R.styleable.View_id: 5629 mID = a.getResourceId(attr, NO_ID); 5630 break; 5631 case com.android.internal.R.styleable.View_tag: 5632 mTag = a.getText(attr); 5633 break; 5634 case com.android.internal.R.styleable.View_fitsSystemWindows: 5635 if (a.getBoolean(attr, false)) { 5636 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5637 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5638 } 5639 break; 5640 case com.android.internal.R.styleable.View_focusable: 5641 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5642 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5643 viewFlagMasks |= FOCUSABLE_MASK; 5644 } 5645 break; 5646 case com.android.internal.R.styleable.View_focusableInTouchMode: 5647 if (a.getBoolean(attr, false)) { 5648 // unset auto focus since focusableInTouchMode implies explicit focusable 5649 viewFlagValues &= ~FOCUSABLE_AUTO; 5650 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5651 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5652 } 5653 break; 5654 case com.android.internal.R.styleable.View_clickable: 5655 if (a.getBoolean(attr, false)) { 5656 viewFlagValues |= CLICKABLE; 5657 viewFlagMasks |= CLICKABLE; 5658 } 5659 break; 5660 case com.android.internal.R.styleable.View_allowClickWhenDisabled: 5661 setAllowClickWhenDisabled(a.getBoolean(attr, false)); 5662 break; 5663 case com.android.internal.R.styleable.View_longClickable: 5664 if (a.getBoolean(attr, false)) { 5665 viewFlagValues |= LONG_CLICKABLE; 5666 viewFlagMasks |= LONG_CLICKABLE; 5667 } 5668 break; 5669 case com.android.internal.R.styleable.View_contextClickable: 5670 if (a.getBoolean(attr, false)) { 5671 viewFlagValues |= CONTEXT_CLICKABLE; 5672 viewFlagMasks |= CONTEXT_CLICKABLE; 5673 } 5674 break; 5675 case com.android.internal.R.styleable.View_saveEnabled: 5676 if (!a.getBoolean(attr, true)) { 5677 viewFlagValues |= SAVE_DISABLED; 5678 viewFlagMasks |= SAVE_DISABLED_MASK; 5679 } 5680 break; 5681 case com.android.internal.R.styleable.View_duplicateParentState: 5682 if (a.getBoolean(attr, false)) { 5683 viewFlagValues |= DUPLICATE_PARENT_STATE; 5684 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5685 } 5686 break; 5687 case com.android.internal.R.styleable.View_visibility: 5688 final int visibility = a.getInt(attr, 0); 5689 if (visibility != 0) { 5690 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5691 viewFlagMasks |= VISIBILITY_MASK; 5692 } 5693 break; 5694 case com.android.internal.R.styleable.View_layoutDirection: 5695 // Clear any layout direction flags (included resolved bits) already set 5696 mPrivateFlags2 &= 5697 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5698 // Set the layout direction flags depending on the value of the attribute 5699 final int layoutDirection = a.getInt(attr, -1); 5700 final int value = (layoutDirection != -1) ? 5701 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5702 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5703 break; 5704 case com.android.internal.R.styleable.View_drawingCacheQuality: 5705 final int cacheQuality = a.getInt(attr, 0); 5706 if (cacheQuality != 0) { 5707 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5708 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5709 } 5710 break; 5711 case com.android.internal.R.styleable.View_contentDescription: 5712 setContentDescription(a.getString(attr)); 5713 break; 5714 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5715 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5716 break; 5717 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5718 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5719 break; 5720 case com.android.internal.R.styleable.View_labelFor: 5721 setLabelFor(a.getResourceId(attr, NO_ID)); 5722 break; 5723 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5724 if (!a.getBoolean(attr, true)) { 5725 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5726 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5727 } 5728 break; 5729 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5730 if (!a.getBoolean(attr, true)) { 5731 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5732 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5733 } 5734 break; 5735 case R.styleable.View_scrollbars: 5736 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5737 if (scrollbars != SCROLLBARS_NONE) { 5738 viewFlagValues |= scrollbars; 5739 viewFlagMasks |= SCROLLBARS_MASK; 5740 initializeScrollbars = true; 5741 } 5742 break; 5743 //noinspection deprecation 5744 case R.styleable.View_fadingEdge: 5745 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5746 // Ignore the attribute starting with ICS 5747 break; 5748 } 5749 // With builds < ICS, fall through and apply fading edges 5750 case R.styleable.View_requiresFadingEdge: 5751 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5752 if (fadingEdge != FADING_EDGE_NONE) { 5753 viewFlagValues |= fadingEdge; 5754 viewFlagMasks |= FADING_EDGE_MASK; 5755 initializeFadingEdgeInternal(a); 5756 } 5757 break; 5758 case R.styleable.View_scrollbarStyle: 5759 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5760 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5761 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5762 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5763 } 5764 break; 5765 case R.styleable.View_isScrollContainer: 5766 setScrollContainer = true; 5767 if (a.getBoolean(attr, false)) { 5768 setScrollContainer(true); 5769 } 5770 break; 5771 case com.android.internal.R.styleable.View_keepScreenOn: 5772 if (a.getBoolean(attr, false)) { 5773 viewFlagValues |= KEEP_SCREEN_ON; 5774 viewFlagMasks |= KEEP_SCREEN_ON; 5775 } 5776 break; 5777 case R.styleable.View_filterTouchesWhenObscured: 5778 if (a.getBoolean(attr, false)) { 5779 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5780 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5781 } 5782 break; 5783 case R.styleable.View_nextFocusLeft: 5784 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5785 break; 5786 case R.styleable.View_nextFocusRight: 5787 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5788 break; 5789 case R.styleable.View_nextFocusUp: 5790 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5791 break; 5792 case R.styleable.View_nextFocusDown: 5793 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5794 break; 5795 case R.styleable.View_nextFocusForward: 5796 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5797 break; 5798 case R.styleable.View_nextClusterForward: 5799 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5800 break; 5801 case R.styleable.View_minWidth: 5802 mMinWidth = a.getDimensionPixelSize(attr, 0); 5803 break; 5804 case R.styleable.View_minHeight: 5805 mMinHeight = a.getDimensionPixelSize(attr, 0); 5806 break; 5807 case R.styleable.View_onClick: 5808 if (context.isRestricted()) { 5809 throw new IllegalStateException("The android:onClick attribute cannot " 5810 + "be used within a restricted context"); 5811 } 5812 5813 final String handlerName = a.getString(attr); 5814 if (handlerName != null) { 5815 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5816 } 5817 break; 5818 case R.styleable.View_overScrollMode: 5819 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5820 break; 5821 case R.styleable.View_verticalScrollbarPosition: 5822 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5823 break; 5824 case R.styleable.View_layerType: 5825 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5826 break; 5827 case R.styleable.View_textDirection: 5828 // Clear any text direction flag already set 5829 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5830 // Set the text direction flags depending on the value of the attribute 5831 final int textDirection = a.getInt(attr, -1); 5832 if (textDirection != -1) { 5833 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5834 } 5835 break; 5836 case R.styleable.View_textAlignment: 5837 // Clear any text alignment flag already set 5838 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5839 // Set the text alignment flag depending on the value of the attribute 5840 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5841 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5842 break; 5843 case R.styleable.View_importantForAccessibility: 5844 setImportantForAccessibility(a.getInt(attr, 5845 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5846 break; 5847 case R.styleable.View_accessibilityLiveRegion: 5848 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5849 break; 5850 case R.styleable.View_transitionName: 5851 setTransitionName(a.getString(attr)); 5852 break; 5853 case R.styleable.View_nestedScrollingEnabled: 5854 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5855 break; 5856 case R.styleable.View_stateListAnimator: 5857 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5858 a.getResourceId(attr, 0))); 5859 break; 5860 case R.styleable.View_backgroundTint: 5861 // This will get applied later during setBackground(). 5862 if (mBackgroundTint == null) { 5863 mBackgroundTint = new TintInfo(); 5864 } 5865 mBackgroundTint.mTintList = a.getColorStateList( 5866 R.styleable.View_backgroundTint); 5867 mBackgroundTint.mHasTintList = true; 5868 break; 5869 case R.styleable.View_backgroundTintMode: 5870 // This will get applied later during setBackground(). 5871 if (mBackgroundTint == null) { 5872 mBackgroundTint = new TintInfo(); 5873 } 5874 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 5875 R.styleable.View_backgroundTintMode, -1), null); 5876 mBackgroundTint.mHasTintMode = true; 5877 break; 5878 case R.styleable.View_outlineProvider: 5879 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5880 PROVIDER_BACKGROUND)); 5881 break; 5882 case R.styleable.View_foreground: 5883 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5884 setForeground(a.getDrawable(attr)); 5885 } 5886 break; 5887 case R.styleable.View_foregroundGravity: 5888 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5889 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5890 } 5891 break; 5892 case R.styleable.View_foregroundTintMode: 5893 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5894 setForegroundTintBlendMode( 5895 Drawable.parseBlendMode(a.getInt(attr, -1), 5896 null)); 5897 } 5898 break; 5899 case R.styleable.View_foregroundTint: 5900 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5901 setForegroundTintList(a.getColorStateList(attr)); 5902 } 5903 break; 5904 case R.styleable.View_foregroundInsidePadding: 5905 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5906 if (mForegroundInfo == null) { 5907 mForegroundInfo = new ForegroundInfo(); 5908 } 5909 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5910 mForegroundInfo.mInsidePadding); 5911 } 5912 break; 5913 case R.styleable.View_scrollIndicators: 5914 final int scrollIndicators = 5915 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5916 & SCROLL_INDICATORS_PFLAG3_MASK; 5917 if (scrollIndicators != 0) { 5918 mPrivateFlags3 |= scrollIndicators; 5919 initializeScrollIndicators = true; 5920 } 5921 break; 5922 case R.styleable.View_pointerIcon: 5923 final int resourceId = a.getResourceId(attr, 0); 5924 if (resourceId != 0) { 5925 setPointerIcon(PointerIcon.load( 5926 context.getResources(), resourceId)); 5927 } else { 5928 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5929 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5930 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5931 } 5932 } 5933 break; 5934 case R.styleable.View_forceHasOverlappingRendering: 5935 if (a.peekValue(attr) != null) { 5936 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5937 } 5938 break; 5939 case R.styleable.View_tooltipText: 5940 setTooltipText(a.getText(attr)); 5941 break; 5942 case R.styleable.View_keyboardNavigationCluster: 5943 if (a.peekValue(attr) != null) { 5944 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5945 } 5946 break; 5947 case R.styleable.View_focusedByDefault: 5948 if (a.peekValue(attr) != null) { 5949 setFocusedByDefault(a.getBoolean(attr, true)); 5950 } 5951 break; 5952 case R.styleable.View_autofillHints: 5953 if (a.peekValue(attr) != null) { 5954 CharSequence[] rawHints = null; 5955 String rawString = null; 5956 5957 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5958 int resId = a.getResourceId(attr, 0); 5959 5960 try { 5961 rawHints = a.getTextArray(attr); 5962 } catch (Resources.NotFoundException e) { 5963 rawString = getResources().getString(resId); 5964 } 5965 } else { 5966 rawString = a.getString(attr); 5967 } 5968 5969 if (rawHints == null) { 5970 if (rawString == null) { 5971 throw new IllegalArgumentException( 5972 "Could not resolve autofillHints"); 5973 } else { 5974 rawHints = rawString.split(","); 5975 } 5976 } 5977 5978 String[] hints = new String[rawHints.length]; 5979 5980 int numHints = rawHints.length; 5981 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5982 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5983 } 5984 setAutofillHints(hints); 5985 } 5986 break; 5987 case R.styleable.View_importantForAutofill: 5988 if (a.peekValue(attr) != null) { 5989 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5990 } 5991 break; 5992 case R.styleable.View_importantForContentCapture: 5993 if (a.peekValue(attr) != null) { 5994 setImportantForContentCapture(a.getInt(attr, 5995 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 5996 } 5997 case R.styleable.View_defaultFocusHighlightEnabled: 5998 if (a.peekValue(attr) != null) { 5999 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 6000 } 6001 break; 6002 case R.styleable.View_screenReaderFocusable: 6003 if (a.peekValue(attr) != null) { 6004 setScreenReaderFocusable(a.getBoolean(attr, false)); 6005 } 6006 break; 6007 case R.styleable.View_accessibilityPaneTitle: 6008 if (a.peekValue(attr) != null) { 6009 setAccessibilityPaneTitle(a.getString(attr)); 6010 } 6011 break; 6012 case R.styleable.View_outlineSpotShadowColor: 6013 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6014 break; 6015 case R.styleable.View_outlineAmbientShadowColor: 6016 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6017 break; 6018 case com.android.internal.R.styleable.View_accessibilityHeading: 6019 setAccessibilityHeading(a.getBoolean(attr, false)); 6020 break; 6021 case R.styleable.View_forceDarkAllowed: 6022 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6023 break; 6024 case R.styleable.View_scrollCaptureHint: 6025 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6026 break; 6027 case R.styleable.View_clipToOutline: 6028 setClipToOutline(a.getBoolean(attr, false)); 6029 break; 6030 } 6031 } 6032 6033 setOverScrollMode(overScrollMode); 6034 6035 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6036 // the resolved layout direction). Those cached values will be used later during padding 6037 // resolution. 6038 mUserPaddingStart = startPadding; 6039 mUserPaddingEnd = endPadding; 6040 6041 if (background != null) { 6042 setBackground(background); 6043 } 6044 6045 // setBackground above will record that padding is currently provided by the background. 6046 // If we have padding specified via xml, record that here instead and use it. 6047 mLeftPaddingDefined = leftPaddingDefined; 6048 mRightPaddingDefined = rightPaddingDefined; 6049 6050 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6051 // bottomPadding, and padding set by background. Valid padding beats everything. 6052 if (padding >= 0) { 6053 leftPadding = padding; 6054 topPadding = padding; 6055 rightPadding = padding; 6056 bottomPadding = padding; 6057 mUserPaddingLeftInitial = padding; 6058 mUserPaddingRightInitial = padding; 6059 } else { 6060 if (paddingHorizontal >= 0) { 6061 leftPadding = paddingHorizontal; 6062 rightPadding = paddingHorizontal; 6063 mUserPaddingLeftInitial = paddingHorizontal; 6064 mUserPaddingRightInitial = paddingHorizontal; 6065 } 6066 if (paddingVertical >= 0) { 6067 topPadding = paddingVertical; 6068 bottomPadding = paddingVertical; 6069 } 6070 } 6071 6072 if (isRtlCompatibilityMode()) { 6073 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6074 // left / right padding are used if defined (meaning here nothing to do). If they are not 6075 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6076 // start / end and resolve them as left / right (layout direction is not taken into account). 6077 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6078 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6079 // defined. 6080 if (!mLeftPaddingDefined && startPaddingDefined) { 6081 leftPadding = startPadding; 6082 } 6083 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6084 if (!mRightPaddingDefined && endPaddingDefined) { 6085 rightPadding = endPadding; 6086 } 6087 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6088 } else { 6089 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6090 // values defined. Otherwise, left /right values are used. 6091 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6092 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6093 // defined. 6094 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6095 6096 if (mLeftPaddingDefined && !hasRelativePadding) { 6097 mUserPaddingLeftInitial = leftPadding; 6098 } 6099 if (mRightPaddingDefined && !hasRelativePadding) { 6100 mUserPaddingRightInitial = rightPadding; 6101 } 6102 } 6103 6104 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6105 // them on if topPadding or bottomPadding are not valid. 6106 internalSetPadding( 6107 mUserPaddingLeftInitial, 6108 topPadding >= 0 ? topPadding : mPaddingTop, 6109 mUserPaddingRightInitial, 6110 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6111 6112 if (viewFlagMasks != 0) { 6113 setFlags(viewFlagValues, viewFlagMasks); 6114 } 6115 6116 if (initializeScrollbars) { 6117 initializeScrollbarsInternal(a); 6118 } 6119 6120 if (initializeScrollIndicators) { 6121 initializeScrollIndicatorsInternal(); 6122 } 6123 6124 a.recycle(); 6125 6126 // Needs to be called after mViewFlags is set 6127 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6128 recomputePadding(); 6129 } 6130 6131 if (x != 0 || y != 0) { 6132 scrollTo(x, y); 6133 } 6134 6135 if (transformSet) { 6136 setTranslationX(tx); 6137 setTranslationY(ty); 6138 setTranslationZ(tz); 6139 setElevation(elevation); 6140 setRotation(rotation); 6141 setRotationX(rotationX); 6142 setRotationY(rotationY); 6143 setScaleX(sx); 6144 setScaleY(sy); 6145 } 6146 6147 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6148 setScrollContainer(true); 6149 } 6150 6151 computeOpaqueFlags(); 6152 } 6153 6154 /** 6155 * Returns the ordered list of resource ID that are considered when resolving attribute values 6156 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6157 * XML. It will also include a set of explicit styles if specified in XML using 6158 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6159 * 6160 * <p> 6161 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6162 * is enabled in Android developer options. 6163 * 6164 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6165 * @return ordered list of resource ID that are considered when resolving attribute values for 6166 * this {@link View}. 6167 */ 6168 @NonNull 6169 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6170 if (!sDebugViewAttributes 6171 || mAttributeResolutionStacks == null 6172 || mAttributeResolutionStacks.get(attribute) == null) { 6173 return new int[0]; 6174 } 6175 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6176 int stackSize = attributeResolutionStack.length; 6177 if (mSourceLayoutId != ID_NULL) { 6178 stackSize++; 6179 } 6180 6181 int currentIndex = 0; 6182 int[] stack = new int[stackSize]; 6183 6184 if (mSourceLayoutId != ID_NULL) { 6185 stack[currentIndex] = mSourceLayoutId; 6186 currentIndex++; 6187 } 6188 for (int i = 0; i < attributeResolutionStack.length; i++) { 6189 stack[currentIndex] = attributeResolutionStack[i]; 6190 currentIndex++; 6191 } 6192 return stack; 6193 } 6194 6195 /** 6196 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6197 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6198 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6199 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6200 * 6201 * <p> 6202 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6203 * is enabled in Android developer options. 6204 * 6205 * @return mapping of attribute resource ID to source resource ID where the attribute value 6206 * was set. 6207 */ 6208 @NonNull 6209 @SuppressWarnings("AndroidFrameworkEfficientCollections") 6210 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6211 HashMap<Integer, Integer> map = new HashMap<>(); 6212 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6213 return map; 6214 } 6215 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6216 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6217 } 6218 return map; 6219 } 6220 6221 /** 6222 * Returns the resource ID for the style specified using {@code style="..."} in the 6223 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6224 * specified or otherwise not applicable. 6225 * <p> 6226 * Each {@link View} can have an explicit style specified in the layout file. 6227 * This style is used first during the {@link View} attribute resolution, then if an attribute 6228 * is not defined there the resource system looks at default style and theme as fallbacks. 6229 * 6230 * <p> 6231 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6232 * is enabled in Android developer options. 6233 * 6234 * @return The resource ID for the style specified using {@code style="..."} in the 6235 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6236 * if not specified or otherwise not applicable. 6237 */ 6238 @StyleRes 6239 public int getExplicitStyle() { 6240 if (!sDebugViewAttributes) { 6241 return ID_NULL; 6242 } 6243 return mExplicitStyle; 6244 } 6245 6246 /** 6247 * An implementation of OnClickListener that attempts to lazily load a 6248 * named click handling method from a parent or ancestor context. 6249 */ 6250 private static class DeclaredOnClickListener implements OnClickListener { 6251 private final View mHostView; 6252 private final String mMethodName; 6253 6254 private Method mResolvedMethod; 6255 private Context mResolvedContext; 6256 6257 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6258 mHostView = hostView; 6259 mMethodName = methodName; 6260 } 6261 6262 @Override 6263 public void onClick(@NonNull View v) { 6264 if (mResolvedMethod == null) { 6265 resolveMethod(mHostView.getContext(), mMethodName); 6266 } 6267 6268 try { 6269 mResolvedMethod.invoke(mResolvedContext, v); 6270 } catch (IllegalAccessException e) { 6271 throw new IllegalStateException( 6272 "Could not execute non-public method for android:onClick", e); 6273 } catch (InvocationTargetException e) { 6274 throw new IllegalStateException( 6275 "Could not execute method for android:onClick", e); 6276 } 6277 } 6278 6279 @NonNull 6280 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6281 while (context != null) { 6282 try { 6283 if (!context.isRestricted()) { 6284 final Method method = context.getClass().getMethod(mMethodName, View.class); 6285 if (method != null) { 6286 mResolvedMethod = method; 6287 mResolvedContext = context; 6288 return; 6289 } 6290 } 6291 } catch (NoSuchMethodException e) { 6292 // Failed to find method, keep searching up the hierarchy. 6293 } 6294 6295 if (context instanceof ContextWrapper) { 6296 context = ((ContextWrapper) context).getBaseContext(); 6297 } else { 6298 // Can't search up the hierarchy, null out and fail. 6299 context = null; 6300 } 6301 } 6302 6303 final int id = mHostView.getId(); 6304 final String idText = id == NO_ID ? "" : " with id '" 6305 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6306 throw new IllegalStateException("Could not find method " + mMethodName 6307 + "(View) in a parent or ancestor Context for android:onClick " 6308 + "attribute defined on view " + mHostView.getClass() + idText); 6309 } 6310 } 6311 6312 /** 6313 * Non-public constructor for use in testing 6314 */ 6315 @UnsupportedAppUsage 6316 View() { 6317 mResources = null; 6318 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6319 } 6320 6321 /** 6322 * Returns {@code true} when the View is attached and the system developer setting to show 6323 * the layout bounds is enabled or {@code false} otherwise. 6324 */ 6325 public final boolean isShowingLayoutBounds() { 6326 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6327 } 6328 6329 /** 6330 * Used to test isShowingLayoutBounds(). This sets the local value used 6331 * by that function. This method does nothing if the layout isn't attached. 6332 * 6333 * @hide 6334 */ 6335 @TestApi 6336 public final void setShowingLayoutBounds(boolean debugLayout) { 6337 if (mAttachInfo != null) { 6338 mAttachInfo.mDebugLayout = debugLayout; 6339 } 6340 } 6341 6342 private static SparseArray<String> getAttributeMap() { 6343 if (mAttributeMap == null) { 6344 mAttributeMap = new SparseArray<>(); 6345 } 6346 return mAttributeMap; 6347 } 6348 6349 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6350 @Nullable AttributeSet attrs) { 6351 if (!sDebugViewAttributes) { 6352 return; 6353 } 6354 mExplicitStyle = theme.getExplicitStyle(attrs); 6355 } 6356 6357 /** 6358 * Stores debugging information about attributes. This should be called in a constructor by 6359 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6360 * then the custom attributes used by this view will not be visible in layout inspection tools. 6361 * 6362 * @param context Context under which this view is created. 6363 * @param styleable A reference to styleable array R.styleable.Foo 6364 * @param attrs AttributeSet used to construct this view. 6365 * @param t Resolved {@link TypedArray} returned by a call to 6366 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6367 * @param defStyleAttr Default style attribute passed into the view constructor. 6368 * @param defStyleRes Default style resource passed into the view constructor. 6369 */ 6370 public final void saveAttributeDataForStyleable(@NonNull Context context, 6371 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6372 int defStyleAttr, int defStyleRes) { 6373 if (!sDebugViewAttributes) { 6374 return; 6375 } 6376 6377 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6378 defStyleAttr, defStyleRes, mExplicitStyle); 6379 6380 if (mAttributeResolutionStacks == null) { 6381 mAttributeResolutionStacks = new SparseArray<>(); 6382 } 6383 6384 if (mAttributeSourceResId == null) { 6385 mAttributeSourceResId = new SparseIntArray(); 6386 } 6387 6388 final int indexCount = t.getIndexCount(); 6389 for (int j = 0; j < indexCount; ++j) { 6390 final int index = t.getIndex(j); 6391 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6392 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6393 } 6394 } 6395 6396 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6397 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6398 final int indexCount = t.getIndexCount(); 6399 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6400 6401 int i = 0; 6402 6403 // Store raw XML attributes. 6404 for (int j = 0; j < attrsCount; ++j) { 6405 attributes[i] = attrs.getAttributeName(j); 6406 attributes[i + 1] = attrs.getAttributeValue(j); 6407 i += 2; 6408 } 6409 6410 // Store resolved styleable attributes. 6411 final Resources res = t.getResources(); 6412 final SparseArray<String> attributeMap = getAttributeMap(); 6413 for (int j = 0; j < indexCount; ++j) { 6414 final int index = t.getIndex(j); 6415 if (!t.hasValueOrEmpty(index)) { 6416 // Value is undefined. Skip it. 6417 continue; 6418 } 6419 6420 final int resourceId = t.getResourceId(index, 0); 6421 if (resourceId == 0) { 6422 // Value is not a reference. Skip it. 6423 continue; 6424 } 6425 6426 String resourceName = attributeMap.get(resourceId); 6427 if (resourceName == null) { 6428 try { 6429 resourceName = res.getResourceName(resourceId); 6430 } catch (Resources.NotFoundException e) { 6431 resourceName = "0x" + Integer.toHexString(resourceId); 6432 } 6433 attributeMap.put(resourceId, resourceName); 6434 } 6435 6436 attributes[i] = resourceName; 6437 attributes[i + 1] = t.getString(index); 6438 i += 2; 6439 } 6440 6441 // Trim to fit contents. 6442 final String[] trimmed = new String[i]; 6443 System.arraycopy(attributes, 0, trimmed, 0, i); 6444 mAttributes = trimmed; 6445 } 6446 6447 @Override 6448 public String toString() { 6449 StringBuilder out = new StringBuilder(128); 6450 out.append(getClass().getName()); 6451 out.append('{'); 6452 out.append(Integer.toHexString(System.identityHashCode(this))); 6453 out.append(' '); 6454 switch (mViewFlags&VISIBILITY_MASK) { 6455 case VISIBLE: out.append('V'); break; 6456 case INVISIBLE: out.append('I'); break; 6457 case GONE: out.append('G'); break; 6458 default: out.append('.'); break; 6459 } 6460 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6461 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6462 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6463 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6464 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6465 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6466 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6467 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6468 out.append(' '); 6469 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6470 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6471 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6472 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6473 out.append('p'); 6474 } else { 6475 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6476 } 6477 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6478 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6479 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6480 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6481 out.append(' '); 6482 out.append(mLeft); 6483 out.append(','); 6484 out.append(mTop); 6485 out.append('-'); 6486 out.append(mRight); 6487 out.append(','); 6488 out.append(mBottom); 6489 final int id = getId(); 6490 if (id != NO_ID) { 6491 out.append(" #"); 6492 out.append(Integer.toHexString(id)); 6493 final Resources r = mResources; 6494 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6495 try { 6496 String pkgname; 6497 switch (id&0xff000000) { 6498 case 0x7f000000: 6499 pkgname="app"; 6500 break; 6501 case 0x01000000: 6502 pkgname="android"; 6503 break; 6504 default: 6505 pkgname = r.getResourcePackageName(id); 6506 break; 6507 } 6508 String typename = r.getResourceTypeName(id); 6509 String entryname = r.getResourceEntryName(id); 6510 out.append(" "); 6511 out.append(pkgname); 6512 out.append(":"); 6513 out.append(typename); 6514 out.append("/"); 6515 out.append(entryname); 6516 } catch (Resources.NotFoundException e) { 6517 } 6518 } 6519 } 6520 if (mAutofillId != null) { 6521 out.append(" aid="); out.append(mAutofillId); 6522 } 6523 out.append("}"); 6524 return out.toString(); 6525 } 6526 6527 /** 6528 * <p> 6529 * Initializes the fading edges from a given set of styled attributes. This 6530 * method should be called by subclasses that need fading edges and when an 6531 * instance of these subclasses is created programmatically rather than 6532 * being inflated from XML. This method is automatically called when the XML 6533 * is inflated. 6534 * </p> 6535 * 6536 * @param a the styled attributes set to initialize the fading edges from 6537 * 6538 * @removed 6539 */ 6540 protected void initializeFadingEdge(TypedArray a) { 6541 // This method probably shouldn't have been included in the SDK to begin with. 6542 // It relies on 'a' having been initialized using an attribute filter array that is 6543 // not publicly available to the SDK. The old method has been renamed 6544 // to initializeFadingEdgeInternal and hidden for framework use only; 6545 // this one initializes using defaults to make it safe to call for apps. 6546 6547 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6548 6549 initializeFadingEdgeInternal(arr); 6550 6551 arr.recycle(); 6552 } 6553 6554 /** 6555 * <p> 6556 * Initializes the fading edges from a given set of styled attributes. This 6557 * method should be called by subclasses that need fading edges and when an 6558 * instance of these subclasses is created programmatically rather than 6559 * being inflated from XML. This method is automatically called when the XML 6560 * is inflated. 6561 * </p> 6562 * 6563 * @param a the styled attributes set to initialize the fading edges from 6564 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6565 */ 6566 protected void initializeFadingEdgeInternal(TypedArray a) { 6567 initScrollCache(); 6568 6569 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6570 R.styleable.View_fadingEdgeLength, 6571 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6572 } 6573 6574 /** 6575 * Returns the size of the vertical faded edges used to indicate that more 6576 * content in this view is visible. 6577 * 6578 * @return The size in pixels of the vertical faded edge or 0 if vertical 6579 * faded edges are not enabled for this view. 6580 * @attr ref android.R.styleable#View_fadingEdgeLength 6581 */ 6582 public int getVerticalFadingEdgeLength() { 6583 if (isVerticalFadingEdgeEnabled()) { 6584 ScrollabilityCache cache = mScrollCache; 6585 if (cache != null) { 6586 return cache.fadingEdgeLength; 6587 } 6588 } 6589 return 0; 6590 } 6591 6592 /** 6593 * Set the size of the faded edge used to indicate that more content in this 6594 * view is available. Will not change whether the fading edge is enabled; use 6595 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6596 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6597 * for the vertical or horizontal fading edges. 6598 * 6599 * @param length The size in pixels of the faded edge used to indicate that more 6600 * content in this view is visible. 6601 */ 6602 public void setFadingEdgeLength(int length) { 6603 initScrollCache(); 6604 mScrollCache.fadingEdgeLength = length; 6605 } 6606 6607 /** 6608 * Returns the size of the horizontal faded edges used to indicate that more 6609 * content in this view is visible. 6610 * 6611 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6612 * faded edges are not enabled for this view. 6613 * @attr ref android.R.styleable#View_fadingEdgeLength 6614 */ 6615 public int getHorizontalFadingEdgeLength() { 6616 if (isHorizontalFadingEdgeEnabled()) { 6617 ScrollabilityCache cache = mScrollCache; 6618 if (cache != null) { 6619 return cache.fadingEdgeLength; 6620 } 6621 } 6622 return 0; 6623 } 6624 6625 /** 6626 * Returns the width of the vertical scrollbar. 6627 * 6628 * @return The width in pixels of the vertical scrollbar or 0 if there 6629 * is no vertical scrollbar. 6630 */ 6631 public int getVerticalScrollbarWidth() { 6632 ScrollabilityCache cache = mScrollCache; 6633 if (cache != null) { 6634 ScrollBarDrawable scrollBar = cache.scrollBar; 6635 if (scrollBar != null) { 6636 int size = scrollBar.getSize(true); 6637 if (size <= 0) { 6638 size = cache.scrollBarSize; 6639 } 6640 return size; 6641 } 6642 return 0; 6643 } 6644 return 0; 6645 } 6646 6647 /** 6648 * Returns the height of the horizontal scrollbar. 6649 * 6650 * @return The height in pixels of the horizontal scrollbar or 0 if 6651 * there is no horizontal scrollbar. 6652 */ 6653 protected int getHorizontalScrollbarHeight() { 6654 ScrollabilityCache cache = mScrollCache; 6655 if (cache != null) { 6656 ScrollBarDrawable scrollBar = cache.scrollBar; 6657 if (scrollBar != null) { 6658 int size = scrollBar.getSize(false); 6659 if (size <= 0) { 6660 size = cache.scrollBarSize; 6661 } 6662 return size; 6663 } 6664 return 0; 6665 } 6666 return 0; 6667 } 6668 6669 /** 6670 * <p> 6671 * Initializes the scrollbars from a given set of styled attributes. This 6672 * method should be called by subclasses that need scrollbars and when an 6673 * instance of these subclasses is created programmatically rather than 6674 * being inflated from XML. This method is automatically called when the XML 6675 * is inflated. 6676 * </p> 6677 * 6678 * @param a the styled attributes set to initialize the scrollbars from 6679 * 6680 * @removed 6681 */ 6682 protected void initializeScrollbars(TypedArray a) { 6683 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6684 // using the View filter array which is not available to the SDK. As such, internal 6685 // framework usage now uses initializeScrollbarsInternal and we grab a default 6686 // TypedArray with the right filter instead here. 6687 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6688 6689 initializeScrollbarsInternal(arr); 6690 6691 // We ignored the method parameter. Recycle the one we actually did use. 6692 arr.recycle(); 6693 } 6694 6695 private void initializeScrollBarDrawable() { 6696 initScrollCache(); 6697 6698 if (mScrollCache.scrollBar == null) { 6699 mScrollCache.scrollBar = new ScrollBarDrawable(); 6700 mScrollCache.scrollBar.setState(getDrawableState()); 6701 mScrollCache.scrollBar.setCallback(this); 6702 } 6703 } 6704 6705 /** 6706 * <p> 6707 * Initializes the scrollbars from a given set of styled attributes. This 6708 * method should be called by subclasses that need scrollbars and when an 6709 * instance of these subclasses is created programmatically rather than 6710 * being inflated from XML. This method is automatically called when the XML 6711 * is inflated. 6712 * </p> 6713 * 6714 * @param a the styled attributes set to initialize the scrollbars from 6715 * @hide 6716 */ 6717 @UnsupportedAppUsage 6718 protected void initializeScrollbarsInternal(TypedArray a) { 6719 initScrollCache(); 6720 6721 final ScrollabilityCache scrollabilityCache = mScrollCache; 6722 6723 if (scrollabilityCache.scrollBar == null) { 6724 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6725 scrollabilityCache.scrollBar.setState(getDrawableState()); 6726 scrollabilityCache.scrollBar.setCallback(this); 6727 } 6728 6729 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6730 6731 if (!fadeScrollbars) { 6732 scrollabilityCache.state = ScrollabilityCache.ON; 6733 } 6734 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6735 6736 6737 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6738 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6739 .getScrollBarFadeDuration()); 6740 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6741 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6742 ViewConfiguration.getScrollDefaultDelay()); 6743 6744 6745 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6746 com.android.internal.R.styleable.View_scrollbarSize, 6747 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6748 6749 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6750 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6751 6752 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6753 if (thumb != null) { 6754 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6755 } 6756 6757 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6758 false); 6759 if (alwaysDraw) { 6760 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6761 } 6762 6763 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6764 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6765 6766 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6767 if (thumb != null) { 6768 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6769 } 6770 6771 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6772 false); 6773 if (alwaysDraw) { 6774 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6775 } 6776 6777 // Apply layout direction to the new Drawables if needed 6778 final int layoutDirection = getLayoutDirection(); 6779 if (track != null) { 6780 track.setLayoutDirection(layoutDirection); 6781 } 6782 if (thumb != null) { 6783 thumb.setLayoutDirection(layoutDirection); 6784 } 6785 6786 // Re-apply user/background padding so that scrollbar(s) get added 6787 resolvePadding(); 6788 } 6789 6790 /** 6791 * Defines the vertical scrollbar thumb drawable 6792 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6793 * 6794 * @see #awakenScrollBars(int) 6795 * @see #isVerticalScrollBarEnabled() 6796 * @see #setVerticalScrollBarEnabled(boolean) 6797 */ 6798 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6799 initializeScrollBarDrawable(); 6800 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 6801 } 6802 6803 /** 6804 * Defines the vertical scrollbar track drawable 6805 * @attr ref android.R.styleable#View_scrollbarTrackVertical 6806 * 6807 * @see #awakenScrollBars(int) 6808 * @see #isVerticalScrollBarEnabled() 6809 * @see #setVerticalScrollBarEnabled(boolean) 6810 */ 6811 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6812 initializeScrollBarDrawable(); 6813 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 6814 } 6815 6816 /** 6817 * Defines the horizontal thumb drawable 6818 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 6819 * 6820 * @see #awakenScrollBars(int) 6821 * @see #isHorizontalScrollBarEnabled() 6822 * @see #setHorizontalScrollBarEnabled(boolean) 6823 */ 6824 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6825 initializeScrollBarDrawable(); 6826 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 6827 } 6828 6829 /** 6830 * Defines the horizontal track drawable 6831 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 6832 * 6833 * @see #awakenScrollBars(int) 6834 * @see #isHorizontalScrollBarEnabled() 6835 * @see #setHorizontalScrollBarEnabled(boolean) 6836 */ 6837 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6838 initializeScrollBarDrawable(); 6839 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 6840 } 6841 6842 /** 6843 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 6844 * exists, null otherwise. 6845 * 6846 * @see #awakenScrollBars(int) 6847 * @see #isVerticalScrollBarEnabled() 6848 * @see #setVerticalScrollBarEnabled(boolean) 6849 */ 6850 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 6851 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 6852 } 6853 6854 /** 6855 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 6856 * exists, null otherwise. 6857 * 6858 * @see #awakenScrollBars(int) 6859 * @see #isVerticalScrollBarEnabled() 6860 * @see #setVerticalScrollBarEnabled(boolean) 6861 */ 6862 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 6863 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 6864 } 6865 6866 /** 6867 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 6868 * exists, null otherwise. 6869 * 6870 * @see #awakenScrollBars(int) 6871 * @see #isHorizontalScrollBarEnabled() 6872 * @see #setHorizontalScrollBarEnabled(boolean) 6873 */ 6874 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 6875 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 6876 } 6877 6878 /** 6879 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 6880 * exists, null otherwise. 6881 * 6882 * @see #awakenScrollBars(int) 6883 * @see #isHorizontalScrollBarEnabled() 6884 * @see #setHorizontalScrollBarEnabled(boolean) 6885 */ 6886 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 6887 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 6888 } 6889 6890 private void initializeScrollIndicatorsInternal() { 6891 // Some day maybe we'll break this into top/left/start/etc. and let the 6892 // client control it. Until then, you can have any scroll indicator you 6893 // want as long as it's a 1dp foreground-colored rectangle. 6894 if (mScrollIndicatorDrawable == null) { 6895 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6896 } 6897 } 6898 6899 /** 6900 * <p> 6901 * Initalizes the scrollability cache if necessary. 6902 * </p> 6903 */ 6904 private void initScrollCache() { 6905 if (mScrollCache == null) { 6906 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6907 } 6908 } 6909 6910 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 6911 private ScrollabilityCache getScrollCache() { 6912 initScrollCache(); 6913 return mScrollCache; 6914 } 6915 6916 /** 6917 * Set the position of the vertical scroll bar. Should be one of 6918 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 6919 * {@link #SCROLLBAR_POSITION_RIGHT}. 6920 * 6921 * @param position Where the vertical scroll bar should be positioned. 6922 */ 6923 public void setVerticalScrollbarPosition(int position) { 6924 if (mVerticalScrollbarPosition != position) { 6925 mVerticalScrollbarPosition = position; 6926 computeOpaqueFlags(); 6927 resolvePadding(); 6928 } 6929 } 6930 6931 /** 6932 * @return The position where the vertical scroll bar will show, if applicable. 6933 * @see #setVerticalScrollbarPosition(int) 6934 */ 6935 public int getVerticalScrollbarPosition() { 6936 return mVerticalScrollbarPosition; 6937 } 6938 6939 boolean isOnScrollbar(float x, float y) { 6940 if (mScrollCache == null) { 6941 return false; 6942 } 6943 x += getScrollX(); 6944 y += getScrollY(); 6945 final boolean canScrollVertically = 6946 computeVerticalScrollRange() > computeVerticalScrollExtent(); 6947 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 6948 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6949 getVerticalScrollBarBounds(null, touchBounds); 6950 if (touchBounds.contains((int) x, (int) y)) { 6951 return true; 6952 } 6953 } 6954 final boolean canScrollHorizontally = 6955 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 6956 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 6957 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6958 getHorizontalScrollBarBounds(null, touchBounds); 6959 if (touchBounds.contains((int) x, (int) y)) { 6960 return true; 6961 } 6962 } 6963 return false; 6964 } 6965 6966 @UnsupportedAppUsage 6967 boolean isOnScrollbarThumb(float x, float y) { 6968 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 6969 } 6970 6971 private boolean isOnVerticalScrollbarThumb(float x, float y) { 6972 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 6973 return false; 6974 } 6975 final int range = computeVerticalScrollRange(); 6976 final int extent = computeVerticalScrollExtent(); 6977 if (range > extent) { 6978 x += getScrollX(); 6979 y += getScrollY(); 6980 final Rect bounds = mScrollCache.mScrollBarBounds; 6981 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6982 getVerticalScrollBarBounds(bounds, touchBounds); 6983 final int offset = computeVerticalScrollOffset(); 6984 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 6985 extent, range); 6986 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 6987 extent, range, offset); 6988 final int thumbTop = bounds.top + thumbOffset; 6989 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6990 if (x >= touchBounds.left && x <= touchBounds.right 6991 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 6992 return true; 6993 } 6994 } 6995 return false; 6996 } 6997 6998 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 6999 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 7000 return false; 7001 } 7002 final int range = computeHorizontalScrollRange(); 7003 final int extent = computeHorizontalScrollExtent(); 7004 if (range > extent) { 7005 x += getScrollX(); 7006 y += getScrollY(); 7007 final Rect bounds = mScrollCache.mScrollBarBounds; 7008 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7009 getHorizontalScrollBarBounds(bounds, touchBounds); 7010 final int offset = computeHorizontalScrollOffset(); 7011 7012 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 7013 extent, range); 7014 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7015 extent, range, offset); 7016 final int thumbLeft = bounds.left + thumbOffset; 7017 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7018 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7019 && y >= touchBounds.top && y <= touchBounds.bottom) { 7020 return true; 7021 } 7022 } 7023 return false; 7024 } 7025 7026 @UnsupportedAppUsage 7027 boolean isDraggingScrollBar() { 7028 return mScrollCache != null 7029 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7030 } 7031 7032 /** 7033 * Sets the state of all scroll indicators. 7034 * <p> 7035 * See {@link #setScrollIndicators(int, int)} for usage information. 7036 * 7037 * @param indicators a bitmask of indicators that should be enabled, or 7038 * {@code 0} to disable all indicators 7039 * @see #setScrollIndicators(int, int) 7040 * @see #getScrollIndicators() 7041 * @attr ref android.R.styleable#View_scrollIndicators 7042 */ 7043 @RemotableViewMethod 7044 public void setScrollIndicators(@ScrollIndicators int indicators) { 7045 setScrollIndicators(indicators, 7046 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7047 } 7048 7049 /** 7050 * Sets the state of the scroll indicators specified by the mask. To change 7051 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7052 * <p> 7053 * When a scroll indicator is enabled, it will be displayed if the view 7054 * can scroll in the direction of the indicator. 7055 * <p> 7056 * Multiple indicator types may be enabled or disabled by passing the 7057 * logical OR of the desired types. If multiple types are specified, they 7058 * will all be set to the same enabled state. 7059 * <p> 7060 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7061 * 7062 * @param indicators the indicator direction, or the logical OR of multiple 7063 * indicator directions. One or more of: 7064 * <ul> 7065 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7066 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7067 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7068 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7069 * <li>{@link #SCROLL_INDICATOR_START}</li> 7070 * <li>{@link #SCROLL_INDICATOR_END}</li> 7071 * </ul> 7072 * @see #setScrollIndicators(int) 7073 * @see #getScrollIndicators() 7074 * @attr ref android.R.styleable#View_scrollIndicators 7075 */ 7076 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7077 // Shift and sanitize mask. 7078 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7079 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7080 7081 // Shift and mask indicators. 7082 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7083 indicators &= mask; 7084 7085 // Merge with non-masked flags. 7086 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7087 7088 if (mPrivateFlags3 != updatedFlags) { 7089 mPrivateFlags3 = updatedFlags; 7090 7091 if (indicators != 0) { 7092 initializeScrollIndicatorsInternal(); 7093 } 7094 invalidate(); 7095 } 7096 } 7097 7098 /** 7099 * Returns a bitmask representing the enabled scroll indicators. 7100 * <p> 7101 * For example, if the top and left scroll indicators are enabled and all 7102 * other indicators are disabled, the return value will be 7103 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7104 * <p> 7105 * To check whether the bottom scroll indicator is enabled, use the value 7106 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7107 * 7108 * @return a bitmask representing the enabled scroll indicators 7109 */ 7110 @InspectableProperty(flagMapping = { 7111 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7112 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7113 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7114 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7115 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7116 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7117 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7118 }) 7119 @ScrollIndicators 7120 public int getScrollIndicators() { 7121 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7122 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7123 } 7124 7125 @UnsupportedAppUsage 7126 ListenerInfo getListenerInfo() { 7127 if (mListenerInfo != null) { 7128 return mListenerInfo; 7129 } 7130 mListenerInfo = new ListenerInfo(); 7131 return mListenerInfo; 7132 } 7133 7134 /** 7135 * Register a callback to be invoked when the scroll X or Y positions of 7136 * this view change. 7137 * <p> 7138 * <b>Note:</b> Some views handle scrolling independently from View and may 7139 * have their own separate listeners for scroll-type events. For example, 7140 * {@link android.widget.ListView ListView} allows clients to register an 7141 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7142 * to listen for changes in list scroll position. 7143 * 7144 * @param l The listener to notify when the scroll X or Y position changes. 7145 * @see android.view.View#getScrollX() 7146 * @see android.view.View#getScrollY() 7147 */ 7148 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7149 getListenerInfo().mOnScrollChangeListener = l; 7150 } 7151 7152 /** 7153 * Register a callback to be invoked when focus of this view changed. 7154 * 7155 * @param l The callback that will run. 7156 */ 7157 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7158 getListenerInfo().mOnFocusChangeListener = l; 7159 } 7160 7161 /** 7162 * Add a listener that will be called when the bounds of the view change due to 7163 * layout processing. 7164 * 7165 * @param listener The listener that will be called when layout bounds change. 7166 */ 7167 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7168 ListenerInfo li = getListenerInfo(); 7169 if (li.mOnLayoutChangeListeners == null) { 7170 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7171 } 7172 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7173 li.mOnLayoutChangeListeners.add(listener); 7174 } 7175 } 7176 7177 /** 7178 * Remove a listener for layout changes. 7179 * 7180 * @param listener The listener for layout bounds change. 7181 */ 7182 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7183 ListenerInfo li = mListenerInfo; 7184 if (li == null || li.mOnLayoutChangeListeners == null) { 7185 return; 7186 } 7187 li.mOnLayoutChangeListeners.remove(listener); 7188 } 7189 7190 /** 7191 * Add a listener for attach state changes. 7192 * 7193 * This listener will be called whenever this view is attached or detached 7194 * from a window. Remove the listener using 7195 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7196 * 7197 * @param listener Listener to attach 7198 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7199 */ 7200 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7201 ListenerInfo li = getListenerInfo(); 7202 if (li.mOnAttachStateChangeListeners == null) { 7203 li.mOnAttachStateChangeListeners 7204 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7205 } 7206 li.mOnAttachStateChangeListeners.add(listener); 7207 } 7208 7209 /** 7210 * Remove a listener for attach state changes. The listener will receive no further 7211 * notification of window attach/detach events. 7212 * 7213 * @param listener Listener to remove 7214 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7215 */ 7216 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7217 ListenerInfo li = mListenerInfo; 7218 if (li == null || li.mOnAttachStateChangeListeners == null) { 7219 return; 7220 } 7221 li.mOnAttachStateChangeListeners.remove(listener); 7222 } 7223 7224 /** 7225 * Returns the focus-change callback registered for this view. 7226 * 7227 * @return The callback, or null if one is not registered. 7228 */ 7229 public OnFocusChangeListener getOnFocusChangeListener() { 7230 ListenerInfo li = mListenerInfo; 7231 return li != null ? li.mOnFocusChangeListener : null; 7232 } 7233 7234 /** 7235 * Register a callback to be invoked when this view is clicked. If this view is not 7236 * clickable, it becomes clickable. 7237 * 7238 * @param l The callback that will run 7239 * 7240 * @see #setClickable(boolean) 7241 */ 7242 public void setOnClickListener(@Nullable OnClickListener l) { 7243 if (!isClickable()) { 7244 setClickable(true); 7245 } 7246 getListenerInfo().mOnClickListener = l; 7247 } 7248 7249 /** 7250 * Return whether this view has an attached OnClickListener. Returns 7251 * true if there is a listener, false if there is none. 7252 */ 7253 public boolean hasOnClickListeners() { 7254 ListenerInfo li = mListenerInfo; 7255 return (li != null && li.mOnClickListener != null); 7256 } 7257 7258 /** 7259 * Register a callback to be invoked when this view is clicked and held. If this view is not 7260 * long clickable, it becomes long clickable. 7261 * 7262 * @param l The callback that will run 7263 * 7264 * @see #setLongClickable(boolean) 7265 */ 7266 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7267 if (!isLongClickable()) { 7268 setLongClickable(true); 7269 } 7270 getListenerInfo().mOnLongClickListener = l; 7271 } 7272 7273 /** 7274 * Return whether this view has an attached OnLongClickListener. Returns 7275 * true if there is a listener, false if there is none. 7276 */ 7277 public boolean hasOnLongClickListeners() { 7278 ListenerInfo li = mListenerInfo; 7279 return (li != null && li.mOnLongClickListener != null); 7280 } 7281 7282 /** 7283 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7284 * @hide 7285 */ 7286 @Nullable 7287 public OnLongClickListener getOnLongClickListener() { 7288 ListenerInfo li = mListenerInfo; 7289 return (li != null) ? li.mOnLongClickListener : null; 7290 } 7291 7292 /** 7293 * Register a callback to be invoked when this view is context clicked. If the view is not 7294 * context clickable, it becomes context clickable. 7295 * 7296 * @param l The callback that will run 7297 * @see #setContextClickable(boolean) 7298 */ 7299 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7300 if (!isContextClickable()) { 7301 setContextClickable(true); 7302 } 7303 getListenerInfo().mOnContextClickListener = l; 7304 } 7305 7306 /** 7307 * Register a callback to be invoked when the context menu for this view is 7308 * being built. If this view is not long clickable, it becomes long clickable. 7309 * 7310 * @param l The callback that will run 7311 * 7312 */ 7313 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7314 if (!isLongClickable()) { 7315 setLongClickable(true); 7316 } 7317 getListenerInfo().mOnCreateContextMenuListener = l; 7318 } 7319 7320 /** 7321 * Set an observer to collect stats for each frame rendered for this view. 7322 * 7323 * @hide 7324 */ 7325 public void addFrameMetricsListener(Window window, 7326 Window.OnFrameMetricsAvailableListener listener, 7327 Handler handler) { 7328 if (mAttachInfo != null) { 7329 if (mAttachInfo.mThreadedRenderer != null) { 7330 if (mFrameMetricsObservers == null) { 7331 mFrameMetricsObservers = new ArrayList<>(); 7332 } 7333 7334 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7335 mFrameMetricsObservers.add(fmo); 7336 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7337 } else { 7338 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7339 } 7340 } else { 7341 if (mFrameMetricsObservers == null) { 7342 mFrameMetricsObservers = new ArrayList<>(); 7343 } 7344 7345 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7346 mFrameMetricsObservers.add(fmo); 7347 } 7348 } 7349 7350 /** 7351 * Remove observer configured to collect frame stats for this view. 7352 * 7353 * @hide 7354 */ 7355 public void removeFrameMetricsListener( 7356 Window.OnFrameMetricsAvailableListener listener) { 7357 ThreadedRenderer renderer = getThreadedRenderer(); 7358 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7359 if (fmo == null) { 7360 throw new IllegalArgumentException( 7361 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7362 } 7363 7364 if (mFrameMetricsObservers != null) { 7365 mFrameMetricsObservers.remove(fmo); 7366 if (renderer != null) { 7367 renderer.removeObserver(fmo.getRendererObserver()); 7368 } 7369 } 7370 } 7371 7372 private void registerPendingFrameMetricsObservers() { 7373 if (mFrameMetricsObservers != null) { 7374 ThreadedRenderer renderer = getThreadedRenderer(); 7375 if (renderer != null) { 7376 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7377 renderer.addObserver(fmo.getRendererObserver()); 7378 } 7379 } else { 7380 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7381 } 7382 } 7383 } 7384 7385 private FrameMetricsObserver findFrameMetricsObserver( 7386 Window.OnFrameMetricsAvailableListener listener) { 7387 if (mFrameMetricsObservers != null) { 7388 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7389 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7390 if (observer.mListener == listener) { 7391 return observer; 7392 } 7393 } 7394 } 7395 7396 return null; 7397 } 7398 7399 /** @hide */ 7400 public void setNotifyAutofillManagerOnClick(boolean notify) { 7401 if (notify) { 7402 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7403 } else { 7404 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7405 } 7406 } 7407 7408 private void notifyAutofillManagerOnClick() { 7409 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7410 try { 7411 getAutofillManager().notifyViewClicked(this); 7412 } finally { 7413 // Set it to already called so it's not called twice when called by 7414 // performClickInternal() 7415 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7416 } 7417 } 7418 } 7419 7420 /** 7421 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7422 * {@code performClick()} directly to make sure the autofill manager is notified when 7423 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7424 * method). 7425 */ 7426 private boolean performClickInternal() { 7427 // Must notify autofill manager before performing the click actions to avoid scenarios where 7428 // the app has a click listener that changes the state of views the autofill service might 7429 // be interested on. 7430 notifyAutofillManagerOnClick(); 7431 7432 return performClick(); 7433 } 7434 7435 /** 7436 * Call this view's OnClickListener, if it is defined. Performs all normal 7437 * actions associated with clicking: reporting accessibility event, playing 7438 * a sound, etc. 7439 * 7440 * @return True there was an assigned OnClickListener that was called, false 7441 * otherwise is returned. 7442 */ 7443 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7444 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7445 // could extend this method without calling super.performClick()). 7446 public boolean performClick() { 7447 // We still need to call this method to handle the cases where performClick() was called 7448 // externally, instead of through performClickInternal() 7449 notifyAutofillManagerOnClick(); 7450 7451 final boolean result; 7452 final ListenerInfo li = mListenerInfo; 7453 if (li != null && li.mOnClickListener != null) { 7454 playSoundEffect(SoundEffectConstants.CLICK); 7455 li.mOnClickListener.onClick(this); 7456 result = true; 7457 } else { 7458 result = false; 7459 } 7460 7461 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7462 7463 notifyEnterOrExitForAutoFillIfNeeded(true); 7464 7465 return result; 7466 } 7467 7468 /** 7469 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7470 * this only calls the listener, and does not do any associated clicking 7471 * actions like reporting an accessibility event. 7472 * 7473 * @return True there was an assigned OnClickListener that was called, false 7474 * otherwise is returned. 7475 */ 7476 public boolean callOnClick() { 7477 ListenerInfo li = mListenerInfo; 7478 if (li != null && li.mOnClickListener != null) { 7479 li.mOnClickListener.onClick(this); 7480 return true; 7481 } 7482 return false; 7483 } 7484 7485 /** 7486 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7487 * context menu if the OnLongClickListener did not consume the event. 7488 * 7489 * @return {@code true} if one of the above receivers consumed the event, 7490 * {@code false} otherwise 7491 */ 7492 public boolean performLongClick() { 7493 return performLongClickInternal(mLongClickX, mLongClickY); 7494 } 7495 7496 /** 7497 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7498 * context menu if the OnLongClickListener did not consume the event, 7499 * anchoring it to an (x,y) coordinate. 7500 * 7501 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7502 * to disable anchoring 7503 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7504 * to disable anchoring 7505 * @return {@code true} if one of the above receivers consumed the event, 7506 * {@code false} otherwise 7507 */ 7508 public boolean performLongClick(float x, float y) { 7509 mLongClickX = x; 7510 mLongClickY = y; 7511 final boolean handled = performLongClick(); 7512 mLongClickX = Float.NaN; 7513 mLongClickY = Float.NaN; 7514 return handled; 7515 } 7516 7517 /** 7518 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7519 * context menu if the OnLongClickListener did not consume the event, 7520 * optionally anchoring it to an (x,y) coordinate. 7521 * 7522 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7523 * to disable anchoring 7524 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7525 * to disable anchoring 7526 * @return {@code true} if one of the above receivers consumed the event, 7527 * {@code false} otherwise 7528 */ 7529 private boolean performLongClickInternal(float x, float y) { 7530 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7531 7532 boolean handled = false; 7533 final ListenerInfo li = mListenerInfo; 7534 if (li != null && li.mOnLongClickListener != null) { 7535 handled = li.mOnLongClickListener.onLongClick(View.this); 7536 } 7537 if (!handled) { 7538 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7539 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7540 } 7541 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7542 if (!handled) { 7543 handled = showLongClickTooltip((int) x, (int) y); 7544 } 7545 } 7546 if (handled) { 7547 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7548 } 7549 return handled; 7550 } 7551 7552 /** 7553 * Call this view's OnContextClickListener, if it is defined. 7554 * 7555 * @param x the x coordinate of the context click 7556 * @param y the y coordinate of the context click 7557 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7558 * otherwise. 7559 */ 7560 public boolean performContextClick(float x, float y) { 7561 return performContextClick(); 7562 } 7563 7564 /** 7565 * Call this view's OnContextClickListener, if it is defined. 7566 * 7567 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7568 * otherwise. 7569 */ 7570 public boolean performContextClick() { 7571 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7572 7573 boolean handled = false; 7574 ListenerInfo li = mListenerInfo; 7575 if (li != null && li.mOnContextClickListener != null) { 7576 handled = li.mOnContextClickListener.onContextClick(View.this); 7577 } 7578 if (handled) { 7579 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7580 } 7581 return handled; 7582 } 7583 7584 /** 7585 * Performs button-related actions during a touch down event. 7586 * 7587 * @param event The event. 7588 * @return True if the down was consumed. 7589 * 7590 * @hide 7591 */ 7592 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7593 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7594 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7595 showContextMenu(event.getX(), event.getY()); 7596 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7597 return true; 7598 } 7599 return false; 7600 } 7601 7602 /** 7603 * Shows the context menu for this view. 7604 * 7605 * @return {@code true} if the context menu was shown, {@code false} 7606 * otherwise 7607 * @see #showContextMenu(float, float) 7608 */ 7609 public boolean showContextMenu() { 7610 return getParent().showContextMenuForChild(this); 7611 } 7612 7613 /** 7614 * Shows the context menu for this view anchored to the specified 7615 * view-relative coordinate. 7616 * 7617 * @param x the X coordinate in pixels relative to the view to which the 7618 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7619 * @param y the Y coordinate in pixels relative to the view to which the 7620 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7621 * @return {@code true} if the context menu was shown, {@code false} 7622 * otherwise 7623 */ 7624 public boolean showContextMenu(float x, float y) { 7625 return getParent().showContextMenuForChild(this, x, y); 7626 } 7627 7628 /** 7629 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7630 * 7631 * @param callback Callback that will control the lifecycle of the action mode 7632 * @return The new action mode if it is started, null otherwise 7633 * 7634 * @see ActionMode 7635 * @see #startActionMode(android.view.ActionMode.Callback, int) 7636 */ 7637 public ActionMode startActionMode(ActionMode.Callback callback) { 7638 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7639 } 7640 7641 /** 7642 * Start an action mode with the given type. 7643 * 7644 * @param callback Callback that will control the lifecycle of the action mode 7645 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7646 * @return The new action mode if it is started, null otherwise 7647 * 7648 * @see ActionMode 7649 */ 7650 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7651 ViewParent parent = getParent(); 7652 if (parent == null) return null; 7653 try { 7654 return parent.startActionModeForChild(this, callback, type); 7655 } catch (AbstractMethodError ame) { 7656 // Older implementations of custom views might not implement this. 7657 return parent.startActionModeForChild(this, callback); 7658 } 7659 } 7660 7661 /** 7662 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7663 * Context, creating a unique View identifier to retrieve the result. 7664 * 7665 * @param intent The Intent to be started. 7666 * @param requestCode The request code to use. 7667 * @hide 7668 */ 7669 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7670 public void startActivityForResult(Intent intent, int requestCode) { 7671 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7672 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7673 } 7674 7675 /** 7676 * If this View corresponds to the calling who, dispatches the activity result. 7677 * @param who The identifier for the targeted View to receive the result. 7678 * @param requestCode The integer request code originally supplied to 7679 * startActivityForResult(), allowing you to identify who this 7680 * result came from. 7681 * @param resultCode The integer result code returned by the child activity 7682 * through its setResult(). 7683 * @param data An Intent, which can return result data to the caller 7684 * (various data can be attached to Intent "extras"). 7685 * @return {@code true} if the activity result was dispatched. 7686 * @hide 7687 */ 7688 public boolean dispatchActivityResult( 7689 String who, int requestCode, int resultCode, Intent data) { 7690 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7691 onActivityResult(requestCode, resultCode, data); 7692 mStartActivityRequestWho = null; 7693 return true; 7694 } 7695 return false; 7696 } 7697 7698 /** 7699 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7700 * 7701 * @param requestCode The integer request code originally supplied to 7702 * startActivityForResult(), allowing you to identify who this 7703 * result came from. 7704 * @param resultCode The integer result code returned by the child activity 7705 * through its setResult(). 7706 * @param data An Intent, which can return result data to the caller 7707 * (various data can be attached to Intent "extras"). 7708 * @hide 7709 */ 7710 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7711 // Do nothing. 7712 } 7713 7714 /** 7715 * Register a callback to be invoked when a hardware key is pressed in this view. 7716 * Key presses in software input methods will generally not trigger the methods of 7717 * this listener. 7718 * @param l the key listener to attach to this view 7719 */ 7720 public void setOnKeyListener(OnKeyListener l) { 7721 getListenerInfo().mOnKeyListener = l; 7722 } 7723 7724 /** 7725 * Register a callback to be invoked when a touch event is sent to this view. 7726 * @param l the touch listener to attach to this view 7727 */ 7728 public void setOnTouchListener(OnTouchListener l) { 7729 getListenerInfo().mOnTouchListener = l; 7730 } 7731 7732 /** 7733 * Register a callback to be invoked when a generic motion event is sent to this view. 7734 * @param l the generic motion listener to attach to this view 7735 */ 7736 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7737 getListenerInfo().mOnGenericMotionListener = l; 7738 } 7739 7740 /** 7741 * Register a callback to be invoked when a hover event is sent to this view. 7742 * @param l the hover listener to attach to this view 7743 */ 7744 public void setOnHoverListener(OnHoverListener l) { 7745 getListenerInfo().mOnHoverListener = l; 7746 } 7747 7748 /** 7749 * Register a drag event listener callback object for this View. The parameter is 7750 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7751 * View, the system calls the 7752 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7753 * @param l An implementation of {@link android.view.View.OnDragListener}. 7754 */ 7755 public void setOnDragListener(OnDragListener l) { 7756 getListenerInfo().mOnDragListener = l; 7757 } 7758 7759 /** 7760 * Give this view focus. This will cause 7761 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7762 * 7763 * Note: this does not check whether this {@link View} should get focus, it just 7764 * gives it focus no matter what. It should only be called internally by framework 7765 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7766 * 7767 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7768 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7769 * focus moved when requestFocus() is called. It may not always 7770 * apply, in which case use the default View.FOCUS_DOWN. 7771 * @param previouslyFocusedRect The rectangle of the view that had focus 7772 * prior in this View's coordinate system. 7773 */ 7774 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7775 if (DBG) { 7776 System.out.println(this + " requestFocus()"); 7777 } 7778 7779 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7780 mPrivateFlags |= PFLAG_FOCUSED; 7781 7782 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7783 7784 if (mParent != null) { 7785 mParent.requestChildFocus(this, this); 7786 updateFocusedInCluster(oldFocus, direction); 7787 } 7788 7789 if (mAttachInfo != null) { 7790 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 7791 } 7792 7793 onFocusChanged(true, direction, previouslyFocusedRect); 7794 refreshDrawableState(); 7795 } 7796 } 7797 7798 /** 7799 * Sets this view's preference for reveal behavior when it gains focus. 7800 * 7801 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 7802 * this view would prefer to be brought fully into view when it gains focus. 7803 * For example, a text field that a user is meant to type into. Other views such 7804 * as scrolling containers may prefer to opt-out of this behavior.</p> 7805 * 7806 * <p>The default value for views is true, though subclasses may change this 7807 * based on their preferred behavior.</p> 7808 * 7809 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 7810 * 7811 * @see #getRevealOnFocusHint() 7812 */ 7813 public final void setRevealOnFocusHint(boolean revealOnFocus) { 7814 if (revealOnFocus) { 7815 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 7816 } else { 7817 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 7818 } 7819 } 7820 7821 /** 7822 * Returns this view's preference for reveal behavior when it gains focus. 7823 * 7824 * <p>When this method returns true for a child view requesting focus, ancestor 7825 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 7826 * should make a best effort to make the newly focused child fully visible to the user. 7827 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 7828 * other properties affecting visibility to the user as part of the focus change.</p> 7829 * 7830 * @return true if this view would prefer to become fully visible when it gains focus, 7831 * false if it would prefer not to disrupt scroll positioning 7832 * 7833 * @see #setRevealOnFocusHint(boolean) 7834 */ 7835 public final boolean getRevealOnFocusHint() { 7836 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 7837 } 7838 7839 /** 7840 * Populates <code>outRect</code> with the hotspot bounds. By default, 7841 * the hotspot bounds are identical to the screen bounds. 7842 * 7843 * @param outRect rect to populate with hotspot bounds 7844 * @hide Only for internal use by views and widgets. 7845 */ 7846 public void getHotspotBounds(Rect outRect) { 7847 final Drawable background = getBackground(); 7848 if (background != null) { 7849 background.getHotspotBounds(outRect); 7850 } else { 7851 getBoundsOnScreen(outRect); 7852 } 7853 } 7854 7855 /** 7856 * Request that a rectangle of this view be visible on the screen, 7857 * scrolling if necessary just enough. 7858 * 7859 * <p>A View should call this if it maintains some notion of which part 7860 * of its content is interesting. For example, a text editing view 7861 * should call this when its cursor moves. 7862 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7863 * It should not be affected by which part of the View is currently visible or its scroll 7864 * position. 7865 * 7866 * @param rectangle The rectangle in the View's content coordinate space 7867 * @return Whether any parent scrolled. 7868 */ 7869 public boolean requestRectangleOnScreen(Rect rectangle) { 7870 return requestRectangleOnScreen(rectangle, false); 7871 } 7872 7873 /** 7874 * Request that a rectangle of this view be visible on the screen, 7875 * scrolling if necessary just enough. 7876 * 7877 * <p>A View should call this if it maintains some notion of which part 7878 * of its content is interesting. For example, a text editing view 7879 * should call this when its cursor moves. 7880 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7881 * It should not be affected by which part of the View is currently visible or its scroll 7882 * position. 7883 * <p>When <code>immediate</code> is set to true, scrolling will not be 7884 * animated. 7885 * 7886 * @param rectangle The rectangle in the View's content coordinate space 7887 * @param immediate True to forbid animated scrolling, false otherwise 7888 * @return Whether any parent scrolled. 7889 */ 7890 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7891 if (mParent == null) { 7892 return false; 7893 } 7894 7895 View child = this; 7896 7897 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7898 position.set(rectangle); 7899 7900 ViewParent parent = mParent; 7901 boolean scrolled = false; 7902 while (parent != null) { 7903 rectangle.set((int) position.left, (int) position.top, 7904 (int) position.right, (int) position.bottom); 7905 7906 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7907 7908 if (!(parent instanceof View)) { 7909 break; 7910 } 7911 7912 // move it from child's content coordinate space to parent's content coordinate space 7913 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 7914 7915 child = (View) parent; 7916 parent = child.getParent(); 7917 } 7918 7919 return scrolled; 7920 } 7921 7922 /** 7923 * Called when this view wants to give up focus. If focus is cleared 7924 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 7925 * <p> 7926 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 7927 * to the first focusable View from the top after focus is cleared. Hence, if this 7928 * View is the first from the top that can take focus, then all callbacks 7929 * related to clearing focus will be invoked after which the framework will 7930 * give focus to this view. 7931 * </p> 7932 */ 7933 public void clearFocus() { 7934 if (DBG) { 7935 System.out.println(this + " clearFocus()"); 7936 } 7937 7938 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 7939 clearFocusInternal(null, true, refocus); 7940 } 7941 7942 /** 7943 * Clears focus from the view, optionally propagating the change up through 7944 * the parent hierarchy and requesting that the root view place new focus. 7945 * 7946 * @param propagate whether to propagate the change up through the parent 7947 * hierarchy 7948 * @param refocus when propagate is true, specifies whether to request the 7949 * root view place new focus 7950 */ 7951 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 7952 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 7953 mPrivateFlags &= ~PFLAG_FOCUSED; 7954 clearParentsWantFocus(); 7955 7956 if (propagate && mParent != null) { 7957 mParent.clearChildFocus(this); 7958 } 7959 7960 onFocusChanged(false, 0, null); 7961 refreshDrawableState(); 7962 7963 if (propagate && (!refocus || !rootViewRequestFocus())) { 7964 notifyGlobalFocusCleared(this); 7965 } 7966 } 7967 } 7968 7969 void notifyGlobalFocusCleared(View oldFocus) { 7970 if (oldFocus != null && mAttachInfo != null) { 7971 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 7972 } 7973 } 7974 7975 boolean rootViewRequestFocus() { 7976 final View root = getRootView(); 7977 return root != null && root.requestFocus(); 7978 } 7979 7980 /** 7981 * Called internally by the view system when a new view is getting focus. 7982 * This is what clears the old focus. 7983 * <p> 7984 * <b>NOTE:</b> The parent view's focused child must be updated manually 7985 * after calling this method. Otherwise, the view hierarchy may be left in 7986 * an inconstent state. 7987 */ 7988 void unFocus(View focused) { 7989 if (DBG) { 7990 System.out.println(this + " unFocus()"); 7991 } 7992 7993 clearFocusInternal(focused, false, false); 7994 } 7995 7996 /** 7997 * Returns true if this view has focus itself, or is the ancestor of the 7998 * view that has focus. 7999 * 8000 * @return True if this view has or contains focus, false otherwise. 8001 */ 8002 @ViewDebug.ExportedProperty(category = "focus") 8003 public boolean hasFocus() { 8004 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8005 } 8006 8007 /** 8008 * Returns true if this view is focusable or if it contains a reachable View 8009 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 8010 * is a view whose parents do not block descendants focus. 8011 * Only {@link #VISIBLE} views are considered focusable. 8012 * 8013 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8014 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8015 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8016 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8017 * {@code false} for views not explicitly marked as focusable. 8018 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8019 * behavior.</p> 8020 * 8021 * @return {@code true} if the view is focusable or if the view contains a focusable 8022 * view, {@code false} otherwise 8023 * 8024 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8025 * @see ViewGroup#getTouchscreenBlocksFocus() 8026 * @see #hasExplicitFocusable() 8027 */ 8028 public boolean hasFocusable() { 8029 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8030 } 8031 8032 /** 8033 * Returns true if this view is focusable or if it contains a reachable View 8034 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8035 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8036 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8037 * {@link #FOCUSABLE} are considered focusable. 8038 * 8039 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8040 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8041 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8042 * to focusable will not.</p> 8043 * 8044 * @return {@code true} if the view is focusable or if the view contains a focusable 8045 * view, {@code false} otherwise 8046 * 8047 * @see #hasFocusable() 8048 */ 8049 public boolean hasExplicitFocusable() { 8050 return hasFocusable(false, true); 8051 } 8052 8053 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8054 if (!isFocusableInTouchMode()) { 8055 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8056 final ViewGroup g = (ViewGroup) p; 8057 if (g.shouldBlockFocusForTouchscreen()) { 8058 return false; 8059 } 8060 } 8061 } 8062 8063 // Invisible, gone, or disabled views are never focusable. 8064 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8065 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8066 return false; 8067 } 8068 8069 // Only use effective focusable value when allowed. 8070 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8071 return true; 8072 } 8073 8074 return false; 8075 } 8076 8077 /** 8078 * Called by the view system when the focus state of this view changes. 8079 * When the focus change event is caused by directional navigation, direction 8080 * and previouslyFocusedRect provide insight into where the focus is coming from. 8081 * When overriding, be sure to call up through to the super class so that 8082 * the standard focus handling will occur. 8083 * 8084 * @param gainFocus True if the View has focus; false otherwise. 8085 * @param direction The direction focus has moved when requestFocus() 8086 * is called to give this view focus. Values are 8087 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8088 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8089 * It may not always apply, in which case use the default. 8090 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8091 * system, of the previously focused view. If applicable, this will be 8092 * passed in as finer grained information about where the focus is coming 8093 * from (in addition to direction). Will be <code>null</code> otherwise. 8094 */ 8095 @CallSuper 8096 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8097 @Nullable Rect previouslyFocusedRect) { 8098 if (gainFocus) { 8099 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8100 } else { 8101 notifyViewAccessibilityStateChangedIfNeeded( 8102 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8103 } 8104 8105 // Here we check whether we still need the default focus highlight, and switch it on/off. 8106 switchDefaultFocusHighlight(); 8107 8108 if (!gainFocus) { 8109 if (isPressed()) { 8110 setPressed(false); 8111 } 8112 if (hasWindowFocus()) { 8113 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8114 } 8115 onFocusLost(); 8116 } else if (hasWindowFocus()) { 8117 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8118 } 8119 8120 invalidate(true); 8121 ListenerInfo li = mListenerInfo; 8122 if (li != null && li.mOnFocusChangeListener != null) { 8123 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8124 } 8125 8126 if (mAttachInfo != null) { 8127 mAttachInfo.mKeyDispatchState.reset(this); 8128 } 8129 8130 if (mParent != null) { 8131 mParent.onDescendantUnbufferedRequested(); 8132 } 8133 8134 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8135 } 8136 8137 /** 8138 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8139 * 8140 * @param hasFocus {@code true} when the {@link View} is being focused. 8141 */ 8142 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8143 if (mAttachInfo == null) { 8144 return; 8145 } 8146 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8147 } 8148 8149 /** @hide */ 8150 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8151 if (canNotifyAutofillEnterExitEvent()) { 8152 AutofillManager afm = getAutofillManager(); 8153 if (afm != null) { 8154 if (enter && isFocused()) { 8155 // We have not been laid out yet, hence cannot evaluate 8156 // whether this view is visible to the user, we will do 8157 // the evaluation once layout is complete. 8158 if (!isLaidOut()) { 8159 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8160 } else if (isVisibleToUser()) { 8161 // TODO This is a potential problem that View gets focus before it's visible 8162 // to User. Ideally View should handle the event when isVisibleToUser() 8163 // becomes true where it should issue notifyViewEntered(). 8164 afm.notifyViewEntered(this); 8165 } 8166 } else if (!enter && !isFocused()) { 8167 afm.notifyViewExited(this); 8168 } 8169 } 8170 } 8171 } 8172 8173 /** 8174 * Visually distinct portion of a window with window-like semantics are considered panes for 8175 * accessibility purposes. One example is the content view of a fragment that is replaced. 8176 * In order for accessibility services to understand a pane's window-like behavior, panes 8177 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 8178 * when they appear, disappear, or change title. 8179 * 8180 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8181 * View is not a pane. 8182 * 8183 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8184 * 8185 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8186 */ 8187 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8188 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8189 mAccessibilityPaneTitle = accessibilityPaneTitle; 8190 notifyViewAccessibilityStateChangedIfNeeded( 8191 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8192 } 8193 } 8194 8195 /** 8196 * Get the title of the pane for purposes of accessibility. 8197 * 8198 * @return The current pane title. 8199 * 8200 * {@see #setAccessibilityPaneTitle}. 8201 * 8202 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8203 */ 8204 @InspectableProperty 8205 @Nullable 8206 public CharSequence getAccessibilityPaneTitle() { 8207 return mAccessibilityPaneTitle; 8208 } 8209 8210 private boolean isAccessibilityPane() { 8211 return mAccessibilityPaneTitle != null; 8212 } 8213 8214 /** 8215 * Sends an accessibility event of the given type. If accessibility is 8216 * not enabled this method has no effect. The default implementation calls 8217 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8218 * to populate information about the event source (this View), then calls 8219 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8220 * populate the text content of the event source including its descendants, 8221 * and last calls 8222 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8223 * on its parent to request sending of the event to interested parties. 8224 * <p> 8225 * If an {@link AccessibilityDelegate} has been specified via calling 8226 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8227 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8228 * responsible for handling this call. 8229 * </p> 8230 * 8231 * @param eventType The type of the event to send, as defined by several types from 8232 * {@link android.view.accessibility.AccessibilityEvent}, such as 8233 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 8234 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8235 * 8236 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8237 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8238 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8239 * @see AccessibilityDelegate 8240 */ 8241 public void sendAccessibilityEvent(int eventType) { 8242 if (mAccessibilityDelegate != null) { 8243 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8244 } else { 8245 sendAccessibilityEventInternal(eventType); 8246 } 8247 } 8248 8249 /** 8250 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8251 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8252 * specified text to its users. 8253 * <p> 8254 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8255 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8256 * accurately supplying the semantics of their UI. 8257 * They should not need to specify what exactly is announced to users. 8258 * 8259 * @param text The announcement text. 8260 */ 8261 public void announceForAccessibility(CharSequence text) { 8262 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8263 AccessibilityEvent event = AccessibilityEvent.obtain( 8264 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8265 onInitializeAccessibilityEvent(event); 8266 event.getText().add(text); 8267 event.setContentDescription(null); 8268 mParent.requestSendAccessibilityEvent(this, event); 8269 } 8270 } 8271 8272 /** 8273 * @see #sendAccessibilityEvent(int) 8274 * 8275 * Note: Called from the default {@link AccessibilityDelegate}. 8276 * 8277 * @hide 8278 */ 8279 public void sendAccessibilityEventInternal(int eventType) { 8280 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8281 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8282 } 8283 } 8284 8285 /** 8286 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8287 * takes as an argument an empty {@link AccessibilityEvent} and does not 8288 * perform a check whether accessibility is enabled. 8289 * <p> 8290 * If an {@link AccessibilityDelegate} has been specified via calling 8291 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8292 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8293 * is responsible for handling this call. 8294 * </p> 8295 * 8296 * @param event The event to send. 8297 * 8298 * @see #sendAccessibilityEvent(int) 8299 */ 8300 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8301 if (mAccessibilityDelegate != null) { 8302 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8303 } else { 8304 sendAccessibilityEventUncheckedInternal(event); 8305 } 8306 } 8307 8308 /** 8309 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8310 * 8311 * Note: Called from the default {@link AccessibilityDelegate}. 8312 * 8313 * @hide 8314 */ 8315 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8316 // Panes disappearing are relevant even if though the view is no longer visible. 8317 boolean isWindowStateChanged = 8318 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8319 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8320 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8321 boolean detached = detached(); 8322 if (!isShown() && !isWindowDisappearedEvent && !detached) { 8323 return; 8324 } 8325 onInitializeAccessibilityEvent(event); 8326 // Only a subset of accessibility events populates text content. 8327 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8328 dispatchPopulateAccessibilityEvent(event); 8329 } 8330 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 8331 if (throttle != null) { 8332 throttle.post(event); 8333 } else if (!isWindowDisappearedEvent && detached) { 8334 // Views could be attached soon later. Accessibility events during this temporarily 8335 // detached period should be sent too. 8336 postDelayed(() -> { 8337 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 8338 requestParentSendAccessibilityEvent(event); 8339 } 8340 }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 8341 } else { 8342 requestParentSendAccessibilityEvent(event); 8343 } 8344 } 8345 8346 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 8347 ViewParent parent = getParent(); 8348 if (parent != null) { 8349 getParent().requestSendAccessibilityEvent(this, event); 8350 } 8351 } 8352 8353 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 8354 AccessibilityEvent event) { 8355 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 8356 if (mSendViewScrolledAccessibilityEvent == null) { 8357 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 8358 } 8359 return mSendViewScrolledAccessibilityEvent; 8360 } 8361 boolean isStateContentChanged = (event.getContentChangeTypes() 8362 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 8363 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 8364 && isStateContentChanged) { 8365 if (mSendStateChangedAccessibilityEvent == null) { 8366 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 8367 } 8368 return mSendStateChangedAccessibilityEvent; 8369 } 8370 return null; 8371 } 8372 8373 private void clearAccessibilityThrottles() { 8374 cancel(mSendViewScrolledAccessibilityEvent); 8375 cancel(mSendStateChangedAccessibilityEvent); 8376 } 8377 8378 /** 8379 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8380 * to its children for adding their text content to the event. Note that the 8381 * event text is populated in a separate dispatch path since we add to the 8382 * event not only the text of the source but also the text of all its descendants. 8383 * A typical implementation will call 8384 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8385 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8386 * on each child. Override this method if custom population of the event text 8387 * content is required. 8388 * <p> 8389 * If an {@link AccessibilityDelegate} has been specified via calling 8390 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8391 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8392 * is responsible for handling this call. 8393 * </p> 8394 * <p> 8395 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8396 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8397 * </p> 8398 * 8399 * @param event The event. 8400 * 8401 * @return True if the event population was completed. 8402 */ 8403 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8404 if (mAccessibilityDelegate != null) { 8405 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8406 } else { 8407 return dispatchPopulateAccessibilityEventInternal(event); 8408 } 8409 } 8410 8411 /** 8412 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8413 * 8414 * Note: Called from the default {@link AccessibilityDelegate}. 8415 * 8416 * @hide 8417 */ 8418 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8419 onPopulateAccessibilityEvent(event); 8420 return false; 8421 } 8422 8423 /** 8424 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8425 * giving a chance to this View to populate the accessibility event with its 8426 * text content. While this method is free to modify event 8427 * attributes other than text content, doing so should normally be performed in 8428 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8429 * <p> 8430 * Example: Adding formatted date string to an accessibility event in addition 8431 * to the text added by the super implementation: 8432 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8433 * super.onPopulateAccessibilityEvent(event); 8434 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8435 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8436 * mCurrentDate.getTimeInMillis(), flags); 8437 * event.getText().add(selectedDateUtterance); 8438 * }</pre> 8439 * <p> 8440 * If an {@link AccessibilityDelegate} has been specified via calling 8441 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8442 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8443 * is responsible for handling this call. 8444 * </p> 8445 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8446 * information to the event, in case the default implementation has basic information to add. 8447 * </p> 8448 * 8449 * @param event The accessibility event which to populate. 8450 * 8451 * @see #sendAccessibilityEvent(int) 8452 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8453 */ 8454 @CallSuper 8455 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8456 if (mAccessibilityDelegate != null) { 8457 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8458 } else { 8459 onPopulateAccessibilityEventInternal(event); 8460 } 8461 } 8462 8463 /** 8464 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8465 * 8466 * Note: Called from the default {@link AccessibilityDelegate}. 8467 * 8468 * @hide 8469 */ 8470 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8471 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8472 && isAccessibilityPane()) { 8473 event.getText().add(getAccessibilityPaneTitle()); 8474 } 8475 } 8476 8477 /** 8478 * Initializes an {@link AccessibilityEvent} with information about 8479 * this View which is the event source. In other words, the source of 8480 * an accessibility event is the view whose state change triggered firing 8481 * the event. 8482 * <p> 8483 * Example: Setting the password property of an event in addition 8484 * to properties set by the super implementation: 8485 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8486 * super.onInitializeAccessibilityEvent(event); 8487 * event.setPassword(true); 8488 * }</pre> 8489 * <p> 8490 * If an {@link AccessibilityDelegate} has been specified via calling 8491 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8492 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8493 * is responsible for handling this call. 8494 * </p> 8495 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8496 * information to the event, in case the default implementation has basic information to add. 8497 * </p> 8498 * @param event The event to initialize. 8499 * 8500 * @see #sendAccessibilityEvent(int) 8501 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8502 */ 8503 @CallSuper 8504 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8505 if (mAccessibilityDelegate != null) { 8506 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8507 } else { 8508 onInitializeAccessibilityEventInternal(event); 8509 } 8510 } 8511 8512 /** 8513 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8514 * 8515 * Note: Called from the default {@link AccessibilityDelegate}. 8516 * 8517 * @hide 8518 */ 8519 @UnsupportedAppUsage 8520 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8521 event.setSource(this); 8522 event.setClassName(getAccessibilityClassName()); 8523 event.setPackageName(getContext().getPackageName()); 8524 event.setEnabled(isEnabled()); 8525 event.setContentDescription(mContentDescription); 8526 event.setScrollX(getScrollX()); 8527 event.setScrollY(getScrollY()); 8528 8529 switch (event.getEventType()) { 8530 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8531 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8532 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8533 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8534 event.setItemCount(focusablesTempList.size()); 8535 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8536 if (mAttachInfo != null) { 8537 focusablesTempList.clear(); 8538 } 8539 } break; 8540 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8541 CharSequence text = getIterableTextForAccessibility(); 8542 if (text != null && text.length() > 0) { 8543 event.setFromIndex(getAccessibilitySelectionStart()); 8544 event.setToIndex(getAccessibilitySelectionEnd()); 8545 event.setItemCount(text.length()); 8546 } 8547 } break; 8548 } 8549 } 8550 8551 /** 8552 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8553 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8554 * This method is responsible for obtaining an accessibility node info from a 8555 * pool of reusable instances and calling 8556 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8557 * initialize the former. 8558 * <p> 8559 * Note: The client is responsible for recycling the obtained instance by calling 8560 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8561 * </p> 8562 * 8563 * @return A populated {@link AccessibilityNodeInfo}. 8564 * 8565 * @see AccessibilityNodeInfo 8566 */ 8567 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8568 if (mAccessibilityDelegate != null) { 8569 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8570 } else { 8571 return createAccessibilityNodeInfoInternal(); 8572 } 8573 } 8574 8575 /** 8576 * @see #createAccessibilityNodeInfo() 8577 * 8578 * @hide 8579 */ 8580 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8581 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8582 if (provider != null) { 8583 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8584 } else { 8585 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8586 onInitializeAccessibilityNodeInfo(info); 8587 return info; 8588 } 8589 } 8590 8591 /** 8592 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8593 * The base implementation sets: 8594 * <ul> 8595 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8596 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8597 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8598 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8599 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8600 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8601 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8602 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8603 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8604 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8605 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8606 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8607 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8608 * </ul> 8609 * <p> 8610 * Subclasses should override this method, call the super implementation, 8611 * and set additional attributes. 8612 * </p> 8613 * <p> 8614 * If an {@link AccessibilityDelegate} has been specified via calling 8615 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8616 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8617 * is responsible for handling this call. 8618 * </p> 8619 * 8620 * @param info The instance to initialize. 8621 */ 8622 @CallSuper 8623 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8624 if (mAccessibilityDelegate != null) { 8625 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8626 } else { 8627 onInitializeAccessibilityNodeInfoInternal(info); 8628 } 8629 } 8630 8631 /** 8632 * Gets the location of this view in screen coordinates. 8633 * 8634 * @param outRect The output location 8635 * @hide 8636 */ 8637 @UnsupportedAppUsage 8638 public void getBoundsOnScreen(Rect outRect) { 8639 getBoundsOnScreen(outRect, false); 8640 } 8641 8642 /** 8643 * Gets the location of this view in screen coordinates. 8644 * 8645 * @param outRect The output location 8646 * @param clipToParent Whether to clip child bounds to the parent ones. 8647 * @hide 8648 */ 8649 @UnsupportedAppUsage 8650 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 8651 if (mAttachInfo == null) { 8652 return; 8653 } 8654 8655 RectF position = mAttachInfo.mTmpTransformRect; 8656 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8657 mapRectFromViewToScreenCoords(position, clipToParent); 8658 outRect.set(Math.round(position.left), Math.round(position.top), 8659 Math.round(position.right), Math.round(position.bottom)); 8660 } 8661 8662 /** 8663 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8664 * 8665 * @param rect The rectangle to be mapped 8666 * @param clipToParent Whether to clip child bounds to the parent ones. 8667 * @hide 8668 */ 8669 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8670 if (!hasIdentityMatrix()) { 8671 getMatrix().mapRect(rect); 8672 } 8673 8674 rect.offset(mLeft, mTop); 8675 8676 ViewParent parent = mParent; 8677 while (parent instanceof View) { 8678 View parentView = (View) parent; 8679 8680 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 8681 8682 if (clipToParent) { 8683 rect.left = Math.max(rect.left, 0); 8684 rect.top = Math.max(rect.top, 0); 8685 rect.right = Math.min(rect.right, parentView.getWidth()); 8686 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 8687 } 8688 8689 if (!parentView.hasIdentityMatrix()) { 8690 parentView.getMatrix().mapRect(rect); 8691 } 8692 8693 rect.offset(parentView.mLeft, parentView.mTop); 8694 8695 parent = parentView.mParent; 8696 } 8697 8698 if (parent instanceof ViewRootImpl) { 8699 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 8700 rect.offset(0, -viewRootImpl.mCurScrollY); 8701 } 8702 8703 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8704 } 8705 8706 /** 8707 * Return the class name of this object to be used for accessibility purposes. 8708 * Subclasses should only override this if they are implementing something that 8709 * should be seen as a completely new class of view when used by accessibility, 8710 * unrelated to the class it is deriving from. This is used to fill in 8711 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 8712 */ 8713 public CharSequence getAccessibilityClassName() { 8714 return View.class.getName(); 8715 } 8716 8717 /** 8718 * Called when assist structure is being retrieved from a view as part of 8719 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 8720 * @param structure Fill in with structured view data. The default implementation 8721 * fills in all data that can be inferred from the view itself. 8722 */ 8723 public void onProvideStructure(ViewStructure structure) { 8724 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 8725 } 8726 8727 /** 8728 * Populates a {@link ViewStructure} to fullfil an autofill request. 8729 * 8730 * <p>The structure should contain at least the following properties: 8731 * <ul> 8732 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 8733 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 8734 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 8735 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 8736 * </ul> 8737 * 8738 * <p>It's also recommended to set the following properties - the more properties the structure 8739 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 8740 * using the structure: 8741 * 8742 * <ul> 8743 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 8744 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 8745 * view can only be filled with predefined values (typically used when the autofill type 8746 * is {@link #AUTOFILL_TYPE_LIST}). 8747 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 8748 * <li>Class name ({@link ViewStructure#setClassName(String)}). 8749 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 8750 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 8751 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 8752 * opacity ({@link ViewStructure#setOpaque(boolean)}). 8753 * <li>For views representing text fields, text properties such as the text itself 8754 * ({@link ViewStructure#setText(CharSequence)}), text hints 8755 * ({@link ViewStructure#setHint(CharSequence)}, input type 8756 * ({@link ViewStructure#setInputType(int)}), 8757 * <li>For views representing HTML nodes, its web domain 8758 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 8759 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 8760 * </ul> 8761 * 8762 * <p>The default implementation of this method already sets most of these properties based on 8763 * related {@link View} methods (for example, the autofill id is set using 8764 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 8765 * and views in the standard Android widgets library also override it to set their 8766 * relevant properties (for example, {@link android.widget.TextView} already sets the text 8767 * properties), so it's recommended to only override this method 8768 * (and call {@code super.onProvideAutofillStructure()}) when: 8769 * 8770 * <ul> 8771 * <li>The view contents does not include PII (Personally Identifiable Information), so it 8772 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 8773 * <li>The view can only be autofilled with predefined options, so it can call 8774 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 8775 * </ul> 8776 * 8777 * <p><b>Note:</b> The {@code left} and {@code top} values set in 8778 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 8779 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 8780 * 8781 * <p>Views support the Autofill Framework mainly by: 8782 * <ul> 8783 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8784 * <li>Notifying the Android System when the view value changed by calling 8785 * {@link AutofillManager#notifyValueChanged(View)}. 8786 * <li>Implementing the methods that autofill the view. 8787 * </ul> 8788 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 8789 * for the latter. 8790 * 8791 * @param structure fill in with structured view data for autofill purposes. 8792 * @param flags optional flags. 8793 * 8794 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8795 */ 8796 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 8797 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 8798 } 8799 8800 /** 8801 * Populates a {@link ViewStructure} for content capture. 8802 * 8803 * <p>This method is called after a view that is eligible for content capture 8804 * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is 8805 * enabled for the user, and the activity rendering the view is enabled for content capture) 8806 * is laid out and is visible. The populated structure is then passed to the service through 8807 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 8808 * 8809 * <p>The default implementation of this method sets the most relevant properties based on 8810 * related {@link View} methods, and views in the standard Android widgets library also 8811 * override it to set their relevant properties. Therefore, if overriding this method, it 8812 * is recommended to call {@code super.onProvideContentCaptureStructure()}. 8813 * 8814 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 8815 * the node representing this view and return right away, then asynchronously report (not 8816 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 8817 * changed by calling 8818 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 8819 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 8820 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 8821 * respectively. The structure for a child must be created using 8822 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 8823 * {@code autofillId} for a child can be obtained either through 8824 * {@code childStructure.getAutofillId()} or 8825 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 8826 * 8827 * <p>When the virtual view hierarchy represents a web page, you should also: 8828 * 8829 * <ul> 8830 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 8831 * capture events should be generate for that URL. 8832 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 8833 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 8834 * that subtree. 8835 * </ul> 8836 * 8837 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 8838 * <ul> 8839 * <li>{@link ViewStructure#setChildCount(int)} 8840 * <li>{@link ViewStructure#addChildCount(int)} 8841 * <li>{@link ViewStructure#getChildCount()} 8842 * <li>{@link ViewStructure#newChild(int)} 8843 * <li>{@link ViewStructure#asyncNewChild(int)} 8844 * <li>{@link ViewStructure#asyncCommit()} 8845 * <li>{@link ViewStructure#setWebDomain(String)} 8846 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 8847 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 8848 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 8849 * <li>{@link ViewStructure#setAlpha(float)} 8850 * <li>{@link ViewStructure#setElevation(float)} 8851 * <li>{@link ViewStructure#setTransformation(Matrix)} 8852 * 8853 * </ul> 8854 */ 8855 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 8856 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 8857 } 8858 8859 /** @hide */ 8860 protected void onProvideStructure(@NonNull ViewStructure structure, 8861 @ViewStructureType int viewFor, int flags) { 8862 final int id = mID; 8863 if (id != NO_ID && !isViewIdGenerated(id)) { 8864 String pkg, type, entry; 8865 try { 8866 final Resources res = getResources(); 8867 entry = res.getResourceEntryName(id); 8868 type = res.getResourceTypeName(id); 8869 pkg = res.getResourcePackageName(id); 8870 } catch (Resources.NotFoundException e) { 8871 entry = type = pkg = null; 8872 } 8873 structure.setId(id, pkg, type, entry); 8874 } else { 8875 structure.setId(id, null, null, null); 8876 } 8877 8878 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8879 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 8880 final @AutofillType int autofillType = getAutofillType(); 8881 // Don't need to fill autofill info if view does not support it. 8882 // For example, only TextViews that are editable support autofill 8883 if (autofillType != AUTOFILL_TYPE_NONE) { 8884 structure.setAutofillType(autofillType); 8885 structure.setAutofillHints(getAutofillHints()); 8886 structure.setAutofillValue(getAutofillValue()); 8887 } 8888 structure.setImportantForAutofill(getImportantForAutofill()); 8889 structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); 8890 } 8891 8892 int ignoredParentLeft = 0; 8893 int ignoredParentTop = 0; 8894 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8895 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 8896 View parentGroup = null; 8897 8898 ViewParent viewParent = getParent(); 8899 if (viewParent instanceof View) { 8900 parentGroup = (View) viewParent; 8901 } 8902 8903 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 8904 ignoredParentLeft += parentGroup.mLeft; 8905 ignoredParentTop += parentGroup.mTop; 8906 8907 viewParent = parentGroup.getParent(); 8908 if (viewParent instanceof View) { 8909 parentGroup = (View) viewParent; 8910 } else { 8911 break; 8912 } 8913 } 8914 } 8915 8916 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 8917 mRight - mLeft, mBottom - mTop); 8918 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 8919 if (!hasIdentityMatrix()) { 8920 structure.setTransformation(getMatrix()); 8921 } 8922 structure.setElevation(getZ()); 8923 } 8924 structure.setVisibility(getVisibility()); 8925 structure.setEnabled(isEnabled()); 8926 if (isClickable()) { 8927 structure.setClickable(true); 8928 } 8929 if (isFocusable()) { 8930 structure.setFocusable(true); 8931 } 8932 if (isFocused()) { 8933 structure.setFocused(true); 8934 } 8935 if (isAccessibilityFocused()) { 8936 structure.setAccessibilityFocused(true); 8937 } 8938 if (isSelected()) { 8939 structure.setSelected(true); 8940 } 8941 if (isActivated()) { 8942 structure.setActivated(true); 8943 } 8944 if (isLongClickable()) { 8945 structure.setLongClickable(true); 8946 } 8947 if (this instanceof Checkable) { 8948 structure.setCheckable(true); 8949 if (((Checkable)this).isChecked()) { 8950 structure.setChecked(true); 8951 } 8952 } 8953 if (isOpaque()) { 8954 structure.setOpaque(true); 8955 } 8956 if (isContextClickable()) { 8957 structure.setContextClickable(true); 8958 } 8959 structure.setClassName(getAccessibilityClassName().toString()); 8960 structure.setContentDescription(getContentDescription()); 8961 } 8962 8963 /** 8964 * Called when assist structure is being retrieved from a view as part of 8965 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 8966 * generate additional virtual structure under this view. The default implementation 8967 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 8968 * view's virtual accessibility nodes, if any. You can override this for a more 8969 * optimal implementation providing this data. 8970 */ 8971 public void onProvideVirtualStructure(ViewStructure structure) { 8972 onProvideVirtualStructureCompat(structure, false); 8973 } 8974 8975 /** 8976 * Fallback implementation to populate a ViewStructure from accessibility state. 8977 * 8978 * @param structure The structure to populate. 8979 * @param forAutofill Whether the structure is needed for autofill. 8980 */ 8981 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 8982 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8983 if (provider != null) { 8984 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8985 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 8986 } 8987 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 8988 structure.setChildCount(1); 8989 final ViewStructure root = structure.newChild(0); 8990 populateVirtualStructure(root, provider, info, forAutofill); 8991 info.recycle(); 8992 } 8993 } 8994 8995 /** 8996 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 8997 * request. 8998 * 8999 * <p>This method should be used when the view manages a virtual structure under this view. For 9000 * example, a view that draws input fields using {@link #draw(Canvas)}. 9001 * 9002 * <p>When implementing this method, subclasses must follow the rules below: 9003 * 9004 * <ul> 9005 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 9006 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 9007 * identifying the children in the virtual structure. 9008 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 9009 * exclude intermediate levels that are irrelevant for autofill; that would improve the 9010 * autofill performance. 9011 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 9012 * children. 9013 * <li>Set the autofill properties of the child structure as defined by 9014 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 9015 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 9016 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 9017 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 9018 * when the focused virtual child changed. 9019 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9020 * whether a given virtual view is visible to the user in order to support triggering 9021 * save when all views of interest go away. 9022 * <li>Call 9023 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9024 * when the value of a virtual child changed. 9025 * <li>Call {@link 9026 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9027 * when the visibility of a virtual child changed. 9028 * <li>Call 9029 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9030 * child is clicked. 9031 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9032 * changed and the current context should be committed (for example, when the user tapped 9033 * a {@code SUBMIT} button in an HTML page). 9034 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9035 * changed and the current context should be canceled (for example, when the user tapped 9036 * a {@code CANCEL} button in an HTML page). 9037 * <li>Provide ways for users to manually request autofill by calling 9038 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9039 * <li>The {@code left} and {@code top} values set in 9040 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9041 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9042 * structure. 9043 * </ul> 9044 * 9045 * <p>Views with virtual children support the Autofill Framework mainly by: 9046 * <ul> 9047 * <li>Providing the metadata defining what the virtual children mean and how they can be 9048 * autofilled. 9049 * <li>Implementing the methods that autofill the virtual children. 9050 * </ul> 9051 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9052 * for the latter. 9053 * 9054 * @param structure fill in with virtual children data for autofill purposes. 9055 * @param flags optional flags. 9056 * 9057 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9058 */ 9059 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9060 if (mContext.isAutofillCompatibilityEnabled()) { 9061 onProvideVirtualStructureCompat(structure, true); 9062 } 9063 } 9064 9065 /** 9066 * Sets the listener to be {@link #performReceiveContent used} to handle insertion of 9067 * content into this view. 9068 * 9069 * <p>Depending on the type of view, this listener may be invoked for different scenarios. For 9070 * example, for an editable {@link android.widget.TextView}, this listener will be invoked for 9071 * the following scenarios: 9072 * <ol> 9073 * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the 9074 * insertion/selection menu) 9075 * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent}) 9076 * <li>Drag and drop (drop events from {@link #onDragEvent}) 9077 * <li>Autofill 9078 * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT} 9079 * </ol> 9080 * 9081 * <p>When setting a listener, clients must also declare the accepted MIME types. 9082 * The listener will still be invoked even if the MIME type of the content is not one of the 9083 * declared MIME types (e.g. if the user pastes content whose type is not one of the declared 9084 * MIME types). 9085 * In that case, the listener may reject the content (defer to the default platform behavior) 9086 * or execute some other fallback logic (e.g. show an appropriate message to the user). 9087 * The declared MIME types serve as a hint to allow different features to optionally alter 9088 * their behavior. For example, a soft keyboard may optionally choose to hide its UI for 9089 * inserting GIFs for a particular input field if the MIME types set here for that field 9090 * don't include "image/gif" or "image/*". 9091 * 9092 * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC 9093 * MIME types. As a result, you should always write your MIME types with lowercase letters, 9094 * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9095 * lowercase. 9096 * 9097 * @param mimeTypes The MIME types accepted by the given listener. These may use patterns 9098 * such as "image/*", but may not start with a wildcard. This argument must 9099 * not be null or empty if a non-null listener is passed in. 9100 * @param listener The listener to use. This can be null to reset to the default behavior. 9101 */ 9102 public void setOnReceiveContentListener( 9103 @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, 9104 @Nullable OnReceiveContentListener listener) { 9105 if (listener != null) { 9106 Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, 9107 "When the listener is set, MIME types must also be set"); 9108 } 9109 if (mimeTypes != null) { 9110 Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")), 9111 "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes)); 9112 } 9113 mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; 9114 getListenerInfo().mOnReceiveContentListener = listener; 9115 } 9116 9117 /** 9118 * Receives the given content. If no listener is set, invokes {@link #onReceiveContent}. If a 9119 * listener is {@link #setOnReceiveContentListener set}, invokes the listener instead; if the 9120 * listener returns a non-null result, invokes {@link #onReceiveContent} to handle it. 9121 * 9122 * @param payload The content to insert and related metadata. 9123 * 9124 * @return The portion of the passed-in content that was not accepted (may be all, some, or none 9125 * of the passed-in content). 9126 */ 9127 @Nullable performReceiveContent(@onNull ContentInfo payload)9128 public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { 9129 final OnReceiveContentListener listener = (mListenerInfo == null) ? null 9130 : getListenerInfo().mOnReceiveContentListener; 9131 if (listener != null) { 9132 final ContentInfo remaining = listener.onReceiveContent(this, payload); 9133 return (remaining == null) ? null : onReceiveContent(remaining); 9134 } 9135 return onReceiveContent(payload); 9136 } 9137 9138 /** 9139 * Implements the default behavior for receiving content for this type of view. The default 9140 * view implementation is a no-op (returns the passed-in content without acting on it). 9141 * 9142 * <p>Widgets should override this method to define their default behavior for receiving 9143 * content. Apps should {@link #setOnReceiveContentListener set a listener} to provide 9144 * app-specific handling for receiving content. 9145 * 9146 * <p>See {@link #setOnReceiveContentListener} and {@link #performReceiveContent} for more info. 9147 * 9148 * @param payload The content to insert and related metadata. 9149 * 9150 * @return The portion of the passed-in content that was not handled (may be all, some, or none 9151 * of the passed-in content). 9152 */ 9153 @Nullable onReceiveContent(@onNull ContentInfo payload)9154 public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { 9155 return payload; 9156 } 9157 9158 /** 9159 * Returns the MIME types accepted by {@link #performReceiveContent} for this view, as 9160 * configured via {@link #setOnReceiveContentListener}. By default returns null. 9161 * 9162 * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft 9163 * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For 9164 * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular 9165 * input field if the MIME types returned here for that field don't include "image/gif" or 9166 * "image/*". 9167 * 9168 * <p>Note: Comparisons of MIME types should be performed using utilities such as 9169 * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to 9170 * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching 9171 * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result, 9172 * you should always write your MIME types with lowercase letters, or use 9173 * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9174 * lowercase. 9175 * 9176 * @return The MIME types accepted by {@link #performReceiveContent} for this view (may 9177 * include patterns such as "image/*"). 9178 */ 9179 @SuppressLint("NullableCollection") 9180 @Nullable getReceiveContentMimeTypes()9181 public String[] getReceiveContentMimeTypes() { 9182 return mReceiveContentMimeTypes; 9183 } 9184 9185 /** 9186 * Automatically fills the content of this view with the {@code value}. 9187 * 9188 * <p>Views support the Autofill Framework mainly by: 9189 * <ul> 9190 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9191 * <li>Implementing the methods that autofill the view. 9192 * </ul> 9193 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 9194 * this method is responsible for latter. 9195 * 9196 * <p>This method does nothing by default, but when overridden it typically: 9197 * <ol> 9198 * <li>Checks if the provided value matches the expected type (which is defined by 9199 * {@link #getAutofillType()}). 9200 * <li>Checks if the view is editable - if it isn't, it should return right away. 9201 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 9202 * <li>Pass the actual value to the equivalent setter in the view. 9203 * </ol> 9204 * 9205 * <p>For example, a text-field view could implement the method this way: 9206 * 9207 * <pre class="prettyprint"> 9208 * @Override 9209 * public void autofill(AutofillValue value) { 9210 * if (!value.isText() || !this.isEditable()) { 9211 * return; 9212 * } 9213 * CharSequence text = value.getTextValue(); 9214 * if (text != null) { 9215 * this.setText(text); 9216 * } 9217 * } 9218 * </pre> 9219 * 9220 * <p>If the value is updated asynchronously, the next call to 9221 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 9222 * changed to the autofilled value. If not, the view will not be considered autofilled. 9223 * 9224 * <p><b>Note:</b> After this method is called, the value returned by 9225 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 9226 * view will not be highlighted as autofilled. 9227 * 9228 * @param value value to be autofilled. 9229 */ autofill(@uppressWarningsR) AutofillValue value)9230 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 9231 } 9232 9233 /** 9234 * Automatically fills the content of the virtual children within this view. 9235 * 9236 * <p>Views with virtual children support the Autofill Framework mainly by: 9237 * <ul> 9238 * <li>Providing the metadata defining what the virtual children mean and how they can be 9239 * autofilled. 9240 * <li>Implementing the methods that autofill the virtual children. 9241 * </ul> 9242 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 9243 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 9244 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 9245 * 9246 * <p>If a child value is updated asynchronously, the next call to 9247 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 9248 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 9249 * considered autofilled. 9250 * 9251 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 9252 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 9253 * changes. 9254 * 9255 * @param values map of values to be autofilled, keyed by virtual child id. 9256 * 9257 * @attr ref android.R.styleable#Theme_autofilledHighlight 9258 */ autofill(@onNull @uppressWarningsR) SparseArray<AutofillValue> values)9259 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 9260 if (!mContext.isAutofillCompatibilityEnabled()) { 9261 return; 9262 } 9263 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9264 if (provider == null) { 9265 return; 9266 } 9267 final int valueCount = values.size(); 9268 for (int i = 0; i < valueCount; i++) { 9269 final AutofillValue value = values.valueAt(i); 9270 if (value.isText()) { 9271 final int virtualId = values.keyAt(i); 9272 final CharSequence text = value.getTextValue(); 9273 final Bundle arguments = new Bundle(); 9274 arguments.putCharSequence( 9275 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 9276 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 9277 } 9278 } 9279 } 9280 9281 /** 9282 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 9283 * 9284 * <p>The autofill id is created on demand, unless it is explicitly set by 9285 * {@link #setAutofillId(AutofillId)}. 9286 * 9287 * <p>See {@link #setAutofillId(AutofillId)} for more info. 9288 * 9289 * @return The View's autofill id. 9290 */ getAutofillId()9291 public final AutofillId getAutofillId() { 9292 if (mAutofillId == null) { 9293 // The autofill id needs to be unique, but its value doesn't matter, 9294 // so it's better to reuse the accessibility id to save space. 9295 mAutofillId = new AutofillId(getAutofillViewId()); 9296 } 9297 return mAutofillId; 9298 } 9299 9300 /** 9301 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 9302 * 9303 * <p>The autofill id is created on demand, and this method should only be called when a view is 9304 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 9305 * that method creates a snapshot of the view that is passed along to the autofill service. 9306 * 9307 * <p>This method is typically used when view subtrees are recycled to represent different 9308 * content* —in this case, the autofill id can be saved before the view content is swapped 9309 * out, and restored later when it's swapped back in. For example: 9310 * 9311 * <pre> 9312 * EditText reusableView = ...; 9313 * ViewGroup parentView = ...; 9314 * AutofillManager afm = ...; 9315 * 9316 * // Swap out the view and change its contents 9317 * AutofillId oldId = reusableView.getAutofillId(); 9318 * CharSequence oldText = reusableView.getText(); 9319 * parentView.removeView(reusableView); 9320 * AutofillId newId = afm.getNextAutofillId(); 9321 * reusableView.setText("New I am"); 9322 * reusableView.setAutofillId(newId); 9323 * parentView.addView(reusableView); 9324 * 9325 * // Later, swap the old content back in 9326 * parentView.removeView(reusableView); 9327 * reusableView.setAutofillId(oldId); 9328 * reusableView.setText(oldText); 9329 * parentView.addView(reusableView); 9330 * </pre> 9331 * 9332 * <p>NOTE: If this view is a descendant of an {@link android.widget.AdapterView}, the system 9333 * may reset its autofill id when this view is recycled. If the autofill ids need to be stable, 9334 * they should be set again in 9335 * {@link android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)}. 9336 * 9337 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 9338 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 9339 * obtained through {@link #getAutofillId()}), or a new value obtained through 9340 * {@link AutofillManager#getNextAutofillId()}. 9341 * 9342 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 9343 * a window}. 9344 * 9345 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 9346 */ setAutofillId(@ullable AutofillId id)9347 public void setAutofillId(@Nullable AutofillId id) { 9348 // TODO(b/37566627): add unit / CTS test for all possible combinations below 9349 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9350 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 9351 } 9352 if (isAttachedToWindow()) { 9353 throw new IllegalStateException("Cannot set autofill id when view is attached"); 9354 } 9355 if (id != null && !id.isNonVirtual()) { 9356 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 9357 } 9358 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 9359 // Ignore reset because it was never explicitly set before. 9360 return; 9361 } 9362 mAutofillId = id; 9363 if (id != null) { 9364 mAutofillViewId = id.getViewId(); 9365 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9366 } else { 9367 mAutofillViewId = NO_ID; 9368 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9369 } 9370 } 9371 9372 /** 9373 * Forces a reset of the autofill ids of the subtree rooted at this view. Like calling 9374 * {@link #setAutofillId(AutofillId) setAutofillId(null)} for each view, but works even if the 9375 * views are attached to a window. 9376 * 9377 * <p>This is useful if the views are being recycled, since an autofill id should uniquely 9378 * identify a particular piece of content. 9379 * 9380 * @hide 9381 */ resetSubtreeAutofillIds()9382 public void resetSubtreeAutofillIds() { 9383 if (mAutofillViewId == NO_ID) { 9384 return; 9385 } 9386 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9387 Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9388 } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9389 Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9390 } 9391 mAutofillId = null; 9392 mAutofillViewId = NO_ID; 9393 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9394 } 9395 9396 /** 9397 * Describes the autofill type of this view, so an 9398 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 9399 * when autofilling the view. 9400 * 9401 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 9402 * support the Autofill Framework. 9403 * 9404 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 9405 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 9406 * 9407 * @see #onProvideAutofillStructure(ViewStructure, int) 9408 * @see #autofill(AutofillValue) 9409 */ getAutofillType()9410 public @AutofillType int getAutofillType() { 9411 return AUTOFILL_TYPE_NONE; 9412 } 9413 9414 /** 9415 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 9416 * to autofill the view with the user's data. 9417 * 9418 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 9419 * 9420 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 9421 * {@code null} if no hints were set. 9422 * 9423 * @attr ref android.R.styleable#View_autofillHints 9424 */ 9425 @ViewDebug.ExportedProperty() 9426 @InspectableProperty getAutofillHints()9427 @Nullable public String[] getAutofillHints() { 9428 return mAutofillHints; 9429 } 9430 9431 /** 9432 * @hide 9433 */ 9434 @TestApi isAutofilled()9435 public boolean isAutofilled() { 9436 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 9437 } 9438 9439 /** 9440 * @hide 9441 */ hideAutofillHighlight()9442 public boolean hideAutofillHighlight() { 9443 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 9444 } 9445 9446 /** 9447 * Gets the {@link View}'s current autofill value. 9448 * 9449 * <p>By default returns {@code null}, but subclasses should override it and return an 9450 * appropriate value to properly support the Autofill Framework. 9451 * 9452 * @see #onProvideAutofillStructure(ViewStructure, int) 9453 * @see #autofill(AutofillValue) 9454 */ 9455 @Nullable getAutofillValue()9456 public AutofillValue getAutofillValue() { 9457 return null; 9458 } 9459 9460 /** 9461 * Gets the mode for determining whether this view is important for autofill. 9462 * 9463 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 9464 * info about this mode. 9465 * 9466 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 9467 * {@link #setImportantForAutofill(int)}. 9468 * 9469 * @attr ref android.R.styleable#View_importantForAutofill 9470 */ 9471 @ViewDebug.ExportedProperty(mapping = { 9472 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 9473 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 9474 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 9475 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9476 to = "yesExcludeDescendants"), 9477 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9478 to = "noExcludeDescendants")}) 9479 @InspectableProperty(enumMapping = { 9480 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 9481 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 9482 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 9483 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9484 name = "yesExcludeDescendants"), 9485 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9486 name = "noExcludeDescendants"), 9487 }) getImportantForAutofill()9488 public @AutofillImportance int getImportantForAutofill() { 9489 return (mPrivateFlags3 9490 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 9491 } 9492 9493 /** 9494 * Sets the mode for determining whether this view is considered important for autofill. 9495 * 9496 * <p>The platform determines the importance for autofill automatically but you 9497 * can use this method to customize the behavior. For example: 9498 * 9499 * <ol> 9500 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 9501 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 9502 * <li>When both the view and its children are irrelevant for autofill (for example, the root 9503 * view of an activity containing a spreadhseet editor), it should be 9504 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9505 * <li>When the view content is relevant for autofill but its children aren't (for example, 9506 * a credit card expiration date represented by a custom view that overrides the proper 9507 * autofill methods and has 2 children representing the month and year), it should 9508 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 9509 * </ol> 9510 * 9511 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9512 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 9513 * children) will be always be considered not important; for example, when the user explicitly 9514 * makes an autofill request, all views are considered important. See 9515 * {@link #isImportantForAutofill()} for more details about how the View's importance for 9516 * autofill is used. 9517 * 9518 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 9519 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 9520 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9521 * 9522 * @attr ref android.R.styleable#View_importantForAutofill 9523 */ setImportantForAutofill(@utofillImportance int mode)9524 public void setImportantForAutofill(@AutofillImportance int mode) { 9525 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9526 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 9527 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9528 } 9529 9530 /** 9531 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 9532 * associated with this view is considered important for autofill purposes. 9533 * 9534 * <p>Generally speaking, a view is important for autofill if: 9535 * <ol> 9536 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 9537 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 9538 * determine how other views can be autofilled. 9539 * <ol> 9540 * 9541 * <p>For example, view containers should typically return {@code false} for performance reasons 9542 * (since the important info is provided by their children), but if its properties have relevant 9543 * information (for example, a resource id called {@code credentials}, it should return 9544 * {@code true}. On the other hand, views representing labels or editable fields should 9545 * typically return {@code true}, but in some cases they could return {@code false} 9546 * (for example, if they're part of a "Captcha" mechanism). 9547 * 9548 * <p>The value returned by this method depends on the value returned by 9549 * {@link #getImportantForAutofill()}: 9550 * 9551 * <ol> 9552 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 9553 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 9554 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9555 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 9556 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 9557 * that can return {@code true} in some cases (like a container with a resource id), 9558 * but {@code false} in most. 9559 * <li>otherwise, it returns {@code false}. 9560 * </ol> 9561 * 9562 * <p>When a view is considered important for autofill: 9563 * <ul> 9564 * <li>The view might automatically trigger an autofill request when focused on. 9565 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 9566 * request. 9567 * </ul> 9568 * 9569 * <p>On the other hand, when a view is considered not important for autofill: 9570 * <ul> 9571 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 9572 * request through {@link AutofillManager#requestAutofill(View)}. 9573 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 9574 * autofill request, unless the request has the 9575 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9576 * </ul> 9577 * 9578 * @return whether the view is considered important for autofill. 9579 * 9580 * @see #setImportantForAutofill(int) 9581 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9582 * @see #IMPORTANT_FOR_AUTOFILL_YES 9583 * @see #IMPORTANT_FOR_AUTOFILL_NO 9584 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9585 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9586 * @see AutofillManager#requestAutofill(View) 9587 */ isImportantForAutofill()9588 public final boolean isImportantForAutofill() { 9589 // Check parent mode to ensure we're not hidden. 9590 ViewParent parent = mParent; 9591 while (parent instanceof View) { 9592 final int parentImportance = ((View) parent).getImportantForAutofill(); 9593 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9594 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9595 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9596 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9597 + "because parent " + parent + "'s importance is " + parentImportance); 9598 } 9599 return false; 9600 } 9601 parent = parent.getParent(); 9602 } 9603 9604 final int importance = getImportantForAutofill(); 9605 9606 // First, check the explicit states. 9607 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9608 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9609 return true; 9610 } 9611 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9612 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9613 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9614 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9615 + "because its importance is " + importance); 9616 } 9617 return false; 9618 } 9619 9620 // Then use some heuristics to handle AUTO. 9621 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9622 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9623 + this); 9624 return false; 9625 } 9626 9627 // Always include views that have an explicit resource id. 9628 final int id = mID; 9629 if (id != NO_ID && !isViewIdGenerated(id)) { 9630 final Resources res = getResources(); 9631 String entry = null; 9632 String pkg = null; 9633 try { 9634 entry = res.getResourceEntryName(id); 9635 pkg = res.getResourcePackageName(id); 9636 } catch (Resources.NotFoundException e) { 9637 // ignore 9638 } 9639 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9640 return true; 9641 } 9642 } 9643 9644 // If the app developer explicitly set hints for it, it's important. 9645 if (getAutofillHints() != null) { 9646 return true; 9647 } 9648 9649 // Otherwise, assume it's not important... 9650 return false; 9651 } 9652 9653 /** 9654 * Gets the mode for determining whether this view is important for content capture. 9655 * 9656 * <p>See {@link #setImportantForContentCapture(int)} and 9657 * {@link #isImportantForContentCapture()} for more info about this mode. 9658 * 9659 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 9660 * {@link #setImportantForContentCapture(int)}. 9661 * 9662 * @attr ref android.R.styleable#View_importantForContentCapture 9663 */ 9664 @ViewDebug.ExportedProperty(mapping = { 9665 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 9666 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 9667 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 9668 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9669 to = "yesExcludeDescendants"), 9670 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9671 to = "noExcludeDescendants")}) 9672 @InspectableProperty(enumMapping = { 9673 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 9674 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 9675 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 9676 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9677 name = "yesExcludeDescendants"), 9678 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9679 name = "noExcludeDescendants"), 9680 }) getImportantForContentCapture()9681 public @ContentCaptureImportance int getImportantForContentCapture() { 9682 // NOTE: the important for content capture values were the first flags added and are set in 9683 // the rightmost position, so we don't need to shift them 9684 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9685 } 9686 9687 /** 9688 * Sets the mode for determining whether this view is considered important for content capture. 9689 * 9690 * <p>The platform determines the importance for autofill automatically but you 9691 * can use this method to customize the behavior. Typically, a view that provides text should 9692 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 9693 * 9694 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 9695 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 9696 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 9697 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 9698 * 9699 * @attr ref android.R.styleable#View_importantForContentCapture 9700 */ setImportantForContentCapture(@ontentCaptureImportance int mode)9701 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 9702 // Reset first 9703 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9704 // Then set again 9705 // NOTE: the important for content capture values were the first flags added and are set in 9706 // the rightmost position, so we don't need to shift them 9707 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 9708 } 9709 9710 /** 9711 * Hints the Android System whether this view is considered important for content capture, based 9712 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 9713 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 9714 * 9715 * <p>See {@link ContentCaptureManager} for more info about content capture. 9716 * 9717 * @return whether the view is considered important for content capture. 9718 * 9719 * @see #setImportantForContentCapture(int) 9720 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 9721 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 9722 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 9723 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9724 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9725 */ isImportantForContentCapture()9726 public final boolean isImportantForContentCapture() { 9727 boolean isImportant; 9728 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 9729 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 9730 return isImportant; 9731 } 9732 9733 isImportant = calculateIsImportantForContentCapture(); 9734 9735 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9736 if (isImportant) { 9737 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9738 } 9739 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 9740 return isImportant; 9741 } 9742 9743 /** 9744 * Calculates whether the flag is important for content capture so it can be used by 9745 * {@link #isImportantForContentCapture()} while the tree is traversed. 9746 */ calculateIsImportantForContentCapture()9747 private boolean calculateIsImportantForContentCapture() { 9748 // Check parent mode to ensure we're important 9749 ViewParent parent = mParent; 9750 while (parent instanceof View) { 9751 final int parentImportance = ((View) parent).getImportantForContentCapture(); 9752 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9753 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 9754 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9755 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 9756 + "content capture because parent " + parent + "'s importance is " 9757 + parentImportance); 9758 } 9759 return false; 9760 } 9761 parent = parent.getParent(); 9762 } 9763 9764 final int importance = getImportantForContentCapture(); 9765 9766 // First, check the explicit states. 9767 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9768 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 9769 return true; 9770 } 9771 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9772 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 9773 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9774 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 9775 + "capture because its importance is " + importance); 9776 } 9777 return false; 9778 } 9779 9780 // Then use some heuristics to handle AUTO. 9781 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 9782 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 9783 + " on view " + this); 9784 return false; 9785 } 9786 9787 // View group is important if at least one children also is 9788 if (this instanceof ViewGroup) { 9789 final ViewGroup group = (ViewGroup) this; 9790 for (int i = 0; i < group.getChildCount(); i++) { 9791 final View child = group.getChildAt(i); 9792 if (child.isImportantForContentCapture()) { 9793 return true; 9794 } 9795 } 9796 } 9797 9798 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 9799 if (getAutofillHints() != null) { 9800 return true; 9801 } 9802 9803 // Otherwise, assume it's not important... 9804 return false; 9805 } 9806 9807 /** 9808 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 9809 * added, based on whether it's laid out and visible, and without knowing if the parent removed 9810 * it from the view hierarchy. 9811 * 9812 * <p>This method is called from many places (visibility changed, view laid out, view attached 9813 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 9814 * described below: 9815 * 9816 * <ol> 9817 * <li>It should only be called when content capture is enabled for the view. 9818 * <li>It must call viewAppeared() before viewDisappeared() 9819 * <li>viewAppearead() can only be called when the view is visible and laidout 9820 * <li>It should not call the same event twice. 9821 * </ol> 9822 */ notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared)9823 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 9824 AttachInfo ai = mAttachInfo; 9825 // Skip it while the view is being laid out for the first time 9826 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 9827 9828 // First check if context has client, so it saves a service lookup when it doesn't 9829 if (mContext.getContentCaptureOptions() == null) return; 9830 9831 if (appeared) { 9832 // The appeared event stops sending to AiAi. 9833 // 1. The view is hidden. 9834 // 2. The same event was sent. 9835 // 3. The view is not laid out, and it will be laid out in the future. 9836 // Some recycled views cached its layout and a relayout is unnecessary. In this case, 9837 // system still needs to notify content capture the view appeared. When a view is 9838 // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED. 9839 final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() 9840 && getVisibility() == VISIBLE 9841 && !isLayoutRequested(); 9842 if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() 9843 || !(isLaidOut() || isRecycledWithoutRelayout)) { 9844 if (DEBUG_CONTENT_CAPTURE) { 9845 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 9846 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9847 + ", visible=" + (getVisibility() == VISIBLE) 9848 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 9849 + ", alreadyNotifiedDisappeared=" 9850 + getNotifiedContentCaptureDisappeared()); 9851 } 9852 return; 9853 } 9854 } else { 9855 if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { 9856 if (DEBUG_CONTENT_CAPTURE) { 9857 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 9858 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9859 + ", visible=" + (getVisibility() == VISIBLE) 9860 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 9861 + ", alreadyNotifiedDisappeared=" 9862 + getNotifiedContentCaptureDisappeared()); 9863 } 9864 return; 9865 } 9866 } 9867 9868 ContentCaptureSession session = getContentCaptureSession(); 9869 if (session == null) return; 9870 9871 // ... and finally at the view level 9872 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 9873 if (!isImportantForContentCapture()) return; 9874 9875 if (appeared) { 9876 setNotifiedContentCaptureAppeared(); 9877 9878 if (ai != null) { 9879 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9880 } else { 9881 if (DEBUG_CONTENT_CAPTURE) { 9882 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 9883 } 9884 } 9885 } else { 9886 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9887 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9888 9889 if (ai != null) { 9890 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9891 } else { 9892 if (DEBUG_CONTENT_CAPTURE) { 9893 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 9894 } 9895 } 9896 } 9897 } 9898 setNotifiedContentCaptureAppeared()9899 private void setNotifiedContentCaptureAppeared() { 9900 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9901 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9902 } 9903 9904 /** @hide */ getNotifiedContentCaptureAppeared()9905 protected boolean getNotifiedContentCaptureAppeared() { 9906 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 9907 } 9908 9909 getNotifiedContentCaptureDisappeared()9910 private boolean getNotifiedContentCaptureDisappeared() { 9911 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; 9912 } 9913 9914 /** 9915 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 9916 * 9917 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 9918 * the content capture events associated with this view or its view hierarchy (if it's a 9919 * {@link ViewGroup}). 9920 * 9921 * <p>For example, if your activity is associated with a web domain, first you would need to 9922 * set the context for the main DOM: 9923 * 9924 * <pre> 9925 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 9926 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 9927 * </pre> 9928 * 9929 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 9930 * 9931 * <pre> 9932 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 9933 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 9934 * iframeView.setContentCaptureSession(iframeSession); 9935 * </pre> 9936 * 9937 * @param contentCaptureSession a session created by 9938 * {@link ContentCaptureSession#createContentCaptureSession( 9939 * android.view.contentcapture.ContentCaptureContext)}. 9940 */ setContentCaptureSession(@ullable ContentCaptureSession contentCaptureSession)9941 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 9942 mContentCaptureSession = contentCaptureSession; 9943 } 9944 9945 /** 9946 * Gets the session used to notify content capture events. 9947 * 9948 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 9949 * inherited by ancestors, default session or {@code null} if content capture is disabled for 9950 * this view. 9951 */ 9952 @Nullable getContentCaptureSession()9953 public final ContentCaptureSession getContentCaptureSession() { 9954 if (mContentCaptureSessionCached) { 9955 return mContentCaptureSession; 9956 } 9957 9958 mContentCaptureSession = getAndCacheContentCaptureSession(); 9959 mContentCaptureSessionCached = true; 9960 return mContentCaptureSession; 9961 } 9962 9963 @Nullable getAndCacheContentCaptureSession()9964 private ContentCaptureSession getAndCacheContentCaptureSession() { 9965 // First try the session explicitly set by setContentCaptureSession() 9966 if (mContentCaptureSession != null) { 9967 return mContentCaptureSession; 9968 } 9969 9970 // Then the session explicitly set in an ancestor 9971 ContentCaptureSession session = null; 9972 if (mParent instanceof View) { 9973 session = ((View) mParent).getContentCaptureSession(); 9974 } 9975 9976 // Finally, if no session was explicitly set, use the context's default session. 9977 if (session == null) { 9978 final ContentCaptureManager ccm = mContext 9979 .getSystemService(ContentCaptureManager.class); 9980 return ccm == null ? null : ccm.getMainContentCaptureSession(); 9981 } 9982 return session; 9983 } 9984 9985 @Nullable getAutofillManager()9986 private AutofillManager getAutofillManager() { 9987 return mContext.getSystemService(AutofillManager.class); 9988 } 9989 isAutofillable()9990 private boolean isAutofillable() { 9991 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 9992 9993 if (!isImportantForAutofill()) { 9994 // View is not important for "regular" autofill, so we must check if Augmented Autofill 9995 // is enabled for the activity 9996 final AutofillOptions options = mContext.getAutofillOptions(); 9997 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 9998 return false; 9999 } 10000 final AutofillManager afm = getAutofillManager(); 10001 if (afm == null) return false; 10002 afm.notifyViewEnteredForAugmentedAutofill(this); 10003 } 10004 10005 return getAutofillViewId() > LAST_APP_AUTOFILL_ID; 10006 } 10007 10008 /** @hide */ canNotifyAutofillEnterExitEvent()10009 public boolean canNotifyAutofillEnterExitEvent() { 10010 return isAutofillable() && isAttachedToWindow(); 10011 } 10012 populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutofill)10013 private void populateVirtualStructure(ViewStructure structure, 10014 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 10015 boolean forAutofill) { 10016 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 10017 null, null, info.getViewIdResourceName()); 10018 Rect rect = structure.getTempRect(); 10019 info.getBoundsInParent(rect); 10020 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 10021 structure.setVisibility(VISIBLE); 10022 structure.setEnabled(info.isEnabled()); 10023 if (info.isClickable()) { 10024 structure.setClickable(true); 10025 } 10026 if (info.isFocusable()) { 10027 structure.setFocusable(true); 10028 } 10029 if (info.isFocused()) { 10030 structure.setFocused(true); 10031 } 10032 if (info.isAccessibilityFocused()) { 10033 structure.setAccessibilityFocused(true); 10034 } 10035 if (info.isSelected()) { 10036 structure.setSelected(true); 10037 } 10038 if (info.isLongClickable()) { 10039 structure.setLongClickable(true); 10040 } 10041 if (info.isCheckable()) { 10042 structure.setCheckable(true); 10043 if (info.isChecked()) { 10044 structure.setChecked(true); 10045 } 10046 } 10047 if (info.isContextClickable()) { 10048 structure.setContextClickable(true); 10049 } 10050 if (forAutofill) { 10051 structure.setAutofillId(new AutofillId(getAutofillId(), 10052 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 10053 } 10054 CharSequence cname = info.getClassName(); 10055 structure.setClassName(cname != null ? cname.toString() : null); 10056 structure.setContentDescription(info.getContentDescription()); 10057 if (forAutofill) { 10058 final int maxTextLength = info.getMaxTextLength(); 10059 if (maxTextLength != -1) { 10060 structure.setMaxTextLength(maxTextLength); 10061 } 10062 structure.setHint(info.getHintText()); 10063 } 10064 CharSequence text = info.getText(); 10065 boolean hasText = text != null || info.getError() != null; 10066 if (hasText) { 10067 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 10068 } 10069 if (forAutofill) { 10070 if (info.isEditable()) { 10071 structure.setDataIsSensitive(true); 10072 if (hasText) { 10073 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 10074 structure.setAutofillValue(AutofillValue.forText(text)); 10075 } 10076 int inputType = info.getInputType(); 10077 if (inputType == 0 && info.isPassword()) { 10078 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 10079 } 10080 structure.setInputType(inputType); 10081 } else { 10082 structure.setDataIsSensitive(false); 10083 } 10084 } 10085 final int NCHILDREN = info.getChildCount(); 10086 if (NCHILDREN > 0) { 10087 structure.setChildCount(NCHILDREN); 10088 for (int i=0; i<NCHILDREN; i++) { 10089 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 10090 == AccessibilityNodeProvider.HOST_VIEW_ID) { 10091 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 10092 continue; 10093 } 10094 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 10095 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 10096 if (cinfo != null) { 10097 ViewStructure child = structure.newChild(i); 10098 populateVirtualStructure(child, provider, cinfo, forAutofill); 10099 cinfo.recycle(); 10100 } 10101 } 10102 } 10103 } 10104 10105 /** 10106 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 10107 * implementation calls {@link #onProvideStructure} and 10108 * {@link #onProvideVirtualStructure}. 10109 */ dispatchProvideStructure(ViewStructure structure)10110 public void dispatchProvideStructure(ViewStructure structure) { 10111 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 10112 } 10113 10114 /** 10115 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 10116 * when an Assist structure is being created as part of an autofill request. 10117 * 10118 * <p>The default implementation does the following: 10119 * <ul> 10120 * <li>Sets the {@link AutofillId} in the structure. 10121 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 10122 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 10123 * </ul> 10124 * 10125 * <p>Typically, this method should only be overridden by subclasses that provide a view 10126 * hierarchy (such as {@link ViewGroup}) - other classes should override 10127 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 10128 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 10129 * 10130 * <p>When overridden, it must: 10131 * 10132 * <ul> 10133 * <li>Either call 10134 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 10135 * set the {@link AutofillId} in the structure (for example, by calling 10136 * {@code structure.setAutofillId(getAutofillId())}). 10137 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 10138 * set, all views in the structure should be considered important for autofill, 10139 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 10140 * respect this flag to provide a better user experience - this flag is typically used 10141 * when an user explicitly requested autofill. If the flag is not set, 10142 * then only views marked as important for autofill should be included in the 10143 * structure - skipping non-important views optimizes the overall autofill performance. 10144 * </ul> 10145 * 10146 * @param structure fill in with structured view data for autofill purposes. 10147 * @param flags optional flags. 10148 * 10149 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 10150 */ dispatchProvideAutofillStructure(@onNull ViewStructure structure, @AutofillFlags int flags)10151 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 10152 @AutofillFlags int flags) { 10153 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 10154 } 10155 dispatchProvideStructure(@onNull ViewStructure structure, @ViewStructureType int viewFor, @AutofillFlags int flags)10156 private void dispatchProvideStructure(@NonNull ViewStructure structure, 10157 @ViewStructureType int viewFor, @AutofillFlags int flags) { 10158 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 10159 structure.setAutofillId(getAutofillId()); 10160 onProvideAutofillStructure(structure, flags); 10161 onProvideAutofillVirtualStructure(structure, flags); 10162 } else if (!isAssistBlocked()) { 10163 onProvideStructure(structure); 10164 onProvideVirtualStructure(structure); 10165 } else { 10166 structure.setClassName(getAccessibilityClassName().toString()); 10167 structure.setAssistBlocked(true); 10168 } 10169 } 10170 10171 /** 10172 * Dispatches the initial content capture events for a view structure. 10173 * 10174 * @hide 10175 */ dispatchInitialProvideContentCaptureStructure()10176 public void dispatchInitialProvideContentCaptureStructure() { 10177 AttachInfo ai = mAttachInfo; 10178 if (ai == null) { 10179 Log.w(CONTENT_CAPTURE_LOG_TAG, 10180 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 10181 return; 10182 } 10183 ContentCaptureManager ccm = ai.mContentCaptureManager; 10184 if (ccm == null) { 10185 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 10186 + "no ContentCaptureManager for " + this); 10187 return; 10188 } 10189 10190 // We must set it before checkign if the view itself is important, because it might 10191 // initially not be (for example, if it's empty), although that might change later (for 10192 // example, if important views are added) 10193 ai.mReadyForContentCaptureUpdates = true; 10194 10195 if (!isImportantForContentCapture()) { 10196 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10197 Log.d(CONTENT_CAPTURE_LOG_TAG, 10198 "dispatchProvideContentCaptureStructure(): decorView is not important"); 10199 } 10200 return; 10201 } 10202 10203 ai.mContentCaptureManager = ccm; 10204 10205 ContentCaptureSession session = getContentCaptureSession(); 10206 if (session == null) { 10207 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10208 Log.d(CONTENT_CAPTURE_LOG_TAG, 10209 "dispatchProvideContentCaptureStructure(): no session for " + this); 10210 } 10211 return; 10212 } 10213 10214 session.internalNotifyViewTreeEvent(/* started= */ true); 10215 try { 10216 dispatchProvideContentCaptureStructure(); 10217 } finally { 10218 session.internalNotifyViewTreeEvent(/* started= */ false); 10219 } 10220 } 10221 10222 /** @hide */ dispatchProvideContentCaptureStructure()10223 void dispatchProvideContentCaptureStructure() { 10224 ContentCaptureSession session = getContentCaptureSession(); 10225 if (session != null) { 10226 ViewStructure structure = session.newViewStructure(this); 10227 onProvideContentCaptureStructure(structure, /* flags= */ 0); 10228 setNotifiedContentCaptureAppeared(); 10229 session.notifyViewAppeared(structure); 10230 } 10231 } 10232 10233 /** 10234 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 10235 * 10236 * Note: Called from the default {@link AccessibilityDelegate}. 10237 * 10238 * @hide 10239 */ onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)10240 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 10241 if (mAttachInfo == null) { 10242 return; 10243 } 10244 10245 Rect bounds = mAttachInfo.mTmpInvalRect; 10246 10247 getDrawingRect(bounds); 10248 info.setBoundsInParent(bounds); 10249 10250 getBoundsOnScreen(bounds, true); 10251 info.setBoundsInScreen(bounds); 10252 10253 ViewParent parent = getParentForAccessibility(); 10254 if (parent instanceof View) { 10255 info.setParent((View) parent); 10256 } 10257 10258 if (mID != View.NO_ID) { 10259 View rootView = getRootView(); 10260 if (rootView == null) { 10261 rootView = this; 10262 } 10263 10264 View label = rootView.findLabelForView(this, mID); 10265 if (label != null) { 10266 info.setLabeledBy(label); 10267 } 10268 10269 if ((mAttachInfo.mAccessibilityFetchFlags 10270 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 10271 && Resources.resourceHasPackage(mID)) { 10272 try { 10273 String viewId = getResources().getResourceName(mID); 10274 info.setViewIdResourceName(viewId); 10275 } catch (Resources.NotFoundException nfe) { 10276 /* ignore */ 10277 } 10278 } 10279 } 10280 10281 if (mLabelForId != View.NO_ID) { 10282 View rootView = getRootView(); 10283 if (rootView == null) { 10284 rootView = this; 10285 } 10286 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 10287 if (labeled != null) { 10288 info.setLabelFor(labeled); 10289 } 10290 } 10291 10292 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 10293 View rootView = getRootView(); 10294 if (rootView == null) { 10295 rootView = this; 10296 } 10297 View next = rootView.findViewInsideOutShouldExist(this, 10298 mAccessibilityTraversalBeforeId); 10299 if (next != null && next.includeForAccessibility()) { 10300 info.setTraversalBefore(next); 10301 } 10302 } 10303 10304 if (mAccessibilityTraversalAfterId != View.NO_ID) { 10305 View rootView = getRootView(); 10306 if (rootView == null) { 10307 rootView = this; 10308 } 10309 View next = rootView.findViewInsideOutShouldExist(this, 10310 mAccessibilityTraversalAfterId); 10311 if (next != null && next.includeForAccessibility()) { 10312 info.setTraversalAfter(next); 10313 } 10314 } 10315 10316 info.setVisibleToUser(isVisibleToUser()); 10317 10318 info.setImportantForAccessibility(isImportantForAccessibility()); 10319 info.setPackageName(mContext.getPackageName()); 10320 info.setClassName(getAccessibilityClassName()); 10321 info.setStateDescription(getStateDescription()); 10322 info.setContentDescription(getContentDescription()); 10323 10324 info.setEnabled(isEnabled()); 10325 info.setClickable(isClickable()); 10326 info.setFocusable(isFocusable()); 10327 info.setScreenReaderFocusable(isScreenReaderFocusable()); 10328 info.setFocused(isFocused()); 10329 info.setAccessibilityFocused(isAccessibilityFocused()); 10330 info.setSelected(isSelected()); 10331 info.setLongClickable(isLongClickable()); 10332 info.setContextClickable(isContextClickable()); 10333 info.setLiveRegion(getAccessibilityLiveRegion()); 10334 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 10335 info.setTooltipText(mTooltipInfo.mTooltipText); 10336 info.addAction((mTooltipInfo.mTooltipPopup == null) 10337 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 10338 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 10339 } 10340 10341 // TODO: These make sense only if we are in an AdapterView but all 10342 // views can be selected. Maybe from accessibility perspective 10343 // we should report as selectable view in an AdapterView. 10344 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 10345 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 10346 10347 if (isFocusable()) { 10348 if (isFocused()) { 10349 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 10350 } else { 10351 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 10352 } 10353 } 10354 10355 if (!isAccessibilityFocused()) { 10356 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 10357 } else { 10358 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 10359 } 10360 10361 if (isClickable() && isEnabled()) { 10362 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 10363 } 10364 10365 if (isLongClickable() && isEnabled()) { 10366 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 10367 } 10368 10369 if (isContextClickable() && isEnabled()) { 10370 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 10371 } 10372 10373 CharSequence text = getIterableTextForAccessibility(); 10374 if (text != null && text.length() > 0) { 10375 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 10376 10377 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 10378 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 10379 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 10380 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 10381 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 10382 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 10383 } 10384 10385 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 10386 populateAccessibilityNodeInfoDrawingOrderInParent(info); 10387 info.setPaneTitle(mAccessibilityPaneTitle); 10388 info.setHeading(isAccessibilityHeading()); 10389 10390 if (mTouchDelegate != null) { 10391 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 10392 } 10393 10394 if (startedSystemDragForAccessibility()) { 10395 info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); 10396 } 10397 10398 if (canAcceptAccessibilityDrop()) { 10399 info.addAction(AccessibilityAction.ACTION_DRAG_DROP); 10400 } 10401 } 10402 10403 10404 /** 10405 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 10406 * additional data. 10407 * <p> 10408 * This method only needs overloading if the node is marked as having extra data available. 10409 * </p> 10410 * 10411 * @param info The info to which to add the extra data. Never {@code null}. 10412 * @param extraDataKey A key specifying the type of extra data to add to the info. The 10413 * extra data should be added to the {@link Bundle} returned by 10414 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 10415 * {@code null}. 10416 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 10417 * {@code null} if the service provided no arguments. 10418 * 10419 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 10420 */ addExtraDataToAccessibilityNodeInfo( @onNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)10421 public void addExtraDataToAccessibilityNodeInfo( 10422 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 10423 @Nullable Bundle arguments) { 10424 } 10425 10426 /** 10427 * Determine the order in which this view will be drawn relative to its siblings for a11y 10428 * 10429 * @param info The info whose drawing order should be populated 10430 */ populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info)10431 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 10432 /* 10433 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 10434 * drawing order may not be well-defined, and some Views with custom drawing order may 10435 * not be initialized sufficiently to respond properly getChildDrawingOrder. 10436 */ 10437 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 10438 info.setDrawingOrder(0); 10439 return; 10440 } 10441 int drawingOrderInParent = 1; 10442 // Iterate up the hierarchy if parents are not important for a11y 10443 View viewAtDrawingLevel = this; 10444 final ViewParent parent = getParentForAccessibility(); 10445 while (viewAtDrawingLevel != parent) { 10446 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 10447 if (!(currentParent instanceof ViewGroup)) { 10448 // Should only happen for the Decor 10449 drawingOrderInParent = 0; 10450 break; 10451 } else { 10452 final ViewGroup parentGroup = (ViewGroup) currentParent; 10453 final int childCount = parentGroup.getChildCount(); 10454 if (childCount > 1) { 10455 List<View> preorderedList = parentGroup.buildOrderedChildList(); 10456 if (preorderedList != null) { 10457 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 10458 for (int i = 0; i < childDrawIndex; i++) { 10459 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 10460 } 10461 preorderedList.clear(); 10462 } else { 10463 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 10464 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 10465 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 10466 .getChildDrawingOrder(childCount, childIndex) : childIndex; 10467 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 10468 if (childDrawIndex != 0) { 10469 for (int i = 0; i < numChildrenToIterate; i++) { 10470 final int otherDrawIndex = (customOrder ? 10471 parentGroup.getChildDrawingOrder(childCount, i) : i); 10472 if (otherDrawIndex < childDrawIndex) { 10473 drawingOrderInParent += 10474 numViewsForAccessibility(parentGroup.getChildAt(i)); 10475 } 10476 } 10477 } 10478 } 10479 } 10480 } 10481 viewAtDrawingLevel = (View) currentParent; 10482 } 10483 info.setDrawingOrder(drawingOrderInParent); 10484 } 10485 numViewsForAccessibility(View view)10486 private static int numViewsForAccessibility(View view) { 10487 if (view != null) { 10488 if (view.includeForAccessibility()) { 10489 return 1; 10490 } else if (view instanceof ViewGroup) { 10491 return ((ViewGroup) view).getNumChildrenForAccessibility(); 10492 } 10493 } 10494 return 0; 10495 } 10496 findLabelForView(View view, int labeledId)10497 private View findLabelForView(View view, int labeledId) { 10498 if (mMatchLabelForPredicate == null) { 10499 mMatchLabelForPredicate = new MatchLabelForPredicate(); 10500 } 10501 mMatchLabelForPredicate.mLabeledId = labeledId; 10502 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 10503 } 10504 10505 /** 10506 * Computes whether this virtual autofill view is visible to the user. 10507 * 10508 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 10509 * view must override it. 10510 * 10511 * @return Whether the view is visible on the screen. 10512 */ isVisibleToUserForAutofill(int virtualId)10513 public boolean isVisibleToUserForAutofill(int virtualId) { 10514 if (mContext.isAutofillCompatibilityEnabled()) { 10515 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10516 if (provider != null) { 10517 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 10518 if (node != null) { 10519 return node.isVisibleToUser(); 10520 } 10521 // if node is null, assume it's not visible anymore 10522 } else { 10523 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 10524 } 10525 return false; 10526 } 10527 return true; 10528 } 10529 10530 /** 10531 * Computes whether this view is visible to the user. Such a view is 10532 * attached, visible, all its predecessors are visible, it is not clipped 10533 * entirely by its predecessors, and has an alpha greater than zero. 10534 * 10535 * @return Whether the view is visible on the screen. 10536 * 10537 * @hide 10538 */ 10539 @UnsupportedAppUsage isVisibleToUser()10540 public boolean isVisibleToUser() { 10541 return isVisibleToUser(null); 10542 } 10543 10544 /** 10545 * Computes whether the given portion of this view is visible to the user. 10546 * Such a view is attached, visible, all its predecessors are visible, 10547 * has an alpha greater than zero, and the specified portion is not 10548 * clipped entirely by its predecessors. 10549 * 10550 * @param boundInView the portion of the view to test; coordinates should be relative; may be 10551 * <code>null</code>, and the entire view will be tested in this case. 10552 * When <code>true</code> is returned by the function, the actual visible 10553 * region will be stored in this parameter; that is, if boundInView is fully 10554 * contained within the view, no modification will be made, otherwise regions 10555 * outside of the visible area of the view will be clipped. 10556 * 10557 * @return Whether the specified portion of the view is visible on the screen. 10558 * 10559 * @hide 10560 */ 10561 @UnsupportedAppUsage(trackingBug = 171933273) isVisibleToUser(Rect boundInView)10562 protected boolean isVisibleToUser(Rect boundInView) { 10563 if (mAttachInfo != null) { 10564 // Attached to invisible window means this view is not visible. 10565 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 10566 return false; 10567 } 10568 // An invisible predecessor or one with alpha zero means 10569 // that this view is not visible to the user. 10570 Object current = this; 10571 while (current instanceof View) { 10572 View view = (View) current; 10573 // We have attach info so this view is attached and there is no 10574 // need to check whether we reach to ViewRootImpl on the way up. 10575 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 10576 view.getVisibility() != VISIBLE) { 10577 return false; 10578 } 10579 current = view.mParent; 10580 } 10581 // Check if the view is entirely covered by its predecessors. 10582 Rect visibleRect = mAttachInfo.mTmpInvalRect; 10583 Point offset = mAttachInfo.mPoint; 10584 if (!getGlobalVisibleRect(visibleRect, offset)) { 10585 return false; 10586 } 10587 // Check if the visible portion intersects the rectangle of interest. 10588 if (boundInView != null) { 10589 visibleRect.offset(-offset.x, -offset.y); 10590 return boundInView.intersect(visibleRect); 10591 } 10592 return true; 10593 } 10594 return false; 10595 } 10596 10597 /** 10598 * Returns the delegate for implementing accessibility support via 10599 * composition. For more details see {@link AccessibilityDelegate}. 10600 * 10601 * @return The delegate, or null if none set. 10602 */ getAccessibilityDelegate()10603 public AccessibilityDelegate getAccessibilityDelegate() { 10604 return mAccessibilityDelegate; 10605 } 10606 10607 /** 10608 * Sets a delegate for implementing accessibility support via composition 10609 * (as opposed to inheritance). For more details, see 10610 * {@link AccessibilityDelegate}. 10611 * <p> 10612 * <strong>Note:</strong> On platform versions prior to 10613 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 10614 * views in the {@code android.widget.*} package are called <i>before</i> 10615 * host methods. This prevents certain properties such as class name from 10616 * being modified by overriding 10617 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 10618 * as any changes will be overwritten by the host class. 10619 * <p> 10620 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 10621 * methods are called <i>after</i> host methods, which all properties to be 10622 * modified without being overwritten by the host class. 10623 * 10624 * @param delegate the object to which accessibility method calls should be 10625 * delegated 10626 * @see AccessibilityDelegate 10627 */ setAccessibilityDelegate(@ullable AccessibilityDelegate delegate)10628 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 10629 mAccessibilityDelegate = delegate; 10630 } 10631 10632 /** 10633 * Gets the provider for managing a virtual view hierarchy rooted at this View 10634 * and reported to {@link android.accessibilityservice.AccessibilityService}s 10635 * that explore the window content. 10636 * <p> 10637 * If this method returns an instance, this instance is responsible for managing 10638 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 10639 * View including the one representing the View itself. Similarly the returned 10640 * instance is responsible for performing accessibility actions on any virtual 10641 * view or the root view itself. 10642 * </p> 10643 * <p> 10644 * If an {@link AccessibilityDelegate} has been specified via calling 10645 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10646 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 10647 * is responsible for handling this call. 10648 * </p> 10649 * 10650 * @return The provider. 10651 * 10652 * @see AccessibilityNodeProvider 10653 */ getAccessibilityNodeProvider()10654 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 10655 if (mAccessibilityDelegate != null) { 10656 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 10657 } else { 10658 return null; 10659 } 10660 } 10661 10662 /** 10663 * Gets the unique identifier of this view on the screen for accessibility purposes. 10664 * 10665 * @return The view accessibility id. 10666 * 10667 * @hide 10668 */ 10669 @UnsupportedAppUsage getAccessibilityViewId()10670 public int getAccessibilityViewId() { 10671 if (mAccessibilityViewId == NO_ID) { 10672 mAccessibilityViewId = sNextAccessibilityViewId++; 10673 } 10674 return mAccessibilityViewId; 10675 } 10676 10677 /** 10678 * Gets the unique identifier of this view on the screen for autofill purposes. 10679 * 10680 * @return The view autofill id. 10681 * 10682 * @hide 10683 */ getAutofillViewId()10684 public int getAutofillViewId() { 10685 if (mAutofillViewId == NO_ID) { 10686 mAutofillViewId = mContext.getNextAutofillId(); 10687 } 10688 return mAutofillViewId; 10689 } 10690 10691 /** 10692 * Gets the unique identifier of the window in which this View resides. 10693 * 10694 * @return The window accessibility id. 10695 * 10696 * @hide 10697 */ getAccessibilityWindowId()10698 public int getAccessibilityWindowId() { 10699 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 10700 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 10701 } 10702 10703 /** 10704 * Returns the {@link View}'s state description. 10705 * <p> 10706 * <strong>Note:</strong> Do not override this method, as it will have no 10707 * effect on the state description presented to accessibility services. 10708 * You must call {@link #setStateDescription(CharSequence)} to modify the 10709 * state description. 10710 * 10711 * @return the state description 10712 * @see #setStateDescription(CharSequence) 10713 */ 10714 @ViewDebug.ExportedProperty(category = "accessibility") getStateDescription()10715 public final @Nullable CharSequence getStateDescription() { 10716 return mStateDescription; 10717 } 10718 10719 /** 10720 * Returns the {@link View}'s content description. 10721 * <p> 10722 * <strong>Note:</strong> Do not override this method, as it will have no 10723 * effect on the content description presented to accessibility services. 10724 * You must call {@link #setContentDescription(CharSequence)} to modify the 10725 * content description. 10726 * 10727 * @return the content description 10728 * @see #setContentDescription(CharSequence) 10729 * @attr ref android.R.styleable#View_contentDescription 10730 */ 10731 @ViewDebug.ExportedProperty(category = "accessibility") 10732 @InspectableProperty getContentDescription()10733 public CharSequence getContentDescription() { 10734 return mContentDescription; 10735 } 10736 10737 /** 10738 * Sets the {@link View}'s state description. 10739 * <p> 10740 * A state description briefly describes the states of the view and is primarily used 10741 * for accessibility support to determine how the states of a view should be presented to 10742 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 10743 * it is used for customized state description (for example, "wifi, connected, three bars"). 10744 * State description changes frequently while content description should change less often. 10745 * State description should be localized. For android widgets which have default state 10746 * descriptions, app developers can call this method to override the state descriptions. 10747 * Setting state description to null restores the default behavior. 10748 * 10749 * @param stateDescription The state description. 10750 * @see #getStateDescription() 10751 */ 10752 @RemotableViewMethod setStateDescription(@ullable CharSequence stateDescription)10753 public void setStateDescription(@Nullable CharSequence stateDescription) { 10754 if (mStateDescription == null) { 10755 if (stateDescription == null) { 10756 return; 10757 } 10758 } else if (mStateDescription.equals(stateDescription)) { 10759 return; 10760 } 10761 mStateDescription = stateDescription; 10762 if (!TextUtils.isEmpty(stateDescription) 10763 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10764 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10765 } 10766 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10767 AccessibilityEvent event = AccessibilityEvent.obtain(); 10768 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 10769 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 10770 sendAccessibilityEventUnchecked(event); 10771 } 10772 } 10773 10774 /** 10775 * Sets the {@link View}'s content description. 10776 * <p> 10777 * A content description briefly describes the view and is primarily used 10778 * for accessibility support to determine how a view should be presented to 10779 * the user. In the case of a view with no textual representation, such as 10780 * {@link android.widget.ImageButton}, a useful content description 10781 * explains what the view does. For example, an image button with a phone 10782 * icon that is used to place a call may use "Call" as its content 10783 * description. An image of a floppy disk that is used to save a file may 10784 * use "Save". 10785 * 10786 * @param contentDescription The content description. 10787 * @see #getContentDescription() 10788 * @attr ref android.R.styleable#View_contentDescription 10789 */ 10790 @RemotableViewMethod setContentDescription(CharSequence contentDescription)10791 public void setContentDescription(CharSequence contentDescription) { 10792 if (mContentDescription == null) { 10793 if (contentDescription == null) { 10794 return; 10795 } 10796 } else if (mContentDescription.equals(contentDescription)) { 10797 return; 10798 } 10799 mContentDescription = contentDescription; 10800 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 10801 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10802 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10803 notifySubtreeAccessibilityStateChangedIfNeeded(); 10804 } else { 10805 notifyViewAccessibilityStateChangedIfNeeded( 10806 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 10807 } 10808 } 10809 10810 /** 10811 * Sets the id of a view before which this one is visited in accessibility traversal. 10812 * A screen-reader must visit the content of this view before the content of the one 10813 * it precedes. For example, if view B is set to be before view A, then a screen-reader 10814 * will traverse the entire content of B before traversing the entire content of A, 10815 * regardles of what traversal strategy it is using. 10816 * <p> 10817 * Views that do not have specified before/after relationships are traversed in order 10818 * determined by the screen-reader. 10819 * </p> 10820 * <p> 10821 * Setting that this view is before a view that is not important for accessibility 10822 * or if this view is not important for accessibility will have no effect as the 10823 * screen-reader is not aware of unimportant views. 10824 * </p> 10825 * 10826 * @param beforeId The id of a view this one precedes in accessibility traversal. 10827 * 10828 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 10829 * 10830 * @see #setImportantForAccessibility(int) 10831 */ 10832 @RemotableViewMethod setAccessibilityTraversalBefore(@dRes int beforeId)10833 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 10834 if (mAccessibilityTraversalBeforeId == beforeId) { 10835 return; 10836 } 10837 mAccessibilityTraversalBeforeId = beforeId; 10838 notifyViewAccessibilityStateChangedIfNeeded( 10839 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10840 } 10841 10842 /** 10843 * Gets the id of a view before which this one is visited in accessibility traversal. 10844 * 10845 * @return The id of a view this one precedes in accessibility traversal if 10846 * specified, otherwise {@link #NO_ID}. 10847 * 10848 * @see #setAccessibilityTraversalBefore(int) 10849 */ 10850 @IdRes 10851 @InspectableProperty getAccessibilityTraversalBefore()10852 public int getAccessibilityTraversalBefore() { 10853 return mAccessibilityTraversalBeforeId; 10854 } 10855 10856 /** 10857 * Sets the id of a view after which this one is visited in accessibility traversal. 10858 * A screen-reader must visit the content of the other view before the content of this 10859 * one. For example, if view B is set to be after view A, then a screen-reader 10860 * will traverse the entire content of A before traversing the entire content of B, 10861 * regardles of what traversal strategy it is using. 10862 * <p> 10863 * Views that do not have specified before/after relationships are traversed in order 10864 * determined by the screen-reader. 10865 * </p> 10866 * <p> 10867 * Setting that this view is after a view that is not important for accessibility 10868 * or if this view is not important for accessibility will have no effect as the 10869 * screen-reader is not aware of unimportant views. 10870 * </p> 10871 * 10872 * @param afterId The id of a view this one succedees in accessibility traversal. 10873 * 10874 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 10875 * 10876 * @see #setImportantForAccessibility(int) 10877 */ 10878 @RemotableViewMethod setAccessibilityTraversalAfter(@dRes int afterId)10879 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 10880 if (mAccessibilityTraversalAfterId == afterId) { 10881 return; 10882 } 10883 mAccessibilityTraversalAfterId = afterId; 10884 notifyViewAccessibilityStateChangedIfNeeded( 10885 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10886 } 10887 10888 /** 10889 * Gets the id of a view after which this one is visited in accessibility traversal. 10890 * 10891 * @return The id of a view this one succeedes in accessibility traversal if 10892 * specified, otherwise {@link #NO_ID}. 10893 * 10894 * @see #setAccessibilityTraversalAfter(int) 10895 */ 10896 @IdRes 10897 @InspectableProperty getAccessibilityTraversalAfter()10898 public int getAccessibilityTraversalAfter() { 10899 return mAccessibilityTraversalAfterId; 10900 } 10901 10902 /** 10903 * Gets the id of a view for which this view serves as a label for 10904 * accessibility purposes. 10905 * 10906 * @return The labeled view id. 10907 */ 10908 @IdRes 10909 @ViewDebug.ExportedProperty(category = "accessibility") 10910 @InspectableProperty getLabelFor()10911 public int getLabelFor() { 10912 return mLabelForId; 10913 } 10914 10915 /** 10916 * Sets the id of a view for which this view serves as a label for 10917 * accessibility purposes. 10918 * 10919 * @param id The labeled view id. 10920 */ 10921 @RemotableViewMethod setLabelFor(@dRes int id)10922 public void setLabelFor(@IdRes int id) { 10923 if (mLabelForId == id) { 10924 return; 10925 } 10926 mLabelForId = id; 10927 if (mLabelForId != View.NO_ID 10928 && mID == View.NO_ID) { 10929 mID = generateViewId(); 10930 } 10931 notifyViewAccessibilityStateChangedIfNeeded( 10932 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10933 } 10934 10935 /** 10936 * Invoked whenever this view loses focus, either by losing window focus or by losing 10937 * focus within its window. This method can be used to clear any state tied to the 10938 * focus. For instance, if a button is held pressed with the trackball and the window 10939 * loses focus, this method can be used to cancel the press. 10940 * 10941 * Subclasses of View overriding this method should always call super.onFocusLost(). 10942 * 10943 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 10944 * @see #onWindowFocusChanged(boolean) 10945 * 10946 * @hide pending API council approval 10947 */ 10948 @CallSuper 10949 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onFocusLost()10950 protected void onFocusLost() { 10951 resetPressedState(); 10952 } 10953 resetPressedState()10954 private void resetPressedState() { 10955 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10956 return; 10957 } 10958 10959 if (isPressed()) { 10960 setPressed(false); 10961 10962 if (!mHasPerformedLongPress) { 10963 removeLongPressCallback(); 10964 } 10965 } 10966 } 10967 10968 /** 10969 * Returns true if this view has focus 10970 * 10971 * @return True if this view has focus, false otherwise. 10972 */ 10973 @ViewDebug.ExportedProperty(category = "focus") 10974 @InspectableProperty(hasAttributeId = false) isFocused()10975 public boolean isFocused() { 10976 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 10977 } 10978 10979 /** 10980 * Find the view in the hierarchy rooted at this view that currently has 10981 * focus. 10982 * 10983 * @return The view that currently has focus, or null if no focused view can 10984 * be found. 10985 */ findFocus()10986 public View findFocus() { 10987 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 10988 } 10989 10990 /** 10991 * Indicates whether this view is one of the set of scrollable containers in 10992 * its window. 10993 * 10994 * @return whether this view is one of the set of scrollable containers in 10995 * its window 10996 * 10997 * @attr ref android.R.styleable#View_isScrollContainer 10998 */ 10999 @InspectableProperty(name = "isScrollContainer") isScrollContainer()11000 public boolean isScrollContainer() { 11001 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 11002 } 11003 11004 /** 11005 * Change whether this view is one of the set of scrollable containers in 11006 * its window. This will be used to determine whether the window can 11007 * resize or must pan when a soft input area is open -- scrollable 11008 * containers allow the window to use resize mode since the container 11009 * will appropriately shrink. 11010 * 11011 * @attr ref android.R.styleable#View_isScrollContainer 11012 */ setScrollContainer(boolean isScrollContainer)11013 public void setScrollContainer(boolean isScrollContainer) { 11014 if (isScrollContainer) { 11015 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 11016 mAttachInfo.mScrollContainers.add(this); 11017 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 11018 } 11019 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 11020 } else { 11021 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 11022 mAttachInfo.mScrollContainers.remove(this); 11023 } 11024 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 11025 } 11026 } 11027 11028 /** 11029 * Returns the quality of the drawing cache. 11030 * 11031 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11032 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11033 * 11034 * @see #setDrawingCacheQuality(int) 11035 * @see #setDrawingCacheEnabled(boolean) 11036 * @see #isDrawingCacheEnabled() 11037 * 11038 * @attr ref android.R.styleable#View_drawingCacheQuality 11039 * 11040 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11041 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11042 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11043 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11044 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11045 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11046 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11047 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11048 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11049 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11050 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11051 * reports or unit testing the {@link PixelCopy} API is recommended. 11052 */ 11053 @Deprecated 11054 @DrawingCacheQuality 11055 @InspectableProperty(enumMapping = { 11056 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 11057 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 11058 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 11059 }) getDrawingCacheQuality()11060 public int getDrawingCacheQuality() { 11061 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 11062 } 11063 11064 /** 11065 * Set the drawing cache quality of this view. This value is used only when the 11066 * drawing cache is enabled 11067 * 11068 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11069 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11070 * 11071 * @see #getDrawingCacheQuality() 11072 * @see #setDrawingCacheEnabled(boolean) 11073 * @see #isDrawingCacheEnabled() 11074 * 11075 * @attr ref android.R.styleable#View_drawingCacheQuality 11076 * 11077 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11078 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11079 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11080 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11081 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11082 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11083 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11084 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11085 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11086 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11087 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11088 * reports or unit testing the {@link PixelCopy} API is recommended. 11089 */ 11090 @Deprecated setDrawingCacheQuality(@rawingCacheQuality int quality)11091 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 11092 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 11093 } 11094 11095 /** 11096 * Returns whether the screen should remain on, corresponding to the current 11097 * value of {@link #KEEP_SCREEN_ON}. 11098 * 11099 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 11100 * 11101 * @see #setKeepScreenOn(boolean) 11102 * 11103 * @attr ref android.R.styleable#View_keepScreenOn 11104 */ 11105 @InspectableProperty getKeepScreenOn()11106 public boolean getKeepScreenOn() { 11107 return (mViewFlags & KEEP_SCREEN_ON) != 0; 11108 } 11109 11110 /** 11111 * Controls whether the screen should remain on, modifying the 11112 * value of {@link #KEEP_SCREEN_ON}. 11113 * 11114 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 11115 * 11116 * @see #getKeepScreenOn() 11117 * 11118 * @attr ref android.R.styleable#View_keepScreenOn 11119 */ setKeepScreenOn(boolean keepScreenOn)11120 public void setKeepScreenOn(boolean keepScreenOn) { 11121 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 11122 } 11123 11124 /** 11125 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11126 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11127 * 11128 * @attr ref android.R.styleable#View_nextFocusLeft 11129 */ 11130 @IdRes 11131 @InspectableProperty(name = "nextFocusLeft") getNextFocusLeftId()11132 public int getNextFocusLeftId() { 11133 return mNextFocusLeftId; 11134 } 11135 11136 /** 11137 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11138 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 11139 * decide automatically. 11140 * 11141 * @attr ref android.R.styleable#View_nextFocusLeft 11142 */ setNextFocusLeftId(@dRes int nextFocusLeftId)11143 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 11144 mNextFocusLeftId = nextFocusLeftId; 11145 } 11146 11147 /** 11148 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11149 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11150 * 11151 * @attr ref android.R.styleable#View_nextFocusRight 11152 */ 11153 @IdRes 11154 @InspectableProperty(name = "nextFocusRight") getNextFocusRightId()11155 public int getNextFocusRightId() { 11156 return mNextFocusRightId; 11157 } 11158 11159 /** 11160 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11161 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 11162 * decide automatically. 11163 * 11164 * @attr ref android.R.styleable#View_nextFocusRight 11165 */ setNextFocusRightId(@dRes int nextFocusRightId)11166 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 11167 mNextFocusRightId = nextFocusRightId; 11168 } 11169 11170 /** 11171 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11172 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11173 * 11174 * @attr ref android.R.styleable#View_nextFocusUp 11175 */ 11176 @IdRes 11177 @InspectableProperty(name = "nextFocusUp") getNextFocusUpId()11178 public int getNextFocusUpId() { 11179 return mNextFocusUpId; 11180 } 11181 11182 /** 11183 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11184 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 11185 * decide automatically. 11186 * 11187 * @attr ref android.R.styleable#View_nextFocusUp 11188 */ setNextFocusUpId(@dRes int nextFocusUpId)11189 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 11190 mNextFocusUpId = nextFocusUpId; 11191 } 11192 11193 /** 11194 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11195 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11196 * 11197 * @attr ref android.R.styleable#View_nextFocusDown 11198 */ 11199 @IdRes 11200 @InspectableProperty(name = "nextFocusDown") getNextFocusDownId()11201 public int getNextFocusDownId() { 11202 return mNextFocusDownId; 11203 } 11204 11205 /** 11206 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11207 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 11208 * decide automatically. 11209 * 11210 * @attr ref android.R.styleable#View_nextFocusDown 11211 */ setNextFocusDownId(@dRes int nextFocusDownId)11212 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 11213 mNextFocusDownId = nextFocusDownId; 11214 } 11215 11216 /** 11217 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11218 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11219 * 11220 * @attr ref android.R.styleable#View_nextFocusForward 11221 */ 11222 @IdRes 11223 @InspectableProperty(name = "nextFocusForward") getNextFocusForwardId()11224 public int getNextFocusForwardId() { 11225 return mNextFocusForwardId; 11226 } 11227 11228 /** 11229 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11230 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 11231 * decide automatically. 11232 * 11233 * @attr ref android.R.styleable#View_nextFocusForward 11234 */ setNextFocusForwardId(@dRes int nextFocusForwardId)11235 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 11236 mNextFocusForwardId = nextFocusForwardId; 11237 } 11238 11239 /** 11240 * Gets the id of the root of the next keyboard navigation cluster. 11241 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 11242 * decide automatically. 11243 * 11244 * @attr ref android.R.styleable#View_nextClusterForward 11245 */ 11246 @IdRes 11247 @InspectableProperty(name = "nextClusterForward") getNextClusterForwardId()11248 public int getNextClusterForwardId() { 11249 return mNextClusterForwardId; 11250 } 11251 11252 /** 11253 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 11254 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 11255 * decide automatically. 11256 * 11257 * @attr ref android.R.styleable#View_nextClusterForward 11258 */ setNextClusterForwardId(@dRes int nextClusterForwardId)11259 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 11260 mNextClusterForwardId = nextClusterForwardId; 11261 } 11262 11263 /** 11264 * Returns the visibility of this view and all of its ancestors 11265 * 11266 * @return True if this view and all of its ancestors are {@link #VISIBLE} 11267 */ isShown()11268 public boolean isShown() { 11269 View current = this; 11270 //noinspection ConstantConditions 11271 do { 11272 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 11273 return false; 11274 } 11275 ViewParent parent = current.mParent; 11276 if (parent == null) { 11277 return false; // We are not attached to the view root 11278 } 11279 if (!(parent instanceof View)) { 11280 return true; 11281 } 11282 current = (View) parent; 11283 } while (current != null); 11284 11285 return false; 11286 } 11287 detached()11288 private boolean detached() { 11289 View current = this; 11290 //noinspection ConstantConditions 11291 do { 11292 if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { 11293 return true; 11294 } 11295 ViewParent parent = current.mParent; 11296 if (parent == null) { 11297 return false; 11298 } 11299 if (!(parent instanceof View)) { 11300 return false; 11301 } 11302 current = (View) parent; 11303 } while (current != null); 11304 11305 return false; 11306 } 11307 11308 /** 11309 * Called by the view hierarchy when the content insets for a window have 11310 * changed, to allow it to adjust its content to fit within those windows. 11311 * The content insets tell you the space that the status bar, input method, 11312 * and other system windows infringe on the application's window. 11313 * 11314 * <p>You do not normally need to deal with this function, since the default 11315 * window decoration given to applications takes care of applying it to the 11316 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 11317 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 11318 * and your content can be placed under those system elements. You can then 11319 * use this method within your view hierarchy if you have parts of your UI 11320 * which you would like to ensure are not being covered. 11321 * 11322 * <p>The default implementation of this method simply applies the content 11323 * insets to the view's padding, consuming that content (modifying the 11324 * insets to be 0), and returning true. This behavior is off by default, but can 11325 * be enabled through {@link #setFitsSystemWindows(boolean)}. 11326 * 11327 * <p>This function's traversal down the hierarchy is depth-first. The same content 11328 * insets object is propagated down the hierarchy, so any changes made to it will 11329 * be seen by all following views (including potentially ones above in 11330 * the hierarchy since this is a depth-first traversal). The first view 11331 * that returns true will abort the entire traversal. 11332 * 11333 * <p>The default implementation works well for a situation where it is 11334 * used with a container that covers the entire window, allowing it to 11335 * apply the appropriate insets to its content on all edges. If you need 11336 * a more complicated layout (such as two different views fitting system 11337 * windows, one on the top of the window, and one on the bottom), 11338 * you can override the method and handle the insets however you would like. 11339 * Note that the insets provided by the framework are always relative to the 11340 * far edges of the window, not accounting for the location of the called view 11341 * within that window. (In fact when this method is called you do not yet know 11342 * where the layout will place the view, as it is done before layout happens.) 11343 * 11344 * <p>Note: unlike many View methods, there is no dispatch phase to this 11345 * call. If you are overriding it in a ViewGroup and want to allow the 11346 * call to continue to your children, you must be sure to call the super 11347 * implementation. 11348 * 11349 * <p>Here is a sample layout that makes use of fitting system windows 11350 * to have controls for a video view placed inside of the window decorations 11351 * that it hides and shows. This can be used with code like the second 11352 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 11353 * 11354 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 11355 * 11356 * @param insets Current content insets of the window. Prior to 11357 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 11358 * the insets or else you and Android will be unhappy. 11359 * 11360 * @return {@code true} if this view applied the insets and it should not 11361 * continue propagating further down the hierarchy, {@code false} otherwise. 11362 * @see #getFitsSystemWindows() 11363 * @see #setFitsSystemWindows(boolean) 11364 * @see #setSystemUiVisibility(int) 11365 * 11366 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 11367 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 11368 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 11369 * to implement handling their own insets. 11370 */ 11371 @Deprecated fitSystemWindows(Rect insets)11372 protected boolean fitSystemWindows(Rect insets) { 11373 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 11374 if (insets == null) { 11375 // Null insets by definition have already been consumed. 11376 // This call cannot apply insets since there are none to apply, 11377 // so return false. 11378 return false; 11379 } 11380 // If we're not in the process of dispatching the newer apply insets call, 11381 // that means we're not in the compatibility path. Dispatch into the newer 11382 // apply insets path and take things from there. 11383 try { 11384 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 11385 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 11386 } finally { 11387 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 11388 } 11389 } else { 11390 // We're being called from the newer apply insets path. 11391 // Perform the standard fallback behavior. 11392 return fitSystemWindowsInt(insets); 11393 } 11394 } 11395 fitSystemWindowsInt(Rect insets)11396 private boolean fitSystemWindowsInt(Rect insets) { 11397 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 11398 Rect localInsets = sThreadLocal.get(); 11399 boolean res = computeFitSystemWindows(insets, localInsets); 11400 applyInsets(localInsets); 11401 return res; 11402 } 11403 return false; 11404 } 11405 applyInsets(Rect insets)11406 private void applyInsets(Rect insets) { 11407 mUserPaddingStart = UNDEFINED_PADDING; 11408 mUserPaddingEnd = UNDEFINED_PADDING; 11409 mUserPaddingLeftInitial = insets.left; 11410 mUserPaddingRightInitial = insets.right; 11411 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 11412 } 11413 11414 /** 11415 * Called when the view should apply {@link WindowInsets} according to its internal policy. 11416 * 11417 * <p>This method should be overridden by views that wish to apply a policy different from or 11418 * in addition to the default behavior. Clients that wish to force a view subtree 11419 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 11420 * 11421 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 11422 * it will be called during dispatch instead of this method. The listener may optionally 11423 * call this method from its own implementation if it wishes to apply the view's default 11424 * insets policy in addition to its own.</p> 11425 * 11426 * <p>Implementations of this method should either return the insets parameter unchanged 11427 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 11428 * that this view applied itself. This allows new inset types added in future platform 11429 * versions to pass through existing implementations unchanged without being erroneously 11430 * consumed.</p> 11431 * 11432 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 11433 * property is set then the view will consume the system window insets and apply them 11434 * as padding for the view.</p> 11435 * 11436 * @param insets Insets to apply 11437 * @return The supplied insets with any applied insets consumed 11438 */ onApplyWindowInsets(WindowInsets insets)11439 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 11440 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11441 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 11442 return onApplyFrameworkOptionalFitSystemWindows(insets); 11443 } 11444 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 11445 // We weren't called from within a direct call to fitSystemWindows, 11446 // call into it as a fallback in case we're in a class that overrides it 11447 // and has logic to perform. 11448 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 11449 return insets.consumeSystemWindowInsets(); 11450 } 11451 } else { 11452 // We were called from within a direct call to fitSystemWindows. 11453 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 11454 return insets.consumeSystemWindowInsets(); 11455 } 11456 } 11457 return insets; 11458 } 11459 onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets)11460 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 11461 Rect localInsets = sThreadLocal.get(); 11462 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 11463 applyInsets(localInsets); 11464 return result; 11465 } 11466 11467 /** 11468 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 11469 * window insets to this view. The listener's 11470 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 11471 * method will be called instead of the view's 11472 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 11473 * 11474 * @param listener Listener to set 11475 * 11476 * @see #onApplyWindowInsets(WindowInsets) 11477 */ setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)11478 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 11479 getListenerInfo().mOnApplyWindowInsetsListener = listener; 11480 } 11481 11482 /** 11483 * Request to apply the given window insets to this view or another view in its subtree. 11484 * 11485 * <p>This method should be called by clients wishing to apply insets corresponding to areas 11486 * obscured by window decorations or overlays. This can include the status and navigation bars, 11487 * action bars, input methods and more. New inset categories may be added in the future. 11488 * The method returns the insets provided minus any that were applied by this view or its 11489 * children.</p> 11490 * 11491 * <p>Clients wishing to provide custom behavior should override the 11492 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 11493 * {@link OnApplyWindowInsetsListener} via the 11494 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 11495 * method.</p> 11496 * 11497 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 11498 * </p> 11499 * 11500 * @param insets Insets to apply 11501 * @return The provided insets minus the insets that were consumed 11502 */ dispatchApplyWindowInsets(WindowInsets insets)11503 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 11504 try { 11505 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 11506 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 11507 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 11508 } else { 11509 return onApplyWindowInsets(insets); 11510 } 11511 } finally { 11512 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 11513 } 11514 } 11515 11516 /** 11517 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 11518 * cause insets. 11519 * <p> 11520 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 11521 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 11522 * this view. 11523 * </p> 11524 * @param callback The callback to set. 11525 */ setWindowInsetsAnimationCallback( @ullable WindowInsetsAnimation.Callback callback)11526 public void setWindowInsetsAnimationCallback( 11527 @Nullable WindowInsetsAnimation.Callback callback) { 11528 getListenerInfo().mWindowInsetsAnimationCallback = callback; 11529 } 11530 11531 /** 11532 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 11533 * or view tree of the sub-hierarchy {@code false} otherwise. 11534 * @hide 11535 */ hasWindowInsetsAnimationCallback()11536 public boolean hasWindowInsetsAnimationCallback() { 11537 return getListenerInfo().mWindowInsetsAnimationCallback != null; 11538 } 11539 11540 /** 11541 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 11542 * when Window Insets animation is being prepared. 11543 * @param animation current animation 11544 * 11545 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 11546 */ dispatchWindowInsetsAnimationPrepare( @onNull WindowInsetsAnimation animation)11547 public void dispatchWindowInsetsAnimationPrepare( 11548 @NonNull WindowInsetsAnimation animation) { 11549 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11550 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 11551 } 11552 } 11553 11554 /** 11555 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 11556 * when Window Insets animation is started. 11557 * @param animation current animation 11558 * @param bounds the upper and lower {@link Bounds} that provides range of 11559 * {@link WindowInsetsAnimation}. 11560 * @return the upper and lower {@link Bounds}. 11561 */ 11562 @NonNull dispatchWindowInsetsAnimationStart( @onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)11563 public Bounds dispatchWindowInsetsAnimationStart( 11564 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 11565 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11566 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 11567 } 11568 return bounds; 11569 } 11570 11571 /** 11572 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 11573 * when Window Insets animation makes progress. 11574 * @param insets The current {@link WindowInsets}. 11575 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 11576 * @return current {@link WindowInsets}. 11577 */ 11578 @NonNull dispatchWindowInsetsAnimationProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)11579 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 11580 @NonNull List<WindowInsetsAnimation> runningAnimations) { 11581 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11582 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 11583 runningAnimations); 11584 } else { 11585 return insets; 11586 } 11587 } 11588 11589 /** 11590 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 11591 * when Window Insets animation ends. 11592 * @param animation The current ongoing {@link WindowInsetsAnimation}. 11593 */ dispatchWindowInsetsAnimationEnd(@onNull WindowInsetsAnimation animation)11594 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 11595 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11596 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 11597 } 11598 } 11599 11600 /** 11601 * Sets a list of areas within this view's post-layout coordinate space where the system 11602 * should not intercept touch or other pointing device gestures. <em>This method should 11603 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 11604 * 11605 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 11606 * input in order to function correctly in the presence of global system gestures that may 11607 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 11608 * to provide system-level navigation functionality, a view such as a navigation drawer 11609 * container can mark the left (or starting) edge of itself as requiring gesture capture 11610 * priority using this API. The system may then choose to relax its own gesture recognition 11611 * to allow the app to consume the user's gesture. It is not necessary for an app to register 11612 * exclusion rects for broadly spanning regions such as the entirety of a 11613 * <code>ScrollView</code> or for simple press and release click targets such as 11614 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 11615 * a precision touch gesture in a small area in either the X or Y dimension, such as 11616 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 11617 * 11618 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 11619 * exclusions it takes into account. The limit does not apply while the navigation 11620 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 11621 * {@link android.inputmethodservice.InputMethodService input method} and 11622 * {@link Intent#CATEGORY_HOME home activity}. 11623 * </p> 11624 * 11625 * @param rects A list of precision gesture regions that this view needs to function correctly 11626 */ setSystemGestureExclusionRects(@onNull List<Rect> rects)11627 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 11628 if (rects.isEmpty() && mListenerInfo == null) return; 11629 11630 final ListenerInfo info = getListenerInfo(); 11631 if (info.mSystemGestureExclusionRects != null) { 11632 info.mSystemGestureExclusionRects.clear(); 11633 info.mSystemGestureExclusionRects.addAll(rects); 11634 } else { 11635 info.mSystemGestureExclusionRects = new ArrayList<>(rects); 11636 } 11637 if (rects.isEmpty()) { 11638 if (info.mPositionUpdateListener != null) { 11639 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 11640 } 11641 } else { 11642 if (info.mPositionUpdateListener == null) { 11643 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 11644 @Override 11645 public void positionChanged(long n, int l, int t, int r, int b) { 11646 postUpdateSystemGestureExclusionRects(); 11647 } 11648 11649 @Override 11650 public void positionLost(long frameNumber) { 11651 postUpdateSystemGestureExclusionRects(); 11652 } 11653 }; 11654 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 11655 } 11656 } 11657 postUpdateSystemGestureExclusionRects(); 11658 } 11659 11660 /** 11661 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 11662 */ postUpdateSystemGestureExclusionRects()11663 void postUpdateSystemGestureExclusionRects() { 11664 // Potentially racey from a background thread. It's ok if it's not perfect. 11665 final Handler h = getHandler(); 11666 if (h != null) { 11667 h.postAtFrontOfQueue(this::updateSystemGestureExclusionRects); 11668 } 11669 } 11670 updateSystemGestureExclusionRects()11671 void updateSystemGestureExclusionRects() { 11672 final AttachInfo ai = mAttachInfo; 11673 if (ai != null) { 11674 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 11675 } 11676 } 11677 11678 /** 11679 * Retrieve the list of areas within this view's post-layout coordinate space where the system 11680 * should not intercept touch or other pointing device gestures. 11681 * 11682 * <p>Do not modify the returned list.</p> 11683 * 11684 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 11685 */ 11686 @NonNull getSystemGestureExclusionRects()11687 public List<Rect> getSystemGestureExclusionRects() { 11688 final ListenerInfo info = mListenerInfo; 11689 if (info != null) { 11690 final List<Rect> list = info.mSystemGestureExclusionRects; 11691 if (list != null) { 11692 return list; 11693 } 11694 } 11695 return Collections.emptyList(); 11696 } 11697 11698 /** 11699 * Compute the view's coordinate within the surface. 11700 * 11701 * <p>Computes the coordinates of this view in its surface. The argument 11702 * must be an array of two integers. After the method returns, the array 11703 * contains the x and y location in that order.</p> 11704 * 11705 * @param location an array of two integers in which to hold the coordinates 11706 */ getLocationInSurface(@onNull @ize2) int[] location)11707 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 11708 getLocationInWindow(location); 11709 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 11710 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 11711 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 11712 } 11713 } 11714 11715 /** 11716 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 11717 * only available if the view is attached. 11718 * 11719 * @return WindowInsets from the top of the view hierarchy or null if View is detached 11720 */ getRootWindowInsets()11721 public WindowInsets getRootWindowInsets() { 11722 if (mAttachInfo != null) { 11723 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 11724 } 11725 return null; 11726 } 11727 11728 /** 11729 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 11730 * 11731 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 11732 * a window nor a view tree with a decor. 11733 * @see Window#getInsetsController() 11734 */ getWindowInsetsController()11735 public @Nullable WindowInsetsController getWindowInsetsController() { 11736 if (mAttachInfo != null) { 11737 return mAttachInfo.mViewRootImpl.getInsetsController(); 11738 } 11739 ViewParent parent = getParent(); 11740 if (parent instanceof View) { 11741 return ((View) parent).getWindowInsetsController(); 11742 } else if (parent instanceof ViewRootImpl) { 11743 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 11744 return ((ViewRootImpl) parent).getInsetsController(); 11745 } 11746 return null; 11747 } 11748 11749 /** 11750 * @hide Compute the insets that should be consumed by this view and the ones 11751 * that should propagate to those under it. 11752 * 11753 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 11754 * 11755 * @param inoutInsets the insets given to this view 11756 * @param outLocalInsets the insets that should be applied to this view 11757 * @deprecated use {@link #computeSystemWindowInsets} 11758 * @return 11759 */ 11760 @Deprecated 11761 @UnsupportedAppUsage computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets)11762 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 11763 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 11764 outLocalInsets); 11765 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 11766 return innerInsets.isSystemWindowInsetsConsumed(); 11767 } 11768 11769 /** 11770 * Compute insets that should be consumed by this view and the ones that should propagate 11771 * to those under it. 11772 * 11773 * @param in Insets currently being processed by this View, likely received as a parameter 11774 * to {@link #onApplyWindowInsets(WindowInsets)}. 11775 * @param outLocalInsets A Rect that will receive the insets that should be consumed 11776 * by this view 11777 * @return Insets that should be passed along to views under this one 11778 */ computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets)11779 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 11780 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11781 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 11782 if (isOptionalFitSystemWindows && mAttachInfo != null) { 11783 OnContentApplyWindowInsetsListener listener = 11784 mAttachInfo.mContentOnApplyWindowInsetsListener; 11785 if (listener == null) { 11786 // The application wants to take care of fitting system window for 11787 // the content. 11788 outLocalInsets.setEmpty(); 11789 return in; 11790 } 11791 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 11792 outLocalInsets.set(result.first.toRect()); 11793 return result.second; 11794 } else { 11795 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 11796 return in.consumeSystemWindowInsets().inset(outLocalInsets); 11797 } 11798 } 11799 11800 /** 11801 * Sets whether or not this view should account for system screen decorations 11802 * such as the status bar and inset its content; that is, controlling whether 11803 * the default implementation of {@link #fitSystemWindows(Rect)} will be 11804 * executed. See that method for more details. 11805 * 11806 * <p>Note that if you are providing your own implementation of 11807 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 11808 * flag to true -- your implementation will be overriding the default 11809 * implementation that checks this flag. 11810 * 11811 * @param fitSystemWindows If true, then the default implementation of 11812 * {@link #fitSystemWindows(Rect)} will be executed. 11813 * 11814 * @attr ref android.R.styleable#View_fitsSystemWindows 11815 * @see #getFitsSystemWindows() 11816 * @see #fitSystemWindows(Rect) 11817 * @see #setSystemUiVisibility(int) 11818 */ setFitsSystemWindows(boolean fitSystemWindows)11819 public void setFitsSystemWindows(boolean fitSystemWindows) { 11820 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 11821 } 11822 11823 /** 11824 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 11825 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 11826 * will be executed. 11827 * 11828 * @return {@code true} if the default implementation of 11829 * {@link #fitSystemWindows(Rect)} will be executed. 11830 * 11831 * @attr ref android.R.styleable#View_fitsSystemWindows 11832 * @see #setFitsSystemWindows(boolean) 11833 * @see #fitSystemWindows(Rect) 11834 * @see #setSystemUiVisibility(int) 11835 */ 11836 @ViewDebug.ExportedProperty 11837 @InspectableProperty getFitsSystemWindows()11838 public boolean getFitsSystemWindows() { 11839 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 11840 } 11841 11842 /** @hide */ 11843 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) fitsSystemWindows()11844 public boolean fitsSystemWindows() { 11845 return getFitsSystemWindows(); 11846 } 11847 11848 /** 11849 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 11850 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 11851 */ 11852 @Deprecated requestFitSystemWindows()11853 public void requestFitSystemWindows() { 11854 if (mParent != null) { 11855 mParent.requestFitSystemWindows(); 11856 } 11857 } 11858 11859 /** 11860 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 11861 */ requestApplyInsets()11862 public void requestApplyInsets() { 11863 requestFitSystemWindows(); 11864 } 11865 11866 /** 11867 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 11868 * @hide 11869 */ 11870 @UnsupportedAppUsage makeOptionalFitsSystemWindows()11871 public void makeOptionalFitsSystemWindows() { 11872 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 11873 } 11874 11875 /** 11876 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 11877 * @hide 11878 */ makeFrameworkOptionalFitsSystemWindows()11879 public void makeFrameworkOptionalFitsSystemWindows() { 11880 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 11881 } 11882 11883 /** 11884 * @hide 11885 */ isFrameworkOptionalFitsSystemWindows()11886 public boolean isFrameworkOptionalFitsSystemWindows() { 11887 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 11888 } 11889 11890 /** 11891 * Returns the visibility status for this view. 11892 * 11893 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11894 * @attr ref android.R.styleable#View_visibility 11895 */ 11896 @ViewDebug.ExportedProperty(mapping = { 11897 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 11898 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 11899 @ViewDebug.IntToString(from = GONE, to = "GONE") 11900 }) 11901 @InspectableProperty(enumMapping = { 11902 @EnumEntry(value = VISIBLE, name = "visible"), 11903 @EnumEntry(value = INVISIBLE, name = "invisible"), 11904 @EnumEntry(value = GONE, name = "gone") 11905 }) 11906 @Visibility getVisibility()11907 public int getVisibility() { 11908 return mViewFlags & VISIBILITY_MASK; 11909 } 11910 11911 /** 11912 * Set the visibility state of this view. 11913 * 11914 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11915 * @attr ref android.R.styleable#View_visibility 11916 */ 11917 @RemotableViewMethod setVisibility(@isibility int visibility)11918 public void setVisibility(@Visibility int visibility) { 11919 setFlags(visibility, VISIBILITY_MASK); 11920 } 11921 11922 /** 11923 * Returns the enabled status for this view. The interpretation of the 11924 * enabled state varies by subclass. 11925 * 11926 * @return True if this view is enabled, false otherwise. 11927 */ 11928 @ViewDebug.ExportedProperty 11929 @InspectableProperty isEnabled()11930 public boolean isEnabled() { 11931 return (mViewFlags & ENABLED_MASK) == ENABLED; 11932 } 11933 11934 /** 11935 * Set the enabled state of this view. The interpretation of the enabled 11936 * state varies by subclass. 11937 * 11938 * @param enabled True if this view is enabled, false otherwise. 11939 */ 11940 @RemotableViewMethod setEnabled(boolean enabled)11941 public void setEnabled(boolean enabled) { 11942 if (enabled == isEnabled()) return; 11943 11944 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 11945 11946 /* 11947 * The View most likely has to change its appearance, so refresh 11948 * the drawable state. 11949 */ 11950 refreshDrawableState(); 11951 11952 // Invalidate too, since the default behavior for views is to be 11953 // be drawn at 50% alpha rather than to change the drawable. 11954 invalidate(true); 11955 11956 if (!enabled) { 11957 cancelPendingInputEvents(); 11958 } 11959 } 11960 11961 /** 11962 * Set whether this view can receive the focus. 11963 * <p> 11964 * Setting this to false will also ensure that this view is not focusable 11965 * in touch mode. 11966 * 11967 * @param focusable If true, this view can receive the focus. 11968 * 11969 * @see #setFocusableInTouchMode(boolean) 11970 * @see #setFocusable(int) 11971 * @attr ref android.R.styleable#View_focusable 11972 */ 11973 @RemotableViewMethod setFocusable(boolean focusable)11974 public void setFocusable(boolean focusable) { 11975 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 11976 } 11977 11978 /** 11979 * Sets whether this view can receive focus. 11980 * <p> 11981 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 11982 * automatically based on the view's interactivity. This is the default. 11983 * <p> 11984 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 11985 * in touch mode. 11986 * 11987 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 11988 * or {@link #FOCUSABLE_AUTO}. 11989 * @see #setFocusableInTouchMode(boolean) 11990 * @attr ref android.R.styleable#View_focusable 11991 */ 11992 @RemotableViewMethod setFocusable(@ocusable int focusable)11993 public void setFocusable(@Focusable int focusable) { 11994 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 11995 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 11996 } 11997 setFlags(focusable, FOCUSABLE_MASK); 11998 } 11999 12000 /** 12001 * Set whether this view can receive focus while in touch mode. 12002 * 12003 * Setting this to true will also ensure that this view is focusable. 12004 * 12005 * @param focusableInTouchMode If true, this view can receive the focus while 12006 * in touch mode. 12007 * 12008 * @see #setFocusable(boolean) 12009 * @attr ref android.R.styleable#View_focusableInTouchMode 12010 */ 12011 @RemotableViewMethod setFocusableInTouchMode(boolean focusableInTouchMode)12012 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 12013 // Focusable in touch mode should always be set before the focusable flag 12014 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 12015 // which, in touch mode, will not successfully request focus on this view 12016 // because the focusable in touch mode flag is not set 12017 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 12018 12019 // Clear FOCUSABLE_AUTO if set. 12020 if (focusableInTouchMode) { 12021 // Clears FOCUSABLE_AUTO if set. 12022 setFlags(FOCUSABLE, FOCUSABLE_MASK); 12023 } 12024 } 12025 12026 /** 12027 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 12028 * to autofill the view with the user's data. 12029 * 12030 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 12031 * For example, if the application accepts either an username or email address to identify 12032 * an user. 12033 * 12034 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 12035 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 12036 * constants such as: 12037 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 12038 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 12039 * {@link #AUTOFILL_HINT_NAME}, 12040 * {@link #AUTOFILL_HINT_PHONE}, 12041 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 12042 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 12043 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 12044 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 12045 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 12046 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 12047 * 12048 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 12049 * @attr ref android.R.styleable#View_autofillHints 12050 */ setAutofillHints(@ullable String... autofillHints)12051 public void setAutofillHints(@Nullable String... autofillHints) { 12052 if (autofillHints == null || autofillHints.length == 0) { 12053 mAutofillHints = null; 12054 } else { 12055 mAutofillHints = autofillHints; 12056 } 12057 } 12058 12059 /** 12060 * @hide 12061 */ 12062 @TestApi setAutofilled(boolean isAutofilled, boolean hideHighlight)12063 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 12064 boolean wasChanged = isAutofilled != isAutofilled(); 12065 12066 if (wasChanged) { 12067 if (isAutofilled) { 12068 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 12069 } else { 12070 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 12071 } 12072 12073 if (hideHighlight) { 12074 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 12075 } else { 12076 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 12077 } 12078 12079 invalidate(); 12080 } 12081 } 12082 12083 /** 12084 * Set whether this view should have sound effects enabled for events such as 12085 * clicking and touching. 12086 * 12087 * <p>You may wish to disable sound effects for a view if you already play sounds, 12088 * for instance, a dial key that plays dtmf tones. 12089 * 12090 * @param soundEffectsEnabled whether sound effects are enabled for this view. 12091 * @see #isSoundEffectsEnabled() 12092 * @see #playSoundEffect(int) 12093 * @attr ref android.R.styleable#View_soundEffectsEnabled 12094 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)12095 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 12096 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 12097 } 12098 12099 /** 12100 * @return whether this view should have sound effects enabled for events such as 12101 * clicking and touching. 12102 * 12103 * @see #setSoundEffectsEnabled(boolean) 12104 * @see #playSoundEffect(int) 12105 * @attr ref android.R.styleable#View_soundEffectsEnabled 12106 */ 12107 @ViewDebug.ExportedProperty 12108 @InspectableProperty isSoundEffectsEnabled()12109 public boolean isSoundEffectsEnabled() { 12110 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 12111 } 12112 12113 /** 12114 * Set whether this view should have haptic feedback for events such as 12115 * long presses. 12116 * 12117 * <p>You may wish to disable haptic feedback if your view already controls 12118 * its own haptic feedback. 12119 * 12120 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 12121 * @see #isHapticFeedbackEnabled() 12122 * @see #performHapticFeedback(int) 12123 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 12124 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)12125 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 12126 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 12127 } 12128 12129 /** 12130 * @return whether this view should have haptic feedback enabled for events 12131 * long presses. 12132 * 12133 * @see #setHapticFeedbackEnabled(boolean) 12134 * @see #performHapticFeedback(int) 12135 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 12136 */ 12137 @ViewDebug.ExportedProperty 12138 @InspectableProperty isHapticFeedbackEnabled()12139 public boolean isHapticFeedbackEnabled() { 12140 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 12141 } 12142 12143 /** 12144 * Returns the layout direction for this view. 12145 * 12146 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 12147 * {@link #LAYOUT_DIRECTION_RTL}, 12148 * {@link #LAYOUT_DIRECTION_INHERIT} or 12149 * {@link #LAYOUT_DIRECTION_LOCALE}. 12150 * 12151 * @attr ref android.R.styleable#View_layoutDirection 12152 * 12153 * @hide 12154 */ 12155 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12156 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 12157 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 12158 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 12159 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 12160 }) 12161 @InspectableProperty(hasAttributeId = false, enumMapping = { 12162 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12163 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 12164 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 12165 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 12166 }) 12167 @LayoutDir getRawLayoutDirection()12168 public int getRawLayoutDirection() { 12169 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 12170 } 12171 12172 /** 12173 * Set the layout direction for this view. This will propagate a reset of layout direction 12174 * resolution to the view's children and resolve layout direction for this view. 12175 * 12176 * @param layoutDirection the layout direction to set. Should be one of: 12177 * 12178 * {@link #LAYOUT_DIRECTION_LTR}, 12179 * {@link #LAYOUT_DIRECTION_RTL}, 12180 * {@link #LAYOUT_DIRECTION_INHERIT}, 12181 * {@link #LAYOUT_DIRECTION_LOCALE}. 12182 * 12183 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 12184 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 12185 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 12186 * 12187 * @attr ref android.R.styleable#View_layoutDirection 12188 */ 12189 @RemotableViewMethod setLayoutDirection(@ayoutDir int layoutDirection)12190 public void setLayoutDirection(@LayoutDir int layoutDirection) { 12191 if (getRawLayoutDirection() != layoutDirection) { 12192 // Reset the current layout direction and the resolved one 12193 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 12194 resetRtlProperties(); 12195 // Set the new layout direction (filtered) 12196 mPrivateFlags2 |= 12197 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 12198 // We need to resolve all RTL properties as they all depend on layout direction 12199 resolveRtlPropertiesIfNeeded(); 12200 requestLayout(); 12201 invalidate(true); 12202 } 12203 } 12204 12205 /** 12206 * Returns the resolved layout direction for this view. 12207 * 12208 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 12209 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 12210 * 12211 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 12212 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 12213 * 12214 * @attr ref android.R.styleable#View_layoutDirection 12215 */ 12216 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12217 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 12218 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 12219 }) 12220 @InspectableProperty(enumMapping = { 12221 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12222 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 12223 }) 12224 @ResolvedLayoutDir getLayoutDirection()12225 public int getLayoutDirection() { 12226 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 12227 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 12228 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 12229 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 12230 } 12231 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 12232 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 12233 } 12234 12235 /** 12236 * Indicates whether or not this view's layout is right-to-left. This is resolved from 12237 * layout attribute and/or the inherited value from the parent 12238 * 12239 * @return true if the layout is right-to-left. 12240 * 12241 * @hide 12242 */ 12243 @ViewDebug.ExportedProperty(category = "layout") 12244 @UnsupportedAppUsage isLayoutRtl()12245 public boolean isLayoutRtl() { 12246 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 12247 } 12248 12249 /** 12250 * Indicates whether the view is currently tracking transient state that the 12251 * app should not need to concern itself with saving and restoring, but that 12252 * the framework should take special note to preserve when possible. 12253 * 12254 * <p>A view with transient state cannot be trivially rebound from an external 12255 * data source, such as an adapter binding item views in a list. This may be 12256 * because the view is performing an animation, tracking user selection 12257 * of content, or similar.</p> 12258 * 12259 * @return true if the view has transient state 12260 */ 12261 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()12262 public boolean hasTransientState() { 12263 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 12264 } 12265 12266 /** 12267 * Set whether this view is currently tracking transient state that the 12268 * framework should attempt to preserve when possible. This flag is reference counted, 12269 * so every call to setHasTransientState(true) should be paired with a later call 12270 * to setHasTransientState(false). 12271 * 12272 * <p>A view with transient state cannot be trivially rebound from an external 12273 * data source, such as an adapter binding item views in a list. This may be 12274 * because the view is performing an animation, tracking user selection 12275 * of content, or similar.</p> 12276 * 12277 * @param hasTransientState true if this view has transient state 12278 */ setHasTransientState(boolean hasTransientState)12279 public void setHasTransientState(boolean hasTransientState) { 12280 final boolean oldHasTransientState = hasTransientState(); 12281 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 12282 mTransientStateCount - 1; 12283 if (mTransientStateCount < 0) { 12284 mTransientStateCount = 0; 12285 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 12286 "unmatched pair of setHasTransientState calls"); 12287 } else if ((hasTransientState && mTransientStateCount == 1) || 12288 (!hasTransientState && mTransientStateCount == 0)) { 12289 // update flag if we've just incremented up from 0 or decremented down to 0 12290 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 12291 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 12292 final boolean newHasTransientState = hasTransientState(); 12293 if (mParent != null && newHasTransientState != oldHasTransientState) { 12294 try { 12295 mParent.childHasTransientStateChanged(this, newHasTransientState); 12296 } catch (AbstractMethodError e) { 12297 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 12298 " does not fully implement ViewParent", e); 12299 } 12300 } 12301 } 12302 } 12303 12304 /** 12305 * Set the view is tracking translation transient state. This flag is used to check if the view 12306 * need to call setHasTransientState(false) to reset transient state that set when starting 12307 * translation. 12308 * 12309 * @param hasTranslationTransientState true if this view has translation transient state 12310 * @hide 12311 */ setHasTranslationTransientState(boolean hasTranslationTransientState)12312 public void setHasTranslationTransientState(boolean hasTranslationTransientState) { 12313 if (hasTranslationTransientState) { 12314 mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12315 } else { 12316 mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12317 } 12318 } 12319 12320 /** 12321 * @hide 12322 */ hasTranslationTransientState()12323 public boolean hasTranslationTransientState() { 12324 return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) 12325 == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12326 } 12327 12328 /** 12329 * Returns true if this view is currently attached to a window. 12330 */ isAttachedToWindow()12331 public boolean isAttachedToWindow() { 12332 return mAttachInfo != null; 12333 } 12334 12335 /** 12336 * Returns true if this view has been through at least one layout since it 12337 * was last attached to or detached from a window. 12338 */ isLaidOut()12339 public boolean isLaidOut() { 12340 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 12341 } 12342 12343 /** 12344 * @return {@code true} if laid-out and not about to do another layout. 12345 */ isLayoutValid()12346 boolean isLayoutValid() { 12347 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 12348 } 12349 12350 /** 12351 * If this view doesn't do any drawing on its own, set this flag to 12352 * allow further optimizations. By default, this flag is not set on 12353 * View, but could be set on some View subclasses such as ViewGroup. 12354 * 12355 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 12356 * you should clear this flag. 12357 * 12358 * @param willNotDraw whether or not this View draw on its own 12359 */ setWillNotDraw(boolean willNotDraw)12360 public void setWillNotDraw(boolean willNotDraw) { 12361 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 12362 } 12363 12364 /** 12365 * Returns whether or not this View draws on its own. 12366 * 12367 * @return true if this view has nothing to draw, false otherwise 12368 */ 12369 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()12370 public boolean willNotDraw() { 12371 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 12372 } 12373 12374 /** 12375 * When a View's drawing cache is enabled, drawing is redirected to an 12376 * offscreen bitmap. Some views, like an ImageView, must be able to 12377 * bypass this mechanism if they already draw a single bitmap, to avoid 12378 * unnecessary usage of the memory. 12379 * 12380 * @param willNotCacheDrawing true if this view does not cache its 12381 * drawing, false otherwise 12382 * 12383 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12384 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12385 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12386 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12387 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12388 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12389 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12390 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12391 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12392 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12393 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12394 * reports or unit testing the {@link PixelCopy} API is recommended. 12395 */ 12396 @Deprecated setWillNotCacheDrawing(boolean willNotCacheDrawing)12397 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 12398 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 12399 } 12400 12401 /** 12402 * Returns whether or not this View can cache its drawing or not. 12403 * 12404 * @return true if this view does not cache its drawing, false otherwise 12405 * 12406 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12407 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12408 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12409 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12410 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12411 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12412 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12413 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12414 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12415 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12416 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12417 * reports or unit testing the {@link PixelCopy} API is recommended. 12418 */ 12419 @ViewDebug.ExportedProperty(category = "drawing") 12420 @Deprecated willNotCacheDrawing()12421 public boolean willNotCacheDrawing() { 12422 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 12423 } 12424 12425 /** 12426 * Indicates whether this view reacts to click events or not. 12427 * 12428 * @return true if the view is clickable, false otherwise 12429 * 12430 * @see #setClickable(boolean) 12431 * @attr ref android.R.styleable#View_clickable 12432 */ 12433 @ViewDebug.ExportedProperty 12434 @InspectableProperty isClickable()12435 public boolean isClickable() { 12436 return (mViewFlags & CLICKABLE) == CLICKABLE; 12437 } 12438 12439 /** 12440 * Enables or disables click events for this view. When a view 12441 * is clickable it will change its state to "pressed" on every click. 12442 * Subclasses should set the view clickable to visually react to 12443 * user's clicks. 12444 * 12445 * @param clickable true to make the view clickable, false otherwise 12446 * 12447 * @see #isClickable() 12448 * @attr ref android.R.styleable#View_clickable 12449 */ setClickable(boolean clickable)12450 public void setClickable(boolean clickable) { 12451 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 12452 } 12453 12454 /** 12455 * Enables or disables click events for this view when disabled. 12456 * 12457 * @param clickableWhenDisabled true to make the view clickable, false otherwise 12458 * 12459 * @attr ref android.R.styleable#View_allowClickWhenDisabled 12460 */ setAllowClickWhenDisabled(boolean clickableWhenDisabled)12461 public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { 12462 if (clickableWhenDisabled) { 12463 mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 12464 } else { 12465 mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 12466 } 12467 } 12468 12469 /** 12470 * Indicates whether this view reacts to long click events or not. 12471 * 12472 * @return true if the view is long clickable, false otherwise 12473 * 12474 * @see #setLongClickable(boolean) 12475 * @attr ref android.R.styleable#View_longClickable 12476 */ 12477 @InspectableProperty isLongClickable()12478 public boolean isLongClickable() { 12479 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12480 } 12481 12482 /** 12483 * Enables or disables long click events for this view. When a view is long 12484 * clickable it reacts to the user holding down the button for a longer 12485 * duration than a tap. This event can either launch the listener or a 12486 * context menu. 12487 * 12488 * @param longClickable true to make the view long clickable, false otherwise 12489 * @see #isLongClickable() 12490 * @attr ref android.R.styleable#View_longClickable 12491 */ setLongClickable(boolean longClickable)12492 public void setLongClickable(boolean longClickable) { 12493 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 12494 } 12495 12496 /** 12497 * Indicates whether this view reacts to context clicks or not. 12498 * 12499 * @return true if the view is context clickable, false otherwise 12500 * @see #setContextClickable(boolean) 12501 * @attr ref android.R.styleable#View_contextClickable 12502 */ 12503 @InspectableProperty isContextClickable()12504 public boolean isContextClickable() { 12505 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12506 } 12507 12508 /** 12509 * Enables or disables context clicking for this view. This event can launch the listener. 12510 * 12511 * @param contextClickable true to make the view react to a context click, false otherwise 12512 * @see #isContextClickable() 12513 * @attr ref android.R.styleable#View_contextClickable 12514 */ setContextClickable(boolean contextClickable)12515 public void setContextClickable(boolean contextClickable) { 12516 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 12517 } 12518 12519 /** 12520 * Sets the pressed state for this view and provides a touch coordinate for 12521 * animation hinting. 12522 * 12523 * @param pressed Pass true to set the View's internal state to "pressed", 12524 * or false to reverts the View's internal state from a 12525 * previously set "pressed" state. 12526 * @param x The x coordinate of the touch that caused the press 12527 * @param y The y coordinate of the touch that caused the press 12528 */ setPressed(boolean pressed, float x, float y)12529 private void setPressed(boolean pressed, float x, float y) { 12530 if (pressed) { 12531 drawableHotspotChanged(x, y); 12532 } 12533 12534 setPressed(pressed); 12535 } 12536 12537 /** 12538 * Sets the pressed state for this view. 12539 * 12540 * @see #isClickable() 12541 * @see #setClickable(boolean) 12542 * 12543 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 12544 * the View's internal state from a previously set "pressed" state. 12545 */ setPressed(boolean pressed)12546 public void setPressed(boolean pressed) { 12547 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 12548 12549 if (pressed) { 12550 mPrivateFlags |= PFLAG_PRESSED; 12551 } else { 12552 mPrivateFlags &= ~PFLAG_PRESSED; 12553 } 12554 12555 if (needsRefresh) { 12556 refreshDrawableState(); 12557 } 12558 dispatchSetPressed(pressed); 12559 } 12560 12561 /** 12562 * Dispatch setPressed to all of this View's children. 12563 * 12564 * @see #setPressed(boolean) 12565 * 12566 * @param pressed The new pressed state 12567 */ dispatchSetPressed(boolean pressed)12568 protected void dispatchSetPressed(boolean pressed) { 12569 } 12570 12571 /** 12572 * Indicates whether the view is currently in pressed state. Unless 12573 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 12574 * the pressed state. 12575 * 12576 * @see #setPressed(boolean) 12577 * @see #isClickable() 12578 * @see #setClickable(boolean) 12579 * 12580 * @return true if the view is currently pressed, false otherwise 12581 */ 12582 @ViewDebug.ExportedProperty 12583 @InspectableProperty(hasAttributeId = false) isPressed()12584 public boolean isPressed() { 12585 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 12586 } 12587 12588 /** 12589 * @hide 12590 * Indicates whether this view will participate in data collection through 12591 * {@link ViewStructure}. If true, it will not provide any data 12592 * for itself or its children. If false, the normal data collection will be allowed. 12593 * 12594 * @return Returns false if assist data collection is not blocked, else true. 12595 * 12596 * @see #setAssistBlocked(boolean) 12597 * @attr ref android.R.styleable#View_assistBlocked 12598 */ isAssistBlocked()12599 public boolean isAssistBlocked() { 12600 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 12601 } 12602 12603 /** 12604 * @hide 12605 * Controls whether assist data collection from this view and its children is enabled 12606 * (that is, whether {@link #onProvideStructure} and 12607 * {@link #onProvideVirtualStructure} will be called). The default value is false, 12608 * allowing normal assist collection. Setting this to false will disable assist collection. 12609 * 12610 * @param enabled Set to true to <em>disable</em> assist data collection, or false 12611 * (the default) to allow it. 12612 * 12613 * @see #isAssistBlocked() 12614 * @see #onProvideStructure 12615 * @see #onProvideVirtualStructure 12616 * @attr ref android.R.styleable#View_assistBlocked 12617 */ 12618 @UnsupportedAppUsage setAssistBlocked(boolean enabled)12619 public void setAssistBlocked(boolean enabled) { 12620 if (enabled) { 12621 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 12622 } else { 12623 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 12624 } 12625 } 12626 12627 /** 12628 * Indicates whether this view will save its state (that is, 12629 * whether its {@link #onSaveInstanceState} method will be called). 12630 * 12631 * @return Returns true if the view state saving is enabled, else false. 12632 * 12633 * @see #setSaveEnabled(boolean) 12634 * @attr ref android.R.styleable#View_saveEnabled 12635 */ 12636 @InspectableProperty isSaveEnabled()12637 public boolean isSaveEnabled() { 12638 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 12639 } 12640 12641 /** 12642 * Controls whether the saving of this view's state is 12643 * enabled (that is, whether its {@link #onSaveInstanceState} method 12644 * will be called). Note that even if freezing is enabled, the 12645 * view still must have an id assigned to it (via {@link #setId(int)}) 12646 * for its state to be saved. This flag can only disable the 12647 * saving of this view; any child views may still have their state saved. 12648 * 12649 * @param enabled Set to false to <em>disable</em> state saving, or true 12650 * (the default) to allow it. 12651 * 12652 * @see #isSaveEnabled() 12653 * @see #setId(int) 12654 * @see #onSaveInstanceState() 12655 * @attr ref android.R.styleable#View_saveEnabled 12656 */ setSaveEnabled(boolean enabled)12657 public void setSaveEnabled(boolean enabled) { 12658 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 12659 } 12660 12661 /** 12662 * Gets whether the framework should discard touches when the view's 12663 * window is obscured by another visible window. 12664 * Refer to the {@link View} security documentation for more details. 12665 * 12666 * @return True if touch filtering is enabled. 12667 * 12668 * @see #setFilterTouchesWhenObscured(boolean) 12669 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12670 */ 12671 @ViewDebug.ExportedProperty 12672 @InspectableProperty getFilterTouchesWhenObscured()12673 public boolean getFilterTouchesWhenObscured() { 12674 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 12675 } 12676 12677 /** 12678 * Sets whether the framework should discard touches when the view's 12679 * window is obscured by another visible window. 12680 * Refer to the {@link View} security documentation for more details. 12681 * 12682 * @param enabled True if touch filtering should be enabled. 12683 * 12684 * @see #getFilterTouchesWhenObscured 12685 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12686 */ setFilterTouchesWhenObscured(boolean enabled)12687 public void setFilterTouchesWhenObscured(boolean enabled) { 12688 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 12689 FILTER_TOUCHES_WHEN_OBSCURED); 12690 } 12691 12692 /** 12693 * Indicates whether the entire hierarchy under this view will save its 12694 * state when a state saving traversal occurs from its parent. The default 12695 * is true; if false, these views will not be saved unless 12696 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12697 * 12698 * @return Returns true if the view state saving from parent is enabled, else false. 12699 * 12700 * @see #setSaveFromParentEnabled(boolean) 12701 */ isSaveFromParentEnabled()12702 public boolean isSaveFromParentEnabled() { 12703 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 12704 } 12705 12706 /** 12707 * Controls whether the entire hierarchy under this view will save its 12708 * state when a state saving traversal occurs from its parent. The default 12709 * is true; if false, these views will not be saved unless 12710 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12711 * 12712 * @param enabled Set to false to <em>disable</em> state saving, or true 12713 * (the default) to allow it. 12714 * 12715 * @see #isSaveFromParentEnabled() 12716 * @see #setId(int) 12717 * @see #onSaveInstanceState() 12718 */ setSaveFromParentEnabled(boolean enabled)12719 public void setSaveFromParentEnabled(boolean enabled) { 12720 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 12721 } 12722 12723 12724 /** 12725 * Returns whether this View is currently able to take focus. 12726 * 12727 * @return True if this view can take focus, or false otherwise. 12728 */ 12729 @ViewDebug.ExportedProperty(category = "focus") isFocusable()12730 public final boolean isFocusable() { 12731 return FOCUSABLE == (mViewFlags & FOCUSABLE); 12732 } 12733 12734 /** 12735 * Returns the focusable setting for this view. 12736 * 12737 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 12738 * @attr ref android.R.styleable#View_focusable 12739 */ 12740 @ViewDebug.ExportedProperty(mapping = { 12741 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 12742 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 12743 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 12744 }, category = "focus") 12745 @InspectableProperty(enumMapping = { 12746 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 12747 @EnumEntry(value = FOCUSABLE, name = "true"), 12748 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 12749 }) 12750 @Focusable getFocusable()12751 public int getFocusable() { 12752 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 12753 } 12754 12755 /** 12756 * When a view is focusable, it may not want to take focus when in touch mode. 12757 * For example, a button would like focus when the user is navigating via a D-pad 12758 * so that the user can click on it, but once the user starts touching the screen, 12759 * the button shouldn't take focus 12760 * @return Whether the view is focusable in touch mode. 12761 * @attr ref android.R.styleable#View_focusableInTouchMode 12762 */ 12763 @ViewDebug.ExportedProperty(category = "focus") 12764 @InspectableProperty isFocusableInTouchMode()12765 public final boolean isFocusableInTouchMode() { 12766 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 12767 } 12768 12769 /** 12770 * Returns whether the view should be treated as a focusable unit by screen reader 12771 * accessibility tools. 12772 * @see #setScreenReaderFocusable(boolean) 12773 * 12774 * @return Whether the view should be treated as a focusable unit by screen reader. 12775 * 12776 * @attr ref android.R.styleable#View_screenReaderFocusable 12777 */ 12778 @InspectableProperty isScreenReaderFocusable()12779 public boolean isScreenReaderFocusable() { 12780 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 12781 } 12782 12783 /** 12784 * Sets whether this View should be a focusable element for screen readers 12785 * and include non-focusable Views from its subtree when providing feedback. 12786 * <p> 12787 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 12788 * but does not impact input focus behavior. 12789 * 12790 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 12791 * accessibility tools. 12792 * 12793 * @attr ref android.R.styleable#View_screenReaderFocusable 12794 */ setScreenReaderFocusable(boolean screenReaderFocusable)12795 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 12796 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 12797 } 12798 12799 /** 12800 * Gets whether this view is a heading for accessibility purposes. 12801 * 12802 * @return {@code true} if the view is a heading, {@code false} otherwise. 12803 * 12804 * @attr ref android.R.styleable#View_accessibilityHeading 12805 */ 12806 @InspectableProperty isAccessibilityHeading()12807 public boolean isAccessibilityHeading() { 12808 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 12809 } 12810 12811 /** 12812 * Set if view is a heading for a section of content for accessibility purposes. 12813 * 12814 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 12815 * 12816 * @attr ref android.R.styleable#View_accessibilityHeading 12817 */ setAccessibilityHeading(boolean isHeading)12818 public void setAccessibilityHeading(boolean isHeading) { 12819 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 12820 } 12821 updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue)12822 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 12823 int pflags3 = mPrivateFlags3; 12824 if (newValue) { 12825 pflags3 |= mask; 12826 } else { 12827 pflags3 &= ~mask; 12828 } 12829 12830 if (pflags3 != mPrivateFlags3) { 12831 mPrivateFlags3 = pflags3; 12832 notifyViewAccessibilityStateChangedIfNeeded( 12833 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12834 } 12835 } 12836 12837 /** 12838 * Find the nearest view in the specified direction that can take focus. 12839 * This does not actually give focus to that view. 12840 * 12841 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12842 * 12843 * @return The nearest focusable in the specified direction, or null if none 12844 * can be found. 12845 */ focusSearch(@ocusRealDirection int direction)12846 public View focusSearch(@FocusRealDirection int direction) { 12847 if (mParent != null) { 12848 return mParent.focusSearch(this, direction); 12849 } else { 12850 return null; 12851 } 12852 } 12853 12854 /** 12855 * Returns whether this View is a root of a keyboard navigation cluster. 12856 * 12857 * @return True if this view is a root of a cluster, or false otherwise. 12858 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12859 */ 12860 @ViewDebug.ExportedProperty(category = "focus") 12861 @InspectableProperty isKeyboardNavigationCluster()12862 public final boolean isKeyboardNavigationCluster() { 12863 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 12864 } 12865 12866 /** 12867 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 12868 * will be ignored. 12869 * 12870 * @return the keyboard navigation cluster that this view is in (can be this view) 12871 * or {@code null} if not in one 12872 */ findKeyboardNavigationCluster()12873 View findKeyboardNavigationCluster() { 12874 if (mParent instanceof View) { 12875 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 12876 if (cluster != null) { 12877 return cluster; 12878 } else if (isKeyboardNavigationCluster()) { 12879 return this; 12880 } 12881 } 12882 return null; 12883 } 12884 12885 /** 12886 * Set whether this view is a root of a keyboard navigation cluster. 12887 * 12888 * @param isCluster If true, this view is a root of a cluster. 12889 * 12890 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12891 */ setKeyboardNavigationCluster(boolean isCluster)12892 public void setKeyboardNavigationCluster(boolean isCluster) { 12893 if (isCluster) { 12894 mPrivateFlags3 |= PFLAG3_CLUSTER; 12895 } else { 12896 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 12897 } 12898 } 12899 12900 /** 12901 * Sets this View as the one which receives focus the next time cluster navigation jumps 12902 * to the cluster containing this View. This does NOT change focus even if the cluster 12903 * containing this view is current. 12904 * 12905 * @hide 12906 */ 12907 @TestApi setFocusedInCluster()12908 public final void setFocusedInCluster() { 12909 setFocusedInCluster(findKeyboardNavigationCluster()); 12910 } 12911 setFocusedInCluster(View cluster)12912 private void setFocusedInCluster(View cluster) { 12913 if (this instanceof ViewGroup) { 12914 ((ViewGroup) this).mFocusedInCluster = null; 12915 } 12916 if (cluster == this) { 12917 return; 12918 } 12919 ViewParent parent = mParent; 12920 View child = this; 12921 while (parent instanceof ViewGroup) { 12922 ((ViewGroup) parent).mFocusedInCluster = child; 12923 if (parent == cluster) { 12924 break; 12925 } 12926 child = (View) parent; 12927 parent = parent.getParent(); 12928 } 12929 } 12930 updateFocusedInCluster(View oldFocus, @FocusDirection int direction)12931 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 12932 if (oldFocus != null) { 12933 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 12934 View cluster = findKeyboardNavigationCluster(); 12935 if (oldCluster != cluster) { 12936 // Going from one cluster to another, so save last-focused. 12937 // This covers cluster jumps because they are always FOCUS_DOWN 12938 oldFocus.setFocusedInCluster(oldCluster); 12939 if (!(oldFocus.mParent instanceof ViewGroup)) { 12940 return; 12941 } 12942 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 12943 // This is a result of ordered navigation so consider navigation through 12944 // the previous cluster "complete" and clear its last-focused memory. 12945 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12946 } else if (oldFocus instanceof ViewGroup 12947 && ((ViewGroup) oldFocus).getDescendantFocusability() 12948 == ViewGroup.FOCUS_AFTER_DESCENDANTS 12949 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 12950 // This means oldFocus is not focusable since it obviously has a focusable 12951 // child (this). Don't restore focus to it in the future. 12952 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12953 } 12954 } 12955 } 12956 } 12957 12958 /** 12959 * Returns whether this View should receive focus when the focus is restored for the view 12960 * hierarchy containing this view. 12961 * <p> 12962 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12963 * window or serves as a target of cluster navigation. 12964 * 12965 * @see #restoreDefaultFocus() 12966 * 12967 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 12968 * @attr ref android.R.styleable#View_focusedByDefault 12969 */ 12970 @ViewDebug.ExportedProperty(category = "focus") 12971 @InspectableProperty isFocusedByDefault()12972 public final boolean isFocusedByDefault() { 12973 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 12974 } 12975 12976 /** 12977 * Sets whether this View should receive focus when the focus is restored for the view 12978 * hierarchy containing this view. 12979 * <p> 12980 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12981 * window or serves as a target of cluster navigation. 12982 * 12983 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 12984 * {@code false} otherwise. 12985 * 12986 * @see #restoreDefaultFocus() 12987 * 12988 * @attr ref android.R.styleable#View_focusedByDefault 12989 */ 12990 @RemotableViewMethod setFocusedByDefault(boolean isFocusedByDefault)12991 public void setFocusedByDefault(boolean isFocusedByDefault) { 12992 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 12993 return; 12994 } 12995 12996 if (isFocusedByDefault) { 12997 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 12998 } else { 12999 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 13000 } 13001 13002 if (mParent instanceof ViewGroup) { 13003 if (isFocusedByDefault) { 13004 ((ViewGroup) mParent).setDefaultFocus(this); 13005 } else { 13006 ((ViewGroup) mParent).clearDefaultFocus(this); 13007 } 13008 } 13009 } 13010 13011 /** 13012 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 13013 * 13014 * @return {@code true} if this view has default focus, {@code false} otherwise 13015 */ hasDefaultFocus()13016 boolean hasDefaultFocus() { 13017 return isFocusedByDefault(); 13018 } 13019 13020 /** 13021 * Find the nearest keyboard navigation cluster in the specified direction. 13022 * This does not actually give focus to that cluster. 13023 * 13024 * @param currentCluster The starting point of the search. Null means the current cluster is not 13025 * found yet 13026 * @param direction Direction to look 13027 * 13028 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 13029 * can be found 13030 */ keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)13031 public View keyboardNavigationClusterSearch(View currentCluster, 13032 @FocusDirection int direction) { 13033 if (isKeyboardNavigationCluster()) { 13034 currentCluster = this; 13035 } 13036 if (isRootNamespace()) { 13037 // Root namespace means we should consider ourselves the top of the 13038 // tree for group searching; otherwise we could be group searching 13039 // into other tabs. see LocalActivityManager and TabHost for more info. 13040 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 13041 this, currentCluster, direction); 13042 } else if (mParent != null) { 13043 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 13044 } 13045 return null; 13046 } 13047 13048 /** 13049 * This method is the last chance for the focused view and its ancestors to 13050 * respond to an arrow key. This is called when the focused view did not 13051 * consume the key internally, nor could the view system find a new view in 13052 * the requested direction to give focus to. 13053 * 13054 * @param focused The currently focused view. 13055 * @param direction The direction focus wants to move. One of FOCUS_UP, 13056 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 13057 * @return True if the this view consumed this unhandled move. 13058 */ dispatchUnhandledMove(View focused, @FocusRealDirection int direction)13059 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 13060 return false; 13061 } 13062 13063 /** 13064 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 13065 * have {@link android.R.attr#state_focused} defined in its background. 13066 * 13067 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 13068 * highlight, {@code false} otherwise. 13069 * 13070 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 13071 */ setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled)13072 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 13073 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 13074 } 13075 13076 /** 13077 13078 /** 13079 * Returns whether this View should use a default focus highlight when it gets focused but 13080 * doesn't have {@link android.R.attr#state_focused} defined in its background. 13081 * 13082 * @return True if this View should use a default focus highlight. 13083 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 13084 */ 13085 @ViewDebug.ExportedProperty(category = "focus") 13086 @InspectableProperty getDefaultFocusHighlightEnabled()13087 public final boolean getDefaultFocusHighlightEnabled() { 13088 return mDefaultFocusHighlightEnabled; 13089 } 13090 13091 /** 13092 * If a user manually specified the next view id for a particular direction, 13093 * use the root to look up the view. 13094 * @param root The root view of the hierarchy containing this view. 13095 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 13096 * or FOCUS_BACKWARD. 13097 * @return The user specified next view, or null if there is none. 13098 */ findUserSetNextFocus(View root, @FocusDirection int direction)13099 View findUserSetNextFocus(View root, @FocusDirection int direction) { 13100 switch (direction) { 13101 case FOCUS_LEFT: 13102 if (mNextFocusLeftId == View.NO_ID) return null; 13103 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 13104 case FOCUS_RIGHT: 13105 if (mNextFocusRightId == View.NO_ID) return null; 13106 return findViewInsideOutShouldExist(root, mNextFocusRightId); 13107 case FOCUS_UP: 13108 if (mNextFocusUpId == View.NO_ID) return null; 13109 return findViewInsideOutShouldExist(root, mNextFocusUpId); 13110 case FOCUS_DOWN: 13111 if (mNextFocusDownId == View.NO_ID) return null; 13112 return findViewInsideOutShouldExist(root, mNextFocusDownId); 13113 case FOCUS_FORWARD: 13114 if (mNextFocusForwardId == View.NO_ID) return null; 13115 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 13116 case FOCUS_BACKWARD: { 13117 if (mID == View.NO_ID) return null; 13118 final View rootView = root; 13119 final View startView = this; 13120 // Since we have forward links but no backward links, we need to find the view that 13121 // forward links to this view. We can't just find the view with the specified ID 13122 // because view IDs need not be unique throughout the tree. 13123 return root.findViewByPredicateInsideOut(startView, 13124 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 13125 == startView); 13126 } 13127 } 13128 return null; 13129 } 13130 13131 /** 13132 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 13133 * use the root to look up the view. 13134 * 13135 * @param root the root view of the hierarchy containing this view 13136 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 13137 * @return the user-specified next cluster, or {@code null} if there is none 13138 */ findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction)13139 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 13140 switch (direction) { 13141 case FOCUS_FORWARD: 13142 if (mNextClusterForwardId == View.NO_ID) return null; 13143 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 13144 case FOCUS_BACKWARD: { 13145 if (mID == View.NO_ID) return null; 13146 final int id = mID; 13147 return root.findViewByPredicateInsideOut(this, 13148 (Predicate<View>) t -> t.mNextClusterForwardId == id); 13149 } 13150 } 13151 return null; 13152 } 13153 findViewInsideOutShouldExist(View root, int id)13154 private View findViewInsideOutShouldExist(View root, int id) { 13155 return findViewInsideOutShouldExist(root, this, id); 13156 } 13157 findViewInsideOutShouldExist(View root, View start, int id)13158 private View findViewInsideOutShouldExist(View root, View start, int id) { 13159 if (mMatchIdPredicate == null) { 13160 mMatchIdPredicate = new MatchIdPredicate(); 13161 } 13162 mMatchIdPredicate.mId = id; 13163 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 13164 if (result == null) { 13165 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 13166 } 13167 return result; 13168 } 13169 13170 /** 13171 * Find and return all focusable views that are descendants of this view, 13172 * possibly including this view if it is focusable itself. 13173 * 13174 * @param direction The direction of the focus 13175 * @return A list of focusable views 13176 */ getFocusables(@ocusDirection int direction)13177 public ArrayList<View> getFocusables(@FocusDirection int direction) { 13178 ArrayList<View> result = new ArrayList<View>(24); 13179 addFocusables(result, direction); 13180 return result; 13181 } 13182 13183 /** 13184 * Add any focusable views that are descendants of this view (possibly 13185 * including this view if it is focusable itself) to views. If we are in touch mode, 13186 * only add views that are also focusable in touch mode. 13187 * 13188 * @param views Focusable views found so far 13189 * @param direction The direction of the focus 13190 */ addFocusables(ArrayList<View> views, @FocusDirection int direction)13191 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 13192 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 13193 } 13194 13195 /** 13196 * Adds any focusable views that are descendants of this view (possibly 13197 * including this view if it is focusable itself) to views. This method 13198 * adds all focusable views regardless if we are in touch mode or 13199 * only views focusable in touch mode if we are in touch mode or 13200 * only views that can take accessibility focus if accessibility is enabled 13201 * depending on the focusable mode parameter. 13202 * 13203 * @param views Focusable views found so far or null if all we are interested is 13204 * the number of focusables. 13205 * @param direction The direction of the focus. 13206 * @param focusableMode The type of focusables to be added. 13207 * 13208 * @see #FOCUSABLES_ALL 13209 * @see #FOCUSABLES_TOUCH_MODE 13210 */ addFocusables(ArrayList<View> views, @FocusDirection int direction, @FocusableMode int focusableMode)13211 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 13212 @FocusableMode int focusableMode) { 13213 if (views == null) { 13214 return; 13215 } 13216 if (!canTakeFocus()) { 13217 return; 13218 } 13219 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 13220 && !isFocusableInTouchMode()) { 13221 return; 13222 } 13223 views.add(this); 13224 } 13225 13226 /** 13227 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 13228 * including this view if it is a cluster root itself) to views. 13229 * 13230 * @param views Keyboard navigation cluster roots found so far 13231 * @param direction Direction to look 13232 */ addKeyboardNavigationClusters( @onNull Collection<View> views, int direction)13233 public void addKeyboardNavigationClusters( 13234 @NonNull Collection<View> views, 13235 int direction) { 13236 if (!isKeyboardNavigationCluster()) { 13237 return; 13238 } 13239 if (!hasFocusable()) { 13240 return; 13241 } 13242 views.add(this); 13243 } 13244 13245 /** 13246 * Finds the Views that contain given text. The containment is case insensitive. 13247 * The search is performed by either the text that the View renders or the content 13248 * description that describes the view for accessibility purposes and the view does 13249 * not render or both. Clients can specify how the search is to be performed via 13250 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 13251 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 13252 * 13253 * @param outViews The output list of matching Views. 13254 * @param searched The text to match against. 13255 * 13256 * @see #FIND_VIEWS_WITH_TEXT 13257 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 13258 * @see #setContentDescription(CharSequence) 13259 */ findViewsWithText(ArrayList<View> outViews, CharSequence searched, @FindViewFlags int flags)13260 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 13261 @FindViewFlags int flags) { 13262 if (getAccessibilityNodeProvider() != null) { 13263 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 13264 outViews.add(this); 13265 } 13266 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 13267 && (searched != null && searched.length() > 0) 13268 && (mContentDescription != null && mContentDescription.length() > 0)) { 13269 String searchedLowerCase = searched.toString().toLowerCase(); 13270 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 13271 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 13272 outViews.add(this); 13273 } 13274 } 13275 } 13276 13277 /** 13278 * Find and return all touchable views that are descendants of this view, 13279 * possibly including this view if it is touchable itself. 13280 * 13281 * @return A list of touchable views 13282 */ getTouchables()13283 public ArrayList<View> getTouchables() { 13284 ArrayList<View> result = new ArrayList<View>(); 13285 addTouchables(result); 13286 return result; 13287 } 13288 13289 /** 13290 * Add any touchable views that are descendants of this view (possibly 13291 * including this view if it is touchable itself) to views. 13292 * 13293 * @param views Touchable views found so far 13294 */ addTouchables(ArrayList<View> views)13295 public void addTouchables(ArrayList<View> views) { 13296 final int viewFlags = mViewFlags; 13297 13298 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 13299 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 13300 && (viewFlags & ENABLED_MASK) == ENABLED) { 13301 views.add(this); 13302 } 13303 } 13304 13305 /** 13306 * Returns whether this View is accessibility focused. 13307 * 13308 * @return True if this View is accessibility focused. 13309 */ 13310 @InspectableProperty(hasAttributeId = false) isAccessibilityFocused()13311 public boolean isAccessibilityFocused() { 13312 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 13313 } 13314 13315 /** 13316 * Call this to try to give accessibility focus to this view. 13317 * 13318 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 13319 * returns false or the view is no visible or the view already has accessibility 13320 * focus. 13321 * 13322 * See also {@link #focusSearch(int)}, which is what you call to say that you 13323 * have focus, and you want your parent to look for the next one. 13324 * 13325 * @return Whether this view actually took accessibility focus. 13326 * 13327 * @hide 13328 */ 13329 @UnsupportedAppUsage requestAccessibilityFocus()13330 public boolean requestAccessibilityFocus() { 13331 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 13332 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 13333 return false; 13334 } 13335 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 13336 return false; 13337 } 13338 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 13339 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 13340 ViewRootImpl viewRootImpl = getViewRootImpl(); 13341 if (viewRootImpl != null) { 13342 viewRootImpl.setAccessibilityFocus(this, null); 13343 } 13344 invalidate(); 13345 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 13346 return true; 13347 } 13348 return false; 13349 } 13350 13351 /** 13352 * Call this to try to clear accessibility focus of this view. 13353 * 13354 * See also {@link #focusSearch(int)}, which is what you call to say that you 13355 * have focus, and you want your parent to look for the next one. 13356 * 13357 * @hide 13358 */ 13359 @UnsupportedAppUsage clearAccessibilityFocus()13360 public void clearAccessibilityFocus() { 13361 clearAccessibilityFocusNoCallbacks(0); 13362 13363 // Clear the global reference of accessibility focus if this view or 13364 // any of its descendants had accessibility focus. This will NOT send 13365 // an event or update internal state if focus is cleared from a 13366 // descendant view, which may leave views in inconsistent states. 13367 final ViewRootImpl viewRootImpl = getViewRootImpl(); 13368 if (viewRootImpl != null) { 13369 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 13370 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13371 viewRootImpl.setAccessibilityFocus(null, null); 13372 } 13373 } 13374 } 13375 sendAccessibilityHoverEvent(int eventType)13376 private void sendAccessibilityHoverEvent(int eventType) { 13377 // Since we are not delivering to a client accessibility events from not 13378 // important views (unless the clinet request that) we need to fire the 13379 // event from the deepest view exposed to the client. As a consequence if 13380 // the user crosses a not exposed view the client will see enter and exit 13381 // of the exposed predecessor followed by and enter and exit of that same 13382 // predecessor when entering and exiting the not exposed descendant. This 13383 // is fine since the client has a clear idea which view is hovered at the 13384 // price of a couple more events being sent. This is a simple and 13385 // working solution. 13386 View source = this; 13387 while (true) { 13388 if (source.includeForAccessibility()) { 13389 source.sendAccessibilityEvent(eventType); 13390 return; 13391 } 13392 ViewParent parent = source.getParent(); 13393 if (parent instanceof View) { 13394 source = (View) parent; 13395 } else { 13396 return; 13397 } 13398 } 13399 } 13400 13401 /** 13402 * Clears accessibility focus without calling any callback methods 13403 * normally invoked in {@link #clearAccessibilityFocus()}. This method 13404 * is used separately from that one for clearing accessibility focus when 13405 * giving this focus to another view. 13406 * 13407 * @param action The action, if any, that led to focus being cleared. Set to 13408 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 13409 * the window. 13410 */ clearAccessibilityFocusNoCallbacks(int action)13411 void clearAccessibilityFocusNoCallbacks(int action) { 13412 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 13413 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 13414 invalidate(); 13415 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13416 AccessibilityEvent event = AccessibilityEvent.obtain( 13417 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 13418 event.setAction(action); 13419 if (mAccessibilityDelegate != null) { 13420 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 13421 } else { 13422 sendAccessibilityEventUnchecked(event); 13423 } 13424 } 13425 } 13426 } 13427 13428 /** 13429 * Call this to try to give focus to a specific view or to one of its 13430 * descendants. 13431 * 13432 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13433 * false), or if it can't be focused due to other conditions (not focusable in touch mode 13434 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 13435 * enabled, or has no size). 13436 * 13437 * See also {@link #focusSearch(int)}, which is what you call to say that you 13438 * have focus, and you want your parent to look for the next one. 13439 * 13440 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 13441 * {@link #FOCUS_DOWN} and <code>null</code>. 13442 * 13443 * @return Whether this view or one of its descendants actually took focus. 13444 */ requestFocus()13445 public final boolean requestFocus() { 13446 return requestFocus(View.FOCUS_DOWN); 13447 } 13448 13449 /** 13450 * This will request focus for whichever View was last focused within this 13451 * cluster before a focus-jump out of it. 13452 * 13453 * @hide 13454 */ 13455 @TestApi restoreFocusInCluster(@ocusRealDirection int direction)13456 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 13457 // Prioritize focusableByDefault over algorithmic focus selection. 13458 if (restoreDefaultFocus()) { 13459 return true; 13460 } 13461 return requestFocus(direction); 13462 } 13463 13464 /** 13465 * This will request focus for whichever View not in a cluster was last focused before a 13466 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 13467 * the "first" focusable view it finds. 13468 * 13469 * @hide 13470 */ 13471 @TestApi restoreFocusNotInCluster()13472 public boolean restoreFocusNotInCluster() { 13473 return requestFocus(View.FOCUS_DOWN); 13474 } 13475 13476 /** 13477 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 13478 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 13479 * 13480 * @return Whether this view or one of its descendants actually took focus 13481 */ restoreDefaultFocus()13482 public boolean restoreDefaultFocus() { 13483 return requestFocus(View.FOCUS_DOWN); 13484 } 13485 13486 /** 13487 * Call this to try to give focus to a specific view or to one of its 13488 * descendants and give it a hint about what direction focus is heading. 13489 * 13490 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13491 * false), or if it is focusable and it is not focusable in touch mode 13492 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13493 * 13494 * See also {@link #focusSearch(int)}, which is what you call to say that you 13495 * have focus, and you want your parent to look for the next one. 13496 * 13497 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 13498 * <code>null</code> set for the previously focused rectangle. 13499 * 13500 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13501 * @return Whether this view or one of its descendants actually took focus. 13502 */ requestFocus(int direction)13503 public final boolean requestFocus(int direction) { 13504 return requestFocus(direction, null); 13505 } 13506 13507 /** 13508 * Call this to try to give focus to a specific view or to one of its descendants 13509 * and give it hints about the direction and a specific rectangle that the focus 13510 * is coming from. The rectangle can help give larger views a finer grained hint 13511 * about where focus is coming from, and therefore, where to show selection, or 13512 * forward focus change internally. 13513 * 13514 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13515 * false), or if it is focusable and it is not focusable in touch mode 13516 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13517 * 13518 * A View will not take focus if it is not visible. 13519 * 13520 * A View will not take focus if one of its parents has 13521 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 13522 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 13523 * 13524 * See also {@link #focusSearch(int)}, which is what you call to say that you 13525 * have focus, and you want your parent to look for the next one. 13526 * 13527 * You may wish to override this method if your custom {@link View} has an internal 13528 * {@link View} that it wishes to forward the request to. 13529 * 13530 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13531 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 13532 * to give a finer grained hint about where focus is coming from. May be null 13533 * if there is no hint. 13534 * @return Whether this view or one of its descendants actually took focus. 13535 */ requestFocus(int direction, Rect previouslyFocusedRect)13536 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 13537 return requestFocusNoSearch(direction, previouslyFocusedRect); 13538 } 13539 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)13540 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 13541 // need to be focusable 13542 if (!canTakeFocus()) { 13543 return false; 13544 } 13545 13546 // need to be focusable in touch mode if in touch mode 13547 if (isInTouchMode() && 13548 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 13549 return false; 13550 } 13551 13552 // need to not have any parents blocking us 13553 if (hasAncestorThatBlocksDescendantFocus()) { 13554 return false; 13555 } 13556 13557 if (!isLayoutValid()) { 13558 mPrivateFlags |= PFLAG_WANTS_FOCUS; 13559 } else { 13560 clearParentsWantFocus(); 13561 } 13562 13563 handleFocusGainInternal(direction, previouslyFocusedRect); 13564 return true; 13565 } 13566 clearParentsWantFocus()13567 void clearParentsWantFocus() { 13568 if (mParent instanceof View) { 13569 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 13570 ((View) mParent).clearParentsWantFocus(); 13571 } 13572 } 13573 13574 /** 13575 * Call this to try to give focus to a specific view or to one of its descendants. This is a 13576 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 13577 * touch mode to request focus when they are touched. 13578 * 13579 * @return Whether this view or one of its descendants actually took focus. 13580 * 13581 * @see #isInTouchMode() 13582 * 13583 */ requestFocusFromTouch()13584 public final boolean requestFocusFromTouch() { 13585 // Leave touch mode if we need to 13586 if (isInTouchMode()) { 13587 ViewRootImpl viewRoot = getViewRootImpl(); 13588 if (viewRoot != null) { 13589 viewRoot.ensureTouchMode(false); 13590 } 13591 } 13592 return requestFocus(View.FOCUS_DOWN); 13593 } 13594 13595 /** 13596 * @return Whether any ancestor of this view blocks descendant focus. 13597 */ hasAncestorThatBlocksDescendantFocus()13598 private boolean hasAncestorThatBlocksDescendantFocus() { 13599 final boolean focusableInTouchMode = isFocusableInTouchMode(); 13600 ViewParent ancestor = mParent; 13601 while (ancestor instanceof ViewGroup) { 13602 final ViewGroup vgAncestor = (ViewGroup) ancestor; 13603 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 13604 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 13605 return true; 13606 } else { 13607 ancestor = vgAncestor.getParent(); 13608 } 13609 } 13610 return false; 13611 } 13612 13613 /** 13614 * Gets the mode for determining whether this View is important for accessibility. 13615 * A view is important for accessibility if it fires accessibility events and if it 13616 * is reported to accessibility services that query the screen. 13617 * 13618 * @return The mode for determining whether a view is important for accessibility, one 13619 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 13620 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 13621 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 13622 * 13623 * @attr ref android.R.styleable#View_importantForAccessibility 13624 * 13625 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13626 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13627 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13628 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13629 */ 13630 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 13631 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 13632 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 13633 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 13634 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13635 to = "noHideDescendants") 13636 }) 13637 @InspectableProperty(enumMapping = { 13638 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 13639 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 13640 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 13641 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13642 name = "noHideDescendants"), 13643 }) getImportantForAccessibility()13644 public int getImportantForAccessibility() { 13645 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 13646 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 13647 } 13648 13649 /** 13650 * Sets the live region mode for this view. This indicates to accessibility 13651 * services whether they should automatically notify the user about changes 13652 * to the view's content description or text, or to the content descriptions 13653 * or text of the view's children (where applicable). 13654 * <p> 13655 * For example, in a login screen with a TextView that displays an "incorrect 13656 * password" notification, that view should be marked as a live region with 13657 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13658 * <p> 13659 * To disable change notifications for this view, use 13660 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 13661 * mode for most views. 13662 * <p> 13663 * To indicate that the user should be notified of changes, use 13664 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13665 * <p> 13666 * If the view's changes should interrupt ongoing speech and notify the user 13667 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 13668 * 13669 * @param mode The live region mode for this view, one of: 13670 * <ul> 13671 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 13672 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 13673 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 13674 * </ul> 13675 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13676 */ setAccessibilityLiveRegion(int mode)13677 public void setAccessibilityLiveRegion(int mode) { 13678 if (mode != getAccessibilityLiveRegion()) { 13679 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13680 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 13681 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13682 notifyViewAccessibilityStateChangedIfNeeded( 13683 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13684 } 13685 } 13686 13687 /** 13688 * Gets the live region mode for this View. 13689 * 13690 * @return The live region mode for the view. 13691 * 13692 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13693 * 13694 * @see #setAccessibilityLiveRegion(int) 13695 */ 13696 @InspectableProperty(enumMapping = { 13697 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 13698 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 13699 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 13700 }) getAccessibilityLiveRegion()13701 public int getAccessibilityLiveRegion() { 13702 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 13703 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 13704 } 13705 13706 /** 13707 * Sets how to determine whether this view is important for accessibility 13708 * which is if it fires accessibility events and if it is reported to 13709 * accessibility services that query the screen. 13710 * 13711 * @param mode How to determine whether this view is important for accessibility. 13712 * 13713 * @attr ref android.R.styleable#View_importantForAccessibility 13714 * 13715 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13716 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13717 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13718 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13719 */ setImportantForAccessibility(int mode)13720 public void setImportantForAccessibility(int mode) { 13721 final int oldMode = getImportantForAccessibility(); 13722 if (mode != oldMode) { 13723 final boolean hideDescendants = 13724 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 13725 13726 // If this node or its descendants are no longer important, try to 13727 // clear accessibility focus. 13728 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 13729 final View focusHost = findAccessibilityFocusHost(hideDescendants); 13730 if (focusHost != null) { 13731 focusHost.clearAccessibilityFocus(); 13732 } 13733 } 13734 13735 // If we're moving between AUTO and another state, we might not need 13736 // to send a subtree changed notification. We'll store the computed 13737 // importance, since we'll need to check it later to make sure. 13738 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 13739 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 13740 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 13741 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13742 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 13743 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13744 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 13745 notifySubtreeAccessibilityStateChangedIfNeeded(); 13746 } else { 13747 notifyViewAccessibilityStateChangedIfNeeded( 13748 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13749 } 13750 } 13751 } 13752 13753 /** 13754 * Returns the view within this view's hierarchy that is hosting 13755 * accessibility focus. 13756 * 13757 * @param searchDescendants whether to search for focus in descendant views 13758 * @return the view hosting accessibility focus, or {@code null} 13759 */ findAccessibilityFocusHost(boolean searchDescendants)13760 private View findAccessibilityFocusHost(boolean searchDescendants) { 13761 if (isAccessibilityFocusedViewOrHost()) { 13762 return this; 13763 } 13764 13765 if (searchDescendants) { 13766 final ViewRootImpl viewRoot = getViewRootImpl(); 13767 if (viewRoot != null) { 13768 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 13769 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13770 return focusHost; 13771 } 13772 } 13773 } 13774 13775 return null; 13776 } 13777 13778 /** 13779 * Computes whether this view should be exposed for accessibility. In 13780 * general, views that are interactive or provide information are exposed 13781 * while views that serve only as containers are hidden. 13782 * <p> 13783 * If an ancestor of this view has importance 13784 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 13785 * returns <code>false</code>. 13786 * <p> 13787 * Otherwise, the value is computed according to the view's 13788 * {@link #getImportantForAccessibility()} value: 13789 * <ol> 13790 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 13791 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 13792 * </code> 13793 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 13794 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 13795 * view satisfies any of the following: 13796 * <ul> 13797 * <li>Is actionable, e.g. {@link #isClickable()}, 13798 * {@link #isLongClickable()}, or {@link #isFocusable()} 13799 * <li>Has an {@link AccessibilityDelegate} 13800 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 13801 * {@link OnKeyListener}, etc. 13802 * <li>Is an accessibility live region, e.g. 13803 * {@link #getAccessibilityLiveRegion()} is not 13804 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 13805 * </ul> 13806 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 13807 * </ol> 13808 * 13809 * @return Whether the view is exposed for accessibility. 13810 * @see #setImportantForAccessibility(int) 13811 * @see #getImportantForAccessibility() 13812 */ isImportantForAccessibility()13813 public boolean isImportantForAccessibility() { 13814 final int mode = getImportantForAccessibility(); 13815 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 13816 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13817 return false; 13818 } 13819 13820 // Check parent mode to ensure we're not hidden. 13821 ViewParent parent = mParent; 13822 while (parent instanceof View) { 13823 if (((View) parent).getImportantForAccessibility() 13824 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13825 return false; 13826 } 13827 parent = parent.getParent(); 13828 } 13829 13830 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 13831 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 13832 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 13833 || isAccessibilityPane(); 13834 } 13835 13836 /** 13837 * Gets the parent for accessibility purposes. Note that the parent for 13838 * accessibility is not necessary the immediate parent. It is the first 13839 * predecessor that is important for accessibility. 13840 * 13841 * @return The parent for accessibility purposes. 13842 */ getParentForAccessibility()13843 public ViewParent getParentForAccessibility() { 13844 if (mParent instanceof View) { 13845 View parentView = (View) mParent; 13846 if (parentView.includeForAccessibility()) { 13847 return mParent; 13848 } else { 13849 return mParent.getParentForAccessibility(); 13850 } 13851 } 13852 return null; 13853 } 13854 13855 /** @hide */ getSelfOrParentImportantForA11y()13856 View getSelfOrParentImportantForA11y() { 13857 if (isImportantForAccessibility()) return this; 13858 ViewParent parent = getParentForAccessibility(); 13859 if (parent instanceof View) return (View) parent; 13860 return null; 13861 } 13862 13863 /** 13864 * Adds the children of this View relevant for accessibility to the given list 13865 * as output. Since some Views are not important for accessibility the added 13866 * child views are not necessarily direct children of this view, rather they are 13867 * the first level of descendants important for accessibility. 13868 * 13869 * @param outChildren The output list that will receive children for accessibility. 13870 */ addChildrenForAccessibility(ArrayList<View> outChildren)13871 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 13872 13873 } 13874 13875 /** 13876 * Whether to regard this view for accessibility. A view is regarded for 13877 * accessibility if it is important for accessibility or the querying 13878 * accessibility service has explicitly requested that view not 13879 * important for accessibility are regarded. 13880 * 13881 * @return Whether to regard the view for accessibility. 13882 * 13883 * @hide 13884 */ 13885 @UnsupportedAppUsage includeForAccessibility()13886 public boolean includeForAccessibility() { 13887 if (mAttachInfo != null) { 13888 return (mAttachInfo.mAccessibilityFetchFlags 13889 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 13890 || isImportantForAccessibility(); 13891 } 13892 return false; 13893 } 13894 13895 /** 13896 * Returns whether the View is considered actionable from 13897 * accessibility perspective. Such view are important for 13898 * accessibility. 13899 * 13900 * @return True if the view is actionable for accessibility. 13901 * 13902 * @hide 13903 */ isActionableForAccessibility()13904 public boolean isActionableForAccessibility() { 13905 return (isClickable() || isLongClickable() || isFocusable()); 13906 } 13907 13908 /** 13909 * Returns whether the View has registered callbacks which makes it 13910 * important for accessibility. 13911 * 13912 * @return True if the view is actionable for accessibility. 13913 */ hasListenersForAccessibility()13914 private boolean hasListenersForAccessibility() { 13915 ListenerInfo info = getListenerInfo(); 13916 return mTouchDelegate != null || info.mOnKeyListener != null 13917 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 13918 || info.mOnHoverListener != null || info.mOnDragListener != null; 13919 } 13920 13921 /** 13922 * Notifies that the accessibility state of this view changed. The change 13923 * is local to this view and does not represent structural changes such 13924 * as children and parent. For example, the view became focusable. The 13925 * notification is at at most once every 13926 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13927 * to avoid unnecessary load to the system. Also once a view has a pending 13928 * notification this method is a NOP until the notification has been sent. 13929 * 13930 * @hide 13931 */ 13932 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) notifyViewAccessibilityStateChangedIfNeeded(int changeType)13933 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 13934 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13935 return; 13936 } 13937 13938 // Changes to views with a pane title count as window state changes, as the pane title 13939 // marks them as significant parts of the UI. 13940 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 13941 && isAccessibilityPane()) { 13942 // If the pane isn't visible, content changed events are sufficient unless we're 13943 // reporting that the view just disappeared 13944 if ((getVisibility() == VISIBLE) 13945 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 13946 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13947 onInitializeAccessibilityEvent(event); 13948 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 13949 event.setContentChangeTypes(changeType); 13950 event.setSource(this); 13951 onPopulateAccessibilityEvent(event); 13952 if (mParent != null) { 13953 try { 13954 mParent.requestSendAccessibilityEvent(this, event); 13955 } catch (AbstractMethodError e) { 13956 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 13957 + " does not fully implement ViewParent", e); 13958 } 13959 } 13960 return; 13961 } 13962 } 13963 13964 // If this is a live region, we should send a subtree change event 13965 // from this view immediately. Otherwise, we can let it propagate up. 13966 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 13967 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13968 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 13969 event.setContentChangeTypes(changeType); 13970 sendAccessibilityEventUnchecked(event); 13971 } else if (mParent != null) { 13972 try { 13973 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 13974 } catch (AbstractMethodError e) { 13975 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13976 " does not fully implement ViewParent", e); 13977 } 13978 } 13979 } 13980 13981 /** 13982 * Notifies that the accessibility state of this view changed. The change 13983 * is *not* local to this view and does represent structural changes such 13984 * as children and parent. For example, the view size changed. The 13985 * notification is at at most once every 13986 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13987 * to avoid unnecessary load to the system. Also once a view has a pending 13988 * notification this method is a NOP until the notification has been sent. 13989 * 13990 * @hide 13991 */ 13992 @UnsupportedAppUsage notifySubtreeAccessibilityStateChangedIfNeeded()13993 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 13994 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13995 return; 13996 } 13997 13998 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 13999 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 14000 if (mParent != null) { 14001 try { 14002 mParent.notifySubtreeAccessibilityStateChanged( 14003 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 14004 } catch (AbstractMethodError e) { 14005 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 14006 " does not fully implement ViewParent", e); 14007 } 14008 } 14009 } 14010 } 14011 notifySubtreeAccessibilityStateChangedByParentIfNeeded()14012 private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { 14013 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 14014 return; 14015 } 14016 14017 final View sendA11yEventView = (View) getParentForAccessibility(); 14018 if (sendA11yEventView != null && sendA11yEventView.isShown()) { 14019 sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); 14020 } 14021 } 14022 14023 /** 14024 * Changes the visibility of this View without triggering any other changes. This should only 14025 * be used by animation frameworks, such as {@link android.transition.Transition}, where 14026 * visibility changes should not adjust focus or trigger a new layout. Application developers 14027 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 14028 * 14029 * <p>Only call this method when a temporary visibility must be applied during an 14030 * animation and the original visibility value is guaranteed to be reset after the 14031 * animation completes. Use {@link #setVisibility} in all other cases.</p> 14032 * 14033 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 14034 * @see #setVisibility(int) 14035 */ setTransitionVisibility(@isibility int visibility)14036 public void setTransitionVisibility(@Visibility int visibility) { 14037 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 14038 } 14039 14040 /** 14041 * Reset the flag indicating the accessibility state of the subtree rooted 14042 * at this view changed. 14043 */ resetSubtreeAccessibilityStateChanged()14044 void resetSubtreeAccessibilityStateChanged() { 14045 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 14046 } 14047 14048 /** 14049 * Report an accessibility action to this view's parents for delegated processing. 14050 * 14051 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 14052 * call this method to delegate an accessibility action to a supporting parent. If the parent 14053 * returns true from its 14054 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 14055 * method this method will return true to signify that the action was consumed.</p> 14056 * 14057 * <p>This method is useful for implementing nested scrolling child views. If 14058 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 14059 * a custom view implementation may invoke this method to allow a parent to consume the 14060 * scroll first. If this method returns true the custom view should skip its own scrolling 14061 * behavior.</p> 14062 * 14063 * @param action Accessibility action to delegate 14064 * @param arguments Optional action arguments 14065 * @return true if the action was consumed by a parent 14066 */ dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments)14067 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 14068 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 14069 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 14070 return true; 14071 } 14072 } 14073 return false; 14074 } 14075 14076 /** 14077 * Performs the specified accessibility action on the view. For 14078 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 14079 * <p> 14080 * If an {@link AccessibilityDelegate} has been specified via calling 14081 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 14082 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 14083 * is responsible for handling this call. 14084 * </p> 14085 * 14086 * <p>The default implementation will delegate 14087 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 14088 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 14089 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 14090 * 14091 * @param action The action to perform. 14092 * @param arguments Optional action arguments. 14093 * @return Whether the action was performed. 14094 */ performAccessibilityAction(int action, Bundle arguments)14095 public boolean performAccessibilityAction(int action, Bundle arguments) { 14096 if (mAccessibilityDelegate != null) { 14097 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 14098 } else { 14099 return performAccessibilityActionInternal(action, arguments); 14100 } 14101 } 14102 14103 /** 14104 * @see #performAccessibilityAction(int, Bundle) 14105 * 14106 * Note: Called from the default {@link AccessibilityDelegate}. 14107 * 14108 * @hide 14109 */ 14110 @UnsupportedAppUsage performAccessibilityActionInternal(int action, Bundle arguments)14111 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 14112 if (isNestedScrollingEnabled() 14113 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 14114 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 14115 || action == R.id.accessibilityActionScrollUp 14116 || action == R.id.accessibilityActionScrollLeft 14117 || action == R.id.accessibilityActionScrollDown 14118 || action == R.id.accessibilityActionScrollRight)) { 14119 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 14120 return true; 14121 } 14122 } 14123 14124 switch (action) { 14125 case AccessibilityNodeInfo.ACTION_CLICK: { 14126 if (isClickable()) { 14127 performClickInternal(); 14128 return true; 14129 } 14130 } break; 14131 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 14132 if (isLongClickable()) { 14133 performLongClick(); 14134 return true; 14135 } 14136 } break; 14137 case AccessibilityNodeInfo.ACTION_FOCUS: { 14138 if (!hasFocus()) { 14139 // Get out of touch mode since accessibility 14140 // wants to move focus around. 14141 getViewRootImpl().ensureTouchMode(false); 14142 return requestFocus(); 14143 } 14144 } break; 14145 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 14146 if (hasFocus()) { 14147 clearFocus(); 14148 return !isFocused(); 14149 } 14150 } break; 14151 case AccessibilityNodeInfo.ACTION_SELECT: { 14152 if (!isSelected()) { 14153 setSelected(true); 14154 return isSelected(); 14155 } 14156 } break; 14157 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 14158 if (isSelected()) { 14159 setSelected(false); 14160 return !isSelected(); 14161 } 14162 } break; 14163 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 14164 if (!isAccessibilityFocused()) { 14165 return requestAccessibilityFocus(); 14166 } 14167 } break; 14168 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 14169 if (isAccessibilityFocused()) { 14170 clearAccessibilityFocus(); 14171 return true; 14172 } 14173 } break; 14174 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 14175 if (arguments != null) { 14176 final int granularity = arguments.getInt( 14177 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 14178 final boolean extendSelection = arguments.getBoolean( 14179 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 14180 return traverseAtGranularity(granularity, true, extendSelection); 14181 } 14182 } break; 14183 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 14184 if (arguments != null) { 14185 final int granularity = arguments.getInt( 14186 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 14187 final boolean extendSelection = arguments.getBoolean( 14188 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 14189 return traverseAtGranularity(granularity, false, extendSelection); 14190 } 14191 } break; 14192 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 14193 CharSequence text = getIterableTextForAccessibility(); 14194 if (text == null) { 14195 return false; 14196 } 14197 final int start = (arguments != null) ? arguments.getInt( 14198 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 14199 final int end = (arguments != null) ? arguments.getInt( 14200 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 14201 // Only cursor position can be specified (selection length == 0) 14202 if ((getAccessibilitySelectionStart() != start 14203 || getAccessibilitySelectionEnd() != end) 14204 && (start == end)) { 14205 setAccessibilitySelection(start, end); 14206 notifyViewAccessibilityStateChangedIfNeeded( 14207 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14208 return true; 14209 } 14210 } break; 14211 case R.id.accessibilityActionShowOnScreen: { 14212 if (mAttachInfo != null) { 14213 final Rect r = mAttachInfo.mTmpInvalRect; 14214 getDrawingRect(r); 14215 return requestRectangleOnScreen(r, true); 14216 } 14217 } break; 14218 case R.id.accessibilityActionContextClick: { 14219 if (isContextClickable()) { 14220 performContextClick(); 14221 return true; 14222 } 14223 } break; 14224 case R.id.accessibilityActionShowTooltip: { 14225 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 14226 // Tooltip already showing 14227 return false; 14228 } 14229 return showLongClickTooltip(0, 0); 14230 } 14231 case R.id.accessibilityActionHideTooltip: { 14232 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 14233 // No tooltip showing 14234 return false; 14235 } 14236 hideTooltip(); 14237 return true; 14238 } 14239 } 14240 14241 if (action == R.id.accessibilityActionDragDrop) { 14242 if (!canAcceptAccessibilityDrop()) { 14243 return false; 14244 } 14245 try { 14246 if (mAttachInfo != null && mAttachInfo.mSession != null) { 14247 final int[] location = new int[2]; 14248 getLocationInWindow(location); 14249 final int centerX = location[0] + getWidth() / 2; 14250 final int centerY = location[1] + getHeight() / 2; 14251 return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, 14252 centerX, centerY); 14253 } 14254 } catch (RemoteException e) { 14255 Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); 14256 } 14257 return false; 14258 } else if (action == R.id.accessibilityActionDragCancel) { 14259 if (!startedSystemDragForAccessibility()) { 14260 return false; 14261 } 14262 if (mAttachInfo != null && mAttachInfo.mDragToken != null) { 14263 cancelDragAndDrop(); 14264 return true; 14265 } 14266 return false; 14267 } 14268 return false; 14269 } 14270 canAcceptAccessibilityDrop()14271 private boolean canAcceptAccessibilityDrop() { 14272 if (!canAcceptDrag()) { 14273 return false; 14274 } 14275 ListenerInfo li = mListenerInfo; 14276 return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); 14277 } 14278 traverseAtGranularity(int granularity, boolean forward, boolean extendSelection)14279 private boolean traverseAtGranularity(int granularity, boolean forward, 14280 boolean extendSelection) { 14281 CharSequence text = getIterableTextForAccessibility(); 14282 if (text == null || text.length() == 0) { 14283 return false; 14284 } 14285 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 14286 if (iterator == null) { 14287 return false; 14288 } 14289 int current = getAccessibilitySelectionEnd(); 14290 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14291 current = forward ? 0 : text.length(); 14292 } 14293 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 14294 if (range == null) { 14295 return false; 14296 } 14297 final int segmentStart = range[0]; 14298 final int segmentEnd = range[1]; 14299 int selectionStart; 14300 int selectionEnd; 14301 if (extendSelection && isAccessibilitySelectionExtendable()) { 14302 selectionStart = getAccessibilitySelectionStart(); 14303 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14304 selectionStart = forward ? segmentStart : segmentEnd; 14305 } 14306 selectionEnd = forward ? segmentEnd : segmentStart; 14307 } else { 14308 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 14309 } 14310 setAccessibilitySelection(selectionStart, selectionEnd); 14311 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 14312 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 14313 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 14314 return true; 14315 } 14316 14317 /** 14318 * Gets the text reported for accessibility purposes. 14319 * 14320 * @return The accessibility text. 14321 * 14322 * @hide 14323 */ 14324 @UnsupportedAppUsage getIterableTextForAccessibility()14325 public CharSequence getIterableTextForAccessibility() { 14326 return getContentDescription(); 14327 } 14328 14329 /** 14330 * Gets whether accessibility selection can be extended. 14331 * 14332 * @return If selection is extensible. 14333 * 14334 * @hide 14335 */ isAccessibilitySelectionExtendable()14336 public boolean isAccessibilitySelectionExtendable() { 14337 return false; 14338 } 14339 14340 /** 14341 * @hide 14342 */ getAccessibilitySelectionStart()14343 public int getAccessibilitySelectionStart() { 14344 return mAccessibilityCursorPosition; 14345 } 14346 14347 /** 14348 * @hide 14349 */ getAccessibilitySelectionEnd()14350 public int getAccessibilitySelectionEnd() { 14351 return getAccessibilitySelectionStart(); 14352 } 14353 14354 /** 14355 * @hide 14356 */ setAccessibilitySelection(int start, int end)14357 public void setAccessibilitySelection(int start, int end) { 14358 if (start == end && end == mAccessibilityCursorPosition) { 14359 return; 14360 } 14361 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 14362 mAccessibilityCursorPosition = start; 14363 } else { 14364 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 14365 } 14366 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 14367 } 14368 sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex)14369 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 14370 int fromIndex, int toIndex) { 14371 if (mParent == null) { 14372 return; 14373 } 14374 AccessibilityEvent event = AccessibilityEvent.obtain( 14375 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 14376 onInitializeAccessibilityEvent(event); 14377 onPopulateAccessibilityEvent(event); 14378 event.setFromIndex(fromIndex); 14379 event.setToIndex(toIndex); 14380 event.setAction(action); 14381 event.setMovementGranularity(granularity); 14382 mParent.requestSendAccessibilityEvent(this, event); 14383 } 14384 14385 /** 14386 * @hide 14387 */ 14388 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getIteratorForGranularity(int granularity)14389 public TextSegmentIterator getIteratorForGranularity(int granularity) { 14390 switch (granularity) { 14391 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 14392 CharSequence text = getIterableTextForAccessibility(); 14393 if (text != null && text.length() > 0) { 14394 CharacterTextSegmentIterator iterator = 14395 CharacterTextSegmentIterator.getInstance( 14396 mContext.getResources().getConfiguration().locale); 14397 iterator.initialize(text.toString()); 14398 return iterator; 14399 } 14400 } break; 14401 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 14402 CharSequence text = getIterableTextForAccessibility(); 14403 if (text != null && text.length() > 0) { 14404 WordTextSegmentIterator iterator = 14405 WordTextSegmentIterator.getInstance( 14406 mContext.getResources().getConfiguration().locale); 14407 iterator.initialize(text.toString()); 14408 return iterator; 14409 } 14410 } break; 14411 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 14412 CharSequence text = getIterableTextForAccessibility(); 14413 if (text != null && text.length() > 0) { 14414 ParagraphTextSegmentIterator iterator = 14415 ParagraphTextSegmentIterator.getInstance(); 14416 iterator.initialize(text.toString()); 14417 return iterator; 14418 } 14419 } break; 14420 } 14421 return null; 14422 } 14423 14424 /** 14425 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 14426 * and {@link #onFinishTemporaryDetach()}. 14427 * 14428 * <p>This method always returns {@code true} when called directly or indirectly from 14429 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 14430 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 14431 * <ul> 14432 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 14433 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 14434 * </ul> 14435 * </p> 14436 * 14437 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 14438 * and {@link #onFinishTemporaryDetach()}. 14439 */ isTemporarilyDetached()14440 public final boolean isTemporarilyDetached() { 14441 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 14442 } 14443 14444 /** 14445 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 14446 * a container View. 14447 */ 14448 @CallSuper dispatchStartTemporaryDetach()14449 public void dispatchStartTemporaryDetach() { 14450 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 14451 notifyEnterOrExitForAutoFillIfNeeded(false); 14452 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 14453 onStartTemporaryDetach(); 14454 } 14455 14456 /** 14457 * This is called when a container is going to temporarily detach a child, with 14458 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 14459 * It will either be followed by {@link #onFinishTemporaryDetach()} or 14460 * {@link #onDetachedFromWindow()} when the container is done. 14461 */ onStartTemporaryDetach()14462 public void onStartTemporaryDetach() { 14463 removeUnsetPressCallback(); 14464 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 14465 } 14466 14467 /** 14468 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 14469 * a container View. 14470 */ 14471 @CallSuper dispatchFinishTemporaryDetach()14472 public void dispatchFinishTemporaryDetach() { 14473 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 14474 onFinishTemporaryDetach(); 14475 if (hasWindowFocus() && hasFocus()) { 14476 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14477 } 14478 notifyEnterOrExitForAutoFillIfNeeded(true); 14479 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 14480 } 14481 14482 /** 14483 * Called after {@link #onStartTemporaryDetach} when the container is done 14484 * changing the view. 14485 */ onFinishTemporaryDetach()14486 public void onFinishTemporaryDetach() { 14487 } 14488 14489 /** 14490 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 14491 * for this view's window. Returns null if the view is not currently attached 14492 * to the window. Normally you will not need to use this directly, but 14493 * just use the standard high-level event callbacks like 14494 * {@link #onKeyDown(int, KeyEvent)}. 14495 */ getKeyDispatcherState()14496 public KeyEvent.DispatcherState getKeyDispatcherState() { 14497 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 14498 } 14499 14500 /** 14501 * Dispatch a key event before it is processed by any input method 14502 * associated with the view hierarchy. This can be used to intercept 14503 * key events in special situations before the IME consumes them; a 14504 * typical example would be handling the BACK key to update the application's 14505 * UI instead of allowing the IME to see it and close itself. 14506 * 14507 * @param event The key event to be dispatched. 14508 * @return True if the event was handled, false otherwise. 14509 */ dispatchKeyEventPreIme(KeyEvent event)14510 public boolean dispatchKeyEventPreIme(KeyEvent event) { 14511 return onKeyPreIme(event.getKeyCode(), event); 14512 } 14513 14514 /** 14515 * Dispatch a key event to the next view on the focus path. This path runs 14516 * from the top of the view tree down to the currently focused view. If this 14517 * view has focus, it will dispatch to itself. Otherwise it will dispatch 14518 * the next node down the focus path. This method also fires any key 14519 * listeners. 14520 * 14521 * @param event The key event to be dispatched. 14522 * @return True if the event was handled, false otherwise. 14523 */ dispatchKeyEvent(KeyEvent event)14524 public boolean dispatchKeyEvent(KeyEvent event) { 14525 if (mInputEventConsistencyVerifier != null) { 14526 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 14527 } 14528 14529 // Give any attached key listener a first crack at the event. 14530 //noinspection SimplifiableIfStatement 14531 ListenerInfo li = mListenerInfo; 14532 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 14533 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 14534 return true; 14535 } 14536 14537 if (event.dispatch(this, mAttachInfo != null 14538 ? mAttachInfo.mKeyDispatchState : null, this)) { 14539 return true; 14540 } 14541 14542 if (mInputEventConsistencyVerifier != null) { 14543 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14544 } 14545 return false; 14546 } 14547 14548 /** 14549 * Dispatches a key shortcut event. 14550 * 14551 * @param event The key event to be dispatched. 14552 * @return True if the event was handled by the view, false otherwise. 14553 */ dispatchKeyShortcutEvent(KeyEvent event)14554 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 14555 return onKeyShortcut(event.getKeyCode(), event); 14556 } 14557 14558 /** 14559 * Pass the touch screen motion event down to the target view, or this 14560 * view if it is the target. 14561 * 14562 * @param event The motion event to be dispatched. 14563 * @return True if the event was handled by the view, false otherwise. 14564 */ dispatchTouchEvent(MotionEvent event)14565 public boolean dispatchTouchEvent(MotionEvent event) { 14566 // If the event should be handled by accessibility focus first. 14567 if (event.isTargetAccessibilityFocus()) { 14568 // We don't have focus or no virtual descendant has it, do not handle the event. 14569 if (!isAccessibilityFocusedViewOrHost()) { 14570 return false; 14571 } 14572 // We have focus and got the event, then use normal event dispatch. 14573 event.setTargetAccessibilityFocus(false); 14574 } 14575 boolean result = false; 14576 14577 if (mInputEventConsistencyVerifier != null) { 14578 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 14579 } 14580 14581 final int actionMasked = event.getActionMasked(); 14582 if (actionMasked == MotionEvent.ACTION_DOWN) { 14583 // Defensive cleanup for new gesture 14584 stopNestedScroll(); 14585 } 14586 14587 if (onFilterTouchEventForSecurity(event)) { 14588 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 14589 result = true; 14590 } 14591 //noinspection SimplifiableIfStatement 14592 ListenerInfo li = mListenerInfo; 14593 if (li != null && li.mOnTouchListener != null 14594 && (mViewFlags & ENABLED_MASK) == ENABLED 14595 && li.mOnTouchListener.onTouch(this, event)) { 14596 result = true; 14597 } 14598 14599 if (!result && onTouchEvent(event)) { 14600 result = true; 14601 } 14602 } 14603 14604 if (!result && mInputEventConsistencyVerifier != null) { 14605 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14606 } 14607 14608 // Clean up after nested scrolls if this is the end of a gesture; 14609 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 14610 // of the gesture. 14611 if (actionMasked == MotionEvent.ACTION_UP || 14612 actionMasked == MotionEvent.ACTION_CANCEL || 14613 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 14614 stopNestedScroll(); 14615 } 14616 14617 return result; 14618 } 14619 isAccessibilityFocusedViewOrHost()14620 boolean isAccessibilityFocusedViewOrHost() { 14621 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 14622 .getAccessibilityFocusedHost() == this); 14623 } 14624 14625 /** 14626 * Returns whether this view can receive pointer events. 14627 * 14628 * @return {@code true} if this view can receive pointer events. 14629 * @hide 14630 */ canReceivePointerEvents()14631 protected boolean canReceivePointerEvents() { 14632 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 14633 } 14634 14635 /** 14636 * Filter the touch event to apply security policies. 14637 * 14638 * @param event The motion event to be filtered. 14639 * @return True if the event should be dispatched, false if the event should be dropped. 14640 * 14641 * @see #getFilterTouchesWhenObscured 14642 */ onFilterTouchEventForSecurity(MotionEvent event)14643 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 14644 //noinspection RedundantIfStatement 14645 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 14646 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 14647 // Window is obscured, drop this touch. 14648 return false; 14649 } 14650 return true; 14651 } 14652 14653 /** 14654 * Pass a trackball motion event down to the focused view. 14655 * 14656 * @param event The motion event to be dispatched. 14657 * @return True if the event was handled by the view, false otherwise. 14658 */ dispatchTrackballEvent(MotionEvent event)14659 public boolean dispatchTrackballEvent(MotionEvent event) { 14660 if (mInputEventConsistencyVerifier != null) { 14661 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 14662 } 14663 14664 return onTrackballEvent(event); 14665 } 14666 14667 /** 14668 * Pass a captured pointer event down to the focused view. 14669 * 14670 * @param event The motion event to be dispatched. 14671 * @return True if the event was handled by the view, false otherwise. 14672 */ dispatchCapturedPointerEvent(MotionEvent event)14673 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 14674 if (!hasPointerCapture()) { 14675 return false; 14676 } 14677 //noinspection SimplifiableIfStatement 14678 ListenerInfo li = mListenerInfo; 14679 if (li != null && li.mOnCapturedPointerListener != null 14680 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 14681 return true; 14682 } 14683 return onCapturedPointerEvent(event); 14684 } 14685 14686 /** 14687 * Dispatch a generic motion event. 14688 * <p> 14689 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 14690 * are delivered to the view under the pointer. All other generic motion events are 14691 * delivered to the focused view. Hover events are handled specially and are delivered 14692 * to {@link #onHoverEvent(MotionEvent)}. 14693 * </p> 14694 * 14695 * @param event The motion event to be dispatched. 14696 * @return True if the event was handled by the view, false otherwise. 14697 */ dispatchGenericMotionEvent(MotionEvent event)14698 public boolean dispatchGenericMotionEvent(MotionEvent event) { 14699 if (mInputEventConsistencyVerifier != null) { 14700 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 14701 } 14702 14703 final int source = event.getSource(); 14704 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 14705 final int action = event.getAction(); 14706 if (action == MotionEvent.ACTION_HOVER_ENTER 14707 || action == MotionEvent.ACTION_HOVER_MOVE 14708 || action == MotionEvent.ACTION_HOVER_EXIT) { 14709 if (dispatchHoverEvent(event)) { 14710 return true; 14711 } 14712 } else if (dispatchGenericPointerEvent(event)) { 14713 return true; 14714 } 14715 } else if (dispatchGenericFocusedEvent(event)) { 14716 return true; 14717 } 14718 14719 if (dispatchGenericMotionEventInternal(event)) { 14720 return true; 14721 } 14722 14723 if (mInputEventConsistencyVerifier != null) { 14724 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14725 } 14726 return false; 14727 } 14728 dispatchGenericMotionEventInternal(MotionEvent event)14729 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 14730 //noinspection SimplifiableIfStatement 14731 ListenerInfo li = mListenerInfo; 14732 if (li != null && li.mOnGenericMotionListener != null 14733 && (mViewFlags & ENABLED_MASK) == ENABLED 14734 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 14735 return true; 14736 } 14737 14738 if (onGenericMotionEvent(event)) { 14739 return true; 14740 } 14741 14742 final int actionButton = event.getActionButton(); 14743 switch (event.getActionMasked()) { 14744 case MotionEvent.ACTION_BUTTON_PRESS: 14745 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 14746 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14747 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14748 if (performContextClick(event.getX(), event.getY())) { 14749 mInContextButtonPress = true; 14750 setPressed(true, event.getX(), event.getY()); 14751 removeTapCallback(); 14752 removeLongPressCallback(); 14753 return true; 14754 } 14755 } 14756 break; 14757 14758 case MotionEvent.ACTION_BUTTON_RELEASE: 14759 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14760 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14761 mInContextButtonPress = false; 14762 mIgnoreNextUpEvent = true; 14763 } 14764 break; 14765 } 14766 14767 if (mInputEventConsistencyVerifier != null) { 14768 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14769 } 14770 return false; 14771 } 14772 14773 /** 14774 * Dispatch a hover event. 14775 * <p> 14776 * Do not call this method directly. 14777 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14778 * </p> 14779 * 14780 * @param event The motion event to be dispatched. 14781 * @return True if the event was handled by the view, false otherwise. 14782 */ dispatchHoverEvent(MotionEvent event)14783 protected boolean dispatchHoverEvent(MotionEvent event) { 14784 ListenerInfo li = mListenerInfo; 14785 //noinspection SimplifiableIfStatement 14786 if (li != null && li.mOnHoverListener != null 14787 && (mViewFlags & ENABLED_MASK) == ENABLED 14788 && li.mOnHoverListener.onHover(this, event)) { 14789 return true; 14790 } 14791 14792 return onHoverEvent(event); 14793 } 14794 14795 /** 14796 * Returns true if the view has a child to which it has recently sent 14797 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 14798 * it does not have a hovered child, then it must be the innermost hovered view. 14799 * @hide 14800 */ hasHoveredChild()14801 protected boolean hasHoveredChild() { 14802 return false; 14803 } 14804 14805 /** 14806 * Returns true if the given point, in local coordinates, is inside the hovered child. 14807 * 14808 * @hide 14809 */ pointInHoveredChild(MotionEvent event)14810 protected boolean pointInHoveredChild(MotionEvent event) { 14811 return false; 14812 } 14813 14814 /** 14815 * Dispatch a generic motion event to the view under the first pointer. 14816 * <p> 14817 * Do not call this method directly. 14818 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14819 * </p> 14820 * 14821 * @param event The motion event to be dispatched. 14822 * @return True if the event was handled by the view, false otherwise. 14823 */ dispatchGenericPointerEvent(MotionEvent event)14824 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 14825 return false; 14826 } 14827 14828 /** 14829 * Dispatch a generic motion event to the currently focused view. 14830 * <p> 14831 * Do not call this method directly. 14832 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14833 * </p> 14834 * 14835 * @param event The motion event to be dispatched. 14836 * @return True if the event was handled by the view, false otherwise. 14837 */ dispatchGenericFocusedEvent(MotionEvent event)14838 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 14839 return false; 14840 } 14841 14842 /** 14843 * Dispatch a pointer event. 14844 * <p> 14845 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 14846 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 14847 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 14848 * and should not be expected to handle other pointing device features. 14849 * </p> 14850 * 14851 * @param event The motion event to be dispatched. 14852 * @return True if the event was handled by the view, false otherwise. 14853 * @hide 14854 */ 14855 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchPointerEvent(MotionEvent event)14856 public final boolean dispatchPointerEvent(MotionEvent event) { 14857 if (event.isTouchEvent()) { 14858 return dispatchTouchEvent(event); 14859 } else { 14860 return dispatchGenericMotionEvent(event); 14861 } 14862 } 14863 14864 /** 14865 * Called when the window containing this view gains or loses window focus. 14866 * ViewGroups should override to route to their children. 14867 * 14868 * @param hasFocus True if the window containing this view now has focus, 14869 * false otherwise. 14870 */ dispatchWindowFocusChanged(boolean hasFocus)14871 public void dispatchWindowFocusChanged(boolean hasFocus) { 14872 onWindowFocusChanged(hasFocus); 14873 } 14874 14875 /** 14876 * Called when the window containing this view gains or loses focus. Note 14877 * that this is separate from view focus: to receive key events, both 14878 * your view and its window must have focus. If a window is displayed 14879 * on top of yours that takes input focus, then your own window will lose 14880 * focus but the view focus will remain unchanged. 14881 * 14882 * @param hasWindowFocus True if the window containing this view now has 14883 * focus, false otherwise. 14884 */ onWindowFocusChanged(boolean hasWindowFocus)14885 public void onWindowFocusChanged(boolean hasWindowFocus) { 14886 if (!hasWindowFocus) { 14887 if (isPressed()) { 14888 setPressed(false); 14889 } 14890 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14891 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14892 notifyFocusChangeToImeFocusController(false /* hasFocus */); 14893 } 14894 removeLongPressCallback(); 14895 removeTapCallback(); 14896 onFocusLost(); 14897 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14898 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14899 } 14900 14901 refreshDrawableState(); 14902 } 14903 14904 /** 14905 * Returns true if this view is in a window that currently has window focus. 14906 * Note that this is not the same as the view itself having focus. 14907 * 14908 * @return True if this view is in a window that currently has window focus. 14909 */ hasWindowFocus()14910 public boolean hasWindowFocus() { 14911 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 14912 } 14913 14914 /** 14915 * @return {@code true} if this view is in a window that currently has IME focusable state. 14916 * @hide 14917 */ hasImeFocus()14918 public boolean hasImeFocus() { 14919 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 14920 } 14921 14922 /** 14923 * Dispatch a view visibility change down the view hierarchy. 14924 * ViewGroups should override to route to their children. 14925 * @param changedView The view whose visibility changed. Could be 'this' or 14926 * an ancestor view. 14927 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 14928 * {@link #INVISIBLE} or {@link #GONE}. 14929 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)14930 protected void dispatchVisibilityChanged(@NonNull View changedView, 14931 @Visibility int visibility) { 14932 onVisibilityChanged(changedView, visibility); 14933 } 14934 14935 /** 14936 * Called when the visibility of the view or an ancestor of the view has 14937 * changed. 14938 * 14939 * @param changedView The view whose visibility changed. May be 14940 * {@code this} or an ancestor view. 14941 * @param visibility The new visibility, one of {@link #VISIBLE}, 14942 * {@link #INVISIBLE} or {@link #GONE}. 14943 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)14944 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 14945 } 14946 14947 /** 14948 * Dispatch a hint about whether this view is displayed. For instance, when 14949 * a View moves out of the screen, it might receives a display hint indicating 14950 * the view is not displayed. Applications should not <em>rely</em> on this hint 14951 * as there is no guarantee that they will receive one. 14952 * 14953 * @param hint A hint about whether or not this view is displayed: 14954 * {@link #VISIBLE} or {@link #INVISIBLE}. 14955 */ dispatchDisplayHint(@isibility int hint)14956 public void dispatchDisplayHint(@Visibility int hint) { 14957 onDisplayHint(hint); 14958 } 14959 14960 /** 14961 * Gives this view a hint about whether is displayed or not. For instance, when 14962 * a View moves out of the screen, it might receives a display hint indicating 14963 * the view is not displayed. Applications should not <em>rely</em> on this hint 14964 * as there is no guarantee that they will receive one. 14965 * 14966 * @param hint A hint about whether or not this view is displayed: 14967 * {@link #VISIBLE} or {@link #INVISIBLE}. 14968 */ onDisplayHint(@isibility int hint)14969 protected void onDisplayHint(@Visibility int hint) { 14970 } 14971 14972 /** 14973 * Dispatch a window visibility change down the view hierarchy. 14974 * ViewGroups should override to route to their children. 14975 * 14976 * @param visibility The new visibility of the window. 14977 * 14978 * @see #onWindowVisibilityChanged(int) 14979 */ dispatchWindowVisibilityChanged(@isibility int visibility)14980 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 14981 onWindowVisibilityChanged(visibility); 14982 } 14983 14984 /** 14985 * Called when the window containing has change its visibility 14986 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 14987 * that this tells you whether or not your window is being made visible 14988 * to the window manager; this does <em>not</em> tell you whether or not 14989 * your window is obscured by other windows on the screen, even if it 14990 * is itself visible. 14991 * 14992 * @param visibility The new visibility of the window. 14993 */ onWindowVisibilityChanged(@isibility int visibility)14994 protected void onWindowVisibilityChanged(@Visibility int visibility) { 14995 if (visibility == VISIBLE) { 14996 initialAwakenScrollBars(); 14997 } 14998 } 14999 15000 /** 15001 * @return true if this view and all ancestors are visible as of the last 15002 * {@link #onVisibilityAggregated(boolean)} call. 15003 */ isAggregatedVisible()15004 boolean isAggregatedVisible() { 15005 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 15006 } 15007 15008 /** 15009 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 15010 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 15011 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 15012 * 15013 * @param isVisible true if this view's visibility to the user is uninterrupted by its 15014 * ancestors or by window visibility 15015 * @return true if this view is visible to the user, not counting clipping or overlapping 15016 */ dispatchVisibilityAggregated(boolean isVisible)15017 boolean dispatchVisibilityAggregated(boolean isVisible) { 15018 final boolean thisVisible = getVisibility() == VISIBLE; 15019 // If we're not visible but something is telling us we are, ignore it. 15020 if (thisVisible || !isVisible) { 15021 onVisibilityAggregated(isVisible); 15022 } 15023 return thisVisible && isVisible; 15024 } 15025 15026 /** 15027 * Called when the user-visibility of this View is potentially affected by a change 15028 * to this view itself, an ancestor view or the window this view is attached to. 15029 * 15030 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 15031 * and this view's window is also visible 15032 */ 15033 @CallSuper onVisibilityAggregated(boolean isVisible)15034 public void onVisibilityAggregated(boolean isVisible) { 15035 // Update our internal visibility tracking so we can detect changes 15036 boolean oldVisible = isAggregatedVisible(); 15037 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 15038 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 15039 if (isVisible && mAttachInfo != null) { 15040 initialAwakenScrollBars(); 15041 } 15042 15043 final Drawable dr = mBackground; 15044 if (dr != null && isVisible != dr.isVisible()) { 15045 dr.setVisible(isVisible, false); 15046 } 15047 final Drawable hl = mDefaultFocusHighlight; 15048 if (hl != null && isVisible != hl.isVisible()) { 15049 hl.setVisible(isVisible, false); 15050 } 15051 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 15052 if (fg != null && isVisible != fg.isVisible()) { 15053 fg.setVisible(isVisible, false); 15054 } 15055 15056 if (isAutofillable()) { 15057 AutofillManager afm = getAutofillManager(); 15058 15059 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 15060 if (mVisibilityChangeForAutofillHandler != null) { 15061 mVisibilityChangeForAutofillHandler.removeMessages(0); 15062 } 15063 15064 // If the view is in the background but still part of the hierarchy this is called 15065 // with isVisible=false. Hence visibility==false requires further checks 15066 if (isVisible) { 15067 afm.notifyViewVisibilityChanged(this, true); 15068 } else { 15069 if (mVisibilityChangeForAutofillHandler == null) { 15070 mVisibilityChangeForAutofillHandler = 15071 new VisibilityChangeForAutofillHandler(afm, this); 15072 } 15073 // Let current operation (e.g. removal of the view from the hierarchy) 15074 // finish before checking state 15075 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 15076 } 15077 } 15078 } 15079 15080 if (isVisible != oldVisible) { 15081 if (isAccessibilityPane()) { 15082 notifyViewAccessibilityStateChangedIfNeeded(isVisible 15083 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 15084 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 15085 } 15086 15087 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 15088 15089 if (!getSystemGestureExclusionRects().isEmpty()) { 15090 postUpdateSystemGestureExclusionRects(); 15091 } 15092 } 15093 } 15094 15095 /** 15096 * Returns the current visibility of the window this view is attached to 15097 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 15098 * 15099 * @return Returns the current visibility of the view's window. 15100 */ 15101 @Visibility getWindowVisibility()15102 public int getWindowVisibility() { 15103 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 15104 } 15105 15106 /** 15107 * Retrieve the overall visible display size in which the window this view is 15108 * attached to has been positioned in. This takes into account screen 15109 * decorations above the window, for both cases where the window itself 15110 * is being position inside of them or the window is being placed under 15111 * then and covered insets are used for the window to position its content 15112 * inside. In effect, this tells you the available area where content can 15113 * be placed and remain visible to users. 15114 * 15115 * @param outRect Filled in with the visible display frame. If the view 15116 * is not attached to a window, this is simply the raw display size. 15117 */ getWindowVisibleDisplayFrame(Rect outRect)15118 public void getWindowVisibleDisplayFrame(Rect outRect) { 15119 if (mAttachInfo != null) { 15120 mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); 15121 return; 15122 } 15123 // The view is not attached to a display so we don't have a context. 15124 // Make a best guess about the display size. 15125 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 15126 d.getRectSize(outRect); 15127 } 15128 15129 /** 15130 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 15131 * is currently in without any insets. 15132 * 15133 * @hide 15134 */ 15135 @UnsupportedAppUsage getWindowDisplayFrame(Rect outRect)15136 public void getWindowDisplayFrame(Rect outRect) { 15137 if (mAttachInfo != null) { 15138 mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); 15139 return; 15140 } 15141 // The view is not attached to a display so we don't have a context. 15142 // Make a best guess about the display size. 15143 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 15144 d.getRectSize(outRect); 15145 } 15146 15147 /** 15148 * Dispatch a notification about a resource configuration change down 15149 * the view hierarchy. 15150 * ViewGroups should override to route to their children. 15151 * 15152 * @param newConfig The new resource configuration. 15153 * 15154 * @see #onConfigurationChanged(android.content.res.Configuration) 15155 */ dispatchConfigurationChanged(Configuration newConfig)15156 public void dispatchConfigurationChanged(Configuration newConfig) { 15157 onConfigurationChanged(newConfig); 15158 } 15159 15160 /** 15161 * Called when the current configuration of the resources being used 15162 * by the application have changed. You can use this to decide when 15163 * to reload resources that can changed based on orientation and other 15164 * configuration characteristics. You only need to use this if you are 15165 * not relying on the normal {@link android.app.Activity} mechanism of 15166 * recreating the activity instance upon a configuration change. 15167 * 15168 * @param newConfig The new resource configuration. 15169 */ onConfigurationChanged(Configuration newConfig)15170 protected void onConfigurationChanged(Configuration newConfig) { 15171 } 15172 15173 /** 15174 * Private function to aggregate all per-view attributes in to the view 15175 * root. 15176 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)15177 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 15178 performCollectViewAttributes(attachInfo, visibility); 15179 } 15180 performCollectViewAttributes(AttachInfo attachInfo, int visibility)15181 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 15182 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 15183 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 15184 attachInfo.mKeepScreenOn = true; 15185 } 15186 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 15187 ListenerInfo li = mListenerInfo; 15188 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 15189 attachInfo.mHasSystemUiListeners = true; 15190 } 15191 } 15192 } 15193 needGlobalAttributesUpdate(boolean force)15194 void needGlobalAttributesUpdate(boolean force) { 15195 final AttachInfo ai = mAttachInfo; 15196 if (ai != null && !ai.mRecomputeGlobalAttributes) { 15197 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 15198 || ai.mHasSystemUiListeners) { 15199 ai.mRecomputeGlobalAttributes = true; 15200 } 15201 } 15202 } 15203 15204 /** 15205 * Returns whether the device is currently in touch mode. Touch mode is entered 15206 * once the user begins interacting with the device by touch, and affects various 15207 * things like whether focus is always visible to the user. 15208 * 15209 * @return Whether the device is in touch mode. 15210 */ 15211 @ViewDebug.ExportedProperty isInTouchMode()15212 public boolean isInTouchMode() { 15213 if (mAttachInfo != null) { 15214 return mAttachInfo.mInTouchMode; 15215 } else { 15216 return ViewRootImpl.isInTouchMode(); 15217 } 15218 } 15219 15220 /** 15221 * Returns the context the view is running in, through which it can 15222 * access the current theme, resources, etc. 15223 * 15224 * @return The view's Context. 15225 */ 15226 @ViewDebug.CapturedViewProperty 15227 @UiContext getContext()15228 public final Context getContext() { 15229 return mContext; 15230 } 15231 15232 /** 15233 * Handle a key event before it is processed by any input method 15234 * associated with the view hierarchy. This can be used to intercept 15235 * key events in special situations before the IME consumes them; a 15236 * typical example would be handling the BACK key to update the application's 15237 * UI instead of allowing the IME to see it and close itself. 15238 * 15239 * @param keyCode The value in event.getKeyCode(). 15240 * @param event Description of the key event. 15241 * @return If you handled the event, return true. If you want to allow the 15242 * event to be handled by the next receiver, return false. 15243 */ onKeyPreIme(int keyCode, KeyEvent event)15244 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 15245 return false; 15246 } 15247 15248 /** 15249 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 15250 * KeyEvent.Callback.onKeyDown()}: perform press of the view 15251 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 15252 * is released, if the view is enabled and clickable. 15253 * <p> 15254 * Key presses in software keyboards will generally NOT trigger this 15255 * listener, although some may elect to do so in some situations. Do not 15256 * rely on this to catch software key presses. 15257 * 15258 * @param keyCode a key code that represents the button pressed, from 15259 * {@link android.view.KeyEvent} 15260 * @param event the KeyEvent object that defines the button action 15261 */ onKeyDown(int keyCode, KeyEvent event)15262 public boolean onKeyDown(int keyCode, KeyEvent event) { 15263 if (KeyEvent.isConfirmKey(keyCode)) { 15264 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15265 return true; 15266 } 15267 15268 if (event.getRepeatCount() == 0) { 15269 // Long clickable items don't necessarily have to be clickable. 15270 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 15271 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 15272 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 15273 // For the purposes of menu anchoring and drawable hotspots, 15274 // key events are considered to be at the center of the view. 15275 final float x = getWidth() / 2f; 15276 final float y = getHeight() / 2f; 15277 if (clickable) { 15278 setPressed(true, x, y); 15279 } 15280 checkForLongClick( 15281 ViewConfiguration.getLongPressTimeout(), 15282 x, 15283 y, 15284 // This is not a touch gesture -- do not classify it as one. 15285 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 15286 return true; 15287 } 15288 } 15289 } 15290 15291 return false; 15292 } 15293 15294 /** 15295 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 15296 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 15297 * the event). 15298 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15299 * although some may elect to do so in some situations. Do not rely on this to 15300 * catch software key presses. 15301 */ onKeyLongPress(int keyCode, KeyEvent event)15302 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 15303 return false; 15304 } 15305 15306 /** 15307 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 15308 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 15309 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 15310 * or {@link KeyEvent#KEYCODE_SPACE} is released. 15311 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15312 * although some may elect to do so in some situations. Do not rely on this to 15313 * catch software key presses. 15314 * 15315 * @param keyCode A key code that represents the button pressed, from 15316 * {@link android.view.KeyEvent}. 15317 * @param event The KeyEvent object that defines the button action. 15318 */ onKeyUp(int keyCode, KeyEvent event)15319 public boolean onKeyUp(int keyCode, KeyEvent event) { 15320 if (KeyEvent.isConfirmKey(keyCode)) { 15321 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15322 return true; 15323 } 15324 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 15325 setPressed(false); 15326 15327 if (!mHasPerformedLongPress) { 15328 // This is a tap, so remove the longpress check 15329 removeLongPressCallback(); 15330 if (!event.isCanceled()) { 15331 return performClickInternal(); 15332 } 15333 } 15334 } 15335 } 15336 return false; 15337 } 15338 15339 /** 15340 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 15341 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 15342 * the event). 15343 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15344 * although some may elect to do so in some situations. Do not rely on this to 15345 * catch software key presses. 15346 * 15347 * @param keyCode A key code that represents the button pressed, from 15348 * {@link android.view.KeyEvent}. 15349 * @param repeatCount The number of times the action was made. 15350 * @param event The KeyEvent object that defines the button action. 15351 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)15352 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 15353 return false; 15354 } 15355 15356 /** 15357 * Called on the focused view when a key shortcut event is not handled. 15358 * Override this method to implement local key shortcuts for the View. 15359 * Key shortcuts can also be implemented by setting the 15360 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 15361 * 15362 * @param keyCode The value in event.getKeyCode(). 15363 * @param event Description of the key event. 15364 * @return If you handled the event, return true. If you want to allow the 15365 * event to be handled by the next receiver, return false. 15366 */ onKeyShortcut(int keyCode, KeyEvent event)15367 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 15368 return false; 15369 } 15370 15371 /** 15372 * Check whether the called view is a text editor, in which case it 15373 * would make sense to automatically display a soft input window for 15374 * it. Subclasses should override this if they implement 15375 * {@link #onCreateInputConnection(EditorInfo)} to return true if 15376 * a call on that method would return a non-null InputConnection, and 15377 * they are really a first-class editor that the user would normally 15378 * start typing on when the go into a window containing your view. 15379 * 15380 * <p>The default implementation always returns false. This does 15381 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 15382 * will not be called or the user can not otherwise perform edits on your 15383 * view; it is just a hint to the system that this is not the primary 15384 * purpose of this view. 15385 * 15386 * @return Returns true if this view is a text editor, else false. 15387 */ onCheckIsTextEditor()15388 public boolean onCheckIsTextEditor() { 15389 return false; 15390 } 15391 15392 /** 15393 * Create a new InputConnection for an InputMethod to interact 15394 * with the view. The default implementation returns null, since it doesn't 15395 * support input methods. You can override this to implement such support. 15396 * This is only needed for views that take focus and text input. 15397 * 15398 * <p>When implementing this, you probably also want to implement 15399 * {@link #onCheckIsTextEditor()} to indicate you will return a 15400 * non-null InputConnection.</p> 15401 * 15402 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 15403 * object correctly and in its entirety, so that the connected IME can rely 15404 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 15405 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 15406 * must be filled in with the correct cursor position for IMEs to work correctly 15407 * with your application.</p> 15408 * 15409 * @param outAttrs Fill in with attribute information about the connection. 15410 */ onCreateInputConnection(EditorInfo outAttrs)15411 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 15412 return null; 15413 } 15414 15415 /** 15416 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 15417 * that the system has successfully initialized an {@link InputConnection} and it is ready for 15418 * use. 15419 * 15420 * <p>The default implementation does nothing, since a view doesn't support input methods by 15421 * default (see {@link #onCreateInputConnection}). 15422 * 15423 * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, 15424 * after it's been fully initialized by the system. 15425 * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. 15426 * @param handler The dedicated {@link Handler} on which IPC method calls from input methods 15427 * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If 15428 * that method returns null, this parameter will be null also. 15429 * 15430 * @hide 15431 */ onInputConnectionOpenedInternal(@onNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler)15432 public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, 15433 @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} 15434 15435 /** 15436 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 15437 * that the {@link InputConnection} has been closed. 15438 * 15439 * <p>The default implementation does nothing, since a view doesn't support input methods by 15440 * default (see {@link #onCreateInputConnection}). 15441 * 15442 * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when 15443 * the {@link InputConnection} is closed or the connection is not valid and managed by 15444 * {@link com.android.server.inputmethod.InputMethodManagerService}. 15445 * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. 15446 * 15447 * @hide 15448 */ onInputConnectionClosedInternal()15449 public void onInputConnectionClosedInternal() {} 15450 15451 /** 15452 * Called by the {@link android.view.inputmethod.InputMethodManager} 15453 * when a view who is not the current 15454 * input connection target is trying to make a call on the manager. The 15455 * default implementation returns false; you can override this to return 15456 * true for certain views if you are performing InputConnection proxying 15457 * to them. 15458 * @param view The View that is making the InputMethodManager call. 15459 * @return Return true to allow the call, false to reject. 15460 */ checkInputConnectionProxy(View view)15461 public boolean checkInputConnectionProxy(View view) { 15462 return false; 15463 } 15464 15465 /** 15466 * Show the context menu for this view. It is not safe to hold on to the 15467 * menu after returning from this method. 15468 * 15469 * You should normally not overload this method. Overload 15470 * {@link #onCreateContextMenu(ContextMenu)} or define an 15471 * {@link OnCreateContextMenuListener} to add items to the context menu. 15472 * 15473 * @param menu The context menu to populate 15474 */ createContextMenu(ContextMenu menu)15475 public void createContextMenu(ContextMenu menu) { 15476 ContextMenuInfo menuInfo = getContextMenuInfo(); 15477 15478 // Sets the current menu info so all items added to menu will have 15479 // my extra info set. 15480 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 15481 15482 onCreateContextMenu(menu); 15483 ListenerInfo li = mListenerInfo; 15484 if (li != null && li.mOnCreateContextMenuListener != null) { 15485 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 15486 } 15487 15488 // Clear the extra information so subsequent items that aren't mine don't 15489 // have my extra info. 15490 ((MenuBuilder)menu).setCurrentMenuInfo(null); 15491 15492 if (mParent != null) { 15493 mParent.createContextMenu(menu); 15494 } 15495 } 15496 15497 /** 15498 * Views should implement this if they have extra information to associate 15499 * with the context menu. The return result is supplied as a parameter to 15500 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 15501 * callback. 15502 * 15503 * @return Extra information about the item for which the context menu 15504 * should be shown. This information will vary across different 15505 * subclasses of View. 15506 */ getContextMenuInfo()15507 protected ContextMenuInfo getContextMenuInfo() { 15508 return null; 15509 } 15510 15511 /** 15512 * Views should implement this if the view itself is going to add items to 15513 * the context menu. 15514 * 15515 * @param menu the context menu to populate 15516 */ onCreateContextMenu(ContextMenu menu)15517 protected void onCreateContextMenu(ContextMenu menu) { 15518 } 15519 15520 /** 15521 * Implement this method to handle trackball motion events. The 15522 * <em>relative</em> movement of the trackball since the last event 15523 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 15524 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 15525 * that a movement of 1 corresponds to the user pressing one DPAD key (so 15526 * they will often be fractional values, representing the more fine-grained 15527 * movement information available from a trackball). 15528 * 15529 * @param event The motion event. 15530 * @return True if the event was handled, false otherwise. 15531 */ onTrackballEvent(MotionEvent event)15532 public boolean onTrackballEvent(MotionEvent event) { 15533 return false; 15534 } 15535 15536 /** 15537 * Implement this method to handle generic motion events. 15538 * <p> 15539 * Generic motion events describe joystick movements, mouse hovers, track pad 15540 * touches, scroll wheel movements and other input events. The 15541 * {@link MotionEvent#getSource() source} of the motion event specifies 15542 * the class of input that was received. Implementations of this method 15543 * must examine the bits in the source before processing the event. 15544 * The following code example shows how this is done. 15545 * </p><p> 15546 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 15547 * are delivered to the view under the pointer. All other generic motion events are 15548 * delivered to the focused view. 15549 * </p> 15550 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 15551 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 15552 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 15553 * // process the joystick movement... 15554 * return true; 15555 * } 15556 * } 15557 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 15558 * switch (event.getAction()) { 15559 * case MotionEvent.ACTION_HOVER_MOVE: 15560 * // process the mouse hover movement... 15561 * return true; 15562 * case MotionEvent.ACTION_SCROLL: 15563 * // process the scroll wheel movement... 15564 * return true; 15565 * } 15566 * } 15567 * return super.onGenericMotionEvent(event); 15568 * }</pre> 15569 * 15570 * @param event The generic motion event being processed. 15571 * @return True if the event was handled, false otherwise. 15572 */ onGenericMotionEvent(MotionEvent event)15573 public boolean onGenericMotionEvent(MotionEvent event) { 15574 return false; 15575 } 15576 15577 /** 15578 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 15579 * <p> 15580 * This method is dispatching hover events to the delegate target to support explore by touch. 15581 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 15582 * the delegate target according to the pointer and the touch area of the delegate while touch 15583 * exploration enabled. 15584 * </p> 15585 * 15586 * @param event The motion event dispatch to the delegate target. 15587 * @return True if the event was handled, false otherwise. 15588 * 15589 * @see #onHoverEvent 15590 */ dispatchTouchExplorationHoverEvent(MotionEvent event)15591 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 15592 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 15593 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 15594 return false; 15595 } 15596 15597 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 15598 final int action = event.getActionMasked(); 15599 boolean pointInDelegateRegion = false; 15600 boolean handled = false; 15601 15602 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 15603 for (int i = 0; i < info.getRegionCount(); i++) { 15604 Region r = info.getRegionAt(i); 15605 if (r.contains((int) event.getX(), (int) event.getY())) { 15606 pointInDelegateRegion = true; 15607 } 15608 } 15609 15610 // Explore by touch should dispatch events to children under the pointer first if any 15611 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 15612 // hover events but receive accessibility focus, it should also not delegate to these 15613 // views when hovered. 15614 if (!oldHoveringTouchDelegate) { 15615 if ((action == MotionEvent.ACTION_HOVER_ENTER 15616 || action == MotionEvent.ACTION_HOVER_MOVE) 15617 && !pointInHoveredChild(event) 15618 && pointInDelegateRegion) { 15619 mHoveringTouchDelegate = true; 15620 } 15621 } else { 15622 if (action == MotionEvent.ACTION_HOVER_EXIT 15623 || (action == MotionEvent.ACTION_HOVER_MOVE 15624 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 15625 mHoveringTouchDelegate = false; 15626 } 15627 } 15628 switch (action) { 15629 case MotionEvent.ACTION_HOVER_MOVE: 15630 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15631 // Inside bounds, dispatch as is. 15632 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 15633 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15634 // Moving inbound, synthesize hover enter. 15635 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 15636 ? event : MotionEvent.obtainNoHistory(event); 15637 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 15638 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15639 eventNoHistory.setAction(action); 15640 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15641 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 15642 // Moving outbound, synthesize hover exit. 15643 final boolean hoverExitPending = event.isHoverExitPending(); 15644 event.setHoverExitPending(true); 15645 mTouchDelegate.onTouchExplorationHoverEvent(event); 15646 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 15647 ? event : MotionEvent.obtainNoHistory(event); 15648 eventNoHistory.setHoverExitPending(hoverExitPending); 15649 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 15650 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15651 } // else: outside bounds, do nothing. 15652 break; 15653 case MotionEvent.ACTION_HOVER_ENTER: 15654 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15655 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 15656 } 15657 break; 15658 case MotionEvent.ACTION_HOVER_EXIT: 15659 if (oldHoveringTouchDelegate) { 15660 mTouchDelegate.onTouchExplorationHoverEvent(event); 15661 } 15662 break; 15663 } 15664 return handled; 15665 } 15666 15667 /** 15668 * Implement this method to handle hover events. 15669 * <p> 15670 * This method is called whenever a pointer is hovering into, over, or out of the 15671 * bounds of a view and the view is not currently being touched. 15672 * Hover events are represented as pointer events with action 15673 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 15674 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 15675 * </p> 15676 * <ul> 15677 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 15678 * when the pointer enters the bounds of the view.</li> 15679 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 15680 * when the pointer has already entered the bounds of the view and has moved.</li> 15681 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 15682 * when the pointer has exited the bounds of the view or when the pointer is 15683 * about to go down due to a button click, tap, or similar user action that 15684 * causes the view to be touched.</li> 15685 * </ul> 15686 * <p> 15687 * The view should implement this method to return true to indicate that it is 15688 * handling the hover event, such as by changing its drawable state. 15689 * </p><p> 15690 * The default implementation calls {@link #setHovered} to update the hovered state 15691 * of the view when a hover enter or hover exit event is received, if the view 15692 * is enabled and is clickable. The default implementation also sends hover 15693 * accessibility events. 15694 * </p> 15695 * 15696 * @param event The motion event that describes the hover. 15697 * @return True if the view handled the hover event. 15698 * 15699 * @see #isHovered 15700 * @see #setHovered 15701 * @see #onHoverChanged 15702 */ onHoverEvent(MotionEvent event)15703 public boolean onHoverEvent(MotionEvent event) { 15704 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 15705 return true; 15706 } 15707 15708 // The root view may receive hover (or touch) events that are outside the bounds of 15709 // the window. This code ensures that we only send accessibility events for 15710 // hovers that are actually within the bounds of the root view. 15711 final int action = event.getActionMasked(); 15712 if (!mSendingHoverAccessibilityEvents) { 15713 if ((action == MotionEvent.ACTION_HOVER_ENTER 15714 || action == MotionEvent.ACTION_HOVER_MOVE) 15715 && !hasHoveredChild() 15716 && pointInView(event.getX(), event.getY())) { 15717 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 15718 mSendingHoverAccessibilityEvents = true; 15719 } 15720 } else { 15721 if (action == MotionEvent.ACTION_HOVER_EXIT 15722 || (action == MotionEvent.ACTION_HOVER_MOVE 15723 && !pointInView(event.getX(), event.getY()))) { 15724 mSendingHoverAccessibilityEvents = false; 15725 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 15726 } 15727 } 15728 15729 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 15730 && event.isFromSource(InputDevice.SOURCE_MOUSE) 15731 && isOnScrollbar(event.getX(), event.getY())) { 15732 awakenScrollBars(); 15733 } 15734 15735 // If we consider ourself hoverable, or if we we're already hovered, 15736 // handle changing state in response to ENTER and EXIT events. 15737 if (isHoverable() || isHovered()) { 15738 switch (action) { 15739 case MotionEvent.ACTION_HOVER_ENTER: 15740 setHovered(true); 15741 break; 15742 case MotionEvent.ACTION_HOVER_EXIT: 15743 setHovered(false); 15744 break; 15745 } 15746 15747 // Dispatch the event to onGenericMotionEvent before returning true. 15748 // This is to provide compatibility with existing applications that 15749 // handled HOVER_MOVE events in onGenericMotionEvent and that would 15750 // break because of the new default handling for hoverable views 15751 // in onHoverEvent. 15752 // Note that onGenericMotionEvent will be called by default when 15753 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 15754 dispatchGenericMotionEventInternal(event); 15755 // The event was already handled by calling setHovered(), so always 15756 // return true. 15757 return true; 15758 } 15759 15760 return false; 15761 } 15762 15763 /** 15764 * Returns true if the view should handle {@link #onHoverEvent} 15765 * by calling {@link #setHovered} to change its hovered state. 15766 * 15767 * @return True if the view is hoverable. 15768 */ isHoverable()15769 private boolean isHoverable() { 15770 final int viewFlags = mViewFlags; 15771 if ((viewFlags & ENABLED_MASK) == DISABLED) { 15772 return false; 15773 } 15774 15775 return (viewFlags & CLICKABLE) == CLICKABLE 15776 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 15777 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15778 } 15779 15780 /** 15781 * Returns true if the view is currently hovered. 15782 * 15783 * @return True if the view is currently hovered. 15784 * 15785 * @see #setHovered 15786 * @see #onHoverChanged 15787 */ 15788 @ViewDebug.ExportedProperty isHovered()15789 public boolean isHovered() { 15790 return (mPrivateFlags & PFLAG_HOVERED) != 0; 15791 } 15792 15793 /** 15794 * Sets whether the view is currently hovered. 15795 * <p> 15796 * Calling this method also changes the drawable state of the view. This 15797 * enables the view to react to hover by using different drawable resources 15798 * to change its appearance. 15799 * </p><p> 15800 * The {@link #onHoverChanged} method is called when the hovered state changes. 15801 * </p> 15802 * 15803 * @param hovered True if the view is hovered. 15804 * 15805 * @see #isHovered 15806 * @see #onHoverChanged 15807 */ setHovered(boolean hovered)15808 public void setHovered(boolean hovered) { 15809 if (hovered) { 15810 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 15811 mPrivateFlags |= PFLAG_HOVERED; 15812 refreshDrawableState(); 15813 onHoverChanged(true); 15814 } 15815 } else { 15816 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 15817 mPrivateFlags &= ~PFLAG_HOVERED; 15818 refreshDrawableState(); 15819 onHoverChanged(false); 15820 } 15821 } 15822 } 15823 15824 /** 15825 * Implement this method to handle hover state changes. 15826 * <p> 15827 * This method is called whenever the hover state changes as a result of a 15828 * call to {@link #setHovered}. 15829 * </p> 15830 * 15831 * @param hovered The current hover state, as returned by {@link #isHovered}. 15832 * 15833 * @see #isHovered 15834 * @see #setHovered 15835 */ onHoverChanged(boolean hovered)15836 public void onHoverChanged(boolean hovered) { 15837 } 15838 15839 /** 15840 * Handles scroll bar dragging by mouse input. 15841 * 15842 * @hide 15843 * @param event The motion event. 15844 * 15845 * @return true if the event was handled as a scroll bar dragging, false otherwise. 15846 */ handleScrollBarDragging(MotionEvent event)15847 protected boolean handleScrollBarDragging(MotionEvent event) { 15848 if (mScrollCache == null) { 15849 return false; 15850 } 15851 final float x = event.getX(); 15852 final float y = event.getY(); 15853 final int action = event.getAction(); 15854 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 15855 && action != MotionEvent.ACTION_DOWN) 15856 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 15857 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 15858 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15859 return false; 15860 } 15861 15862 switch (action) { 15863 case MotionEvent.ACTION_MOVE: 15864 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 15865 return false; 15866 } 15867 if (mScrollCache.mScrollBarDraggingState 15868 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 15869 final Rect bounds = mScrollCache.mScrollBarBounds; 15870 getVerticalScrollBarBounds(bounds, null); 15871 final int range = computeVerticalScrollRange(); 15872 final int offset = computeVerticalScrollOffset(); 15873 final int extent = computeVerticalScrollExtent(); 15874 15875 final int thumbLength = ScrollBarUtils.getThumbLength( 15876 bounds.height(), bounds.width(), extent, range); 15877 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15878 bounds.height(), thumbLength, extent, range, offset); 15879 15880 final float diff = y - mScrollCache.mScrollBarDraggingPos; 15881 final float maxThumbOffset = bounds.height() - thumbLength; 15882 final float newThumbOffset = 15883 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15884 final int height = getHeight(); 15885 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15886 && height > 0 && extent > 0) { 15887 final int newY = Math.round((range - extent) 15888 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 15889 if (newY != getScrollY()) { 15890 mScrollCache.mScrollBarDraggingPos = y; 15891 setScrollY(newY); 15892 } 15893 } 15894 return true; 15895 } 15896 if (mScrollCache.mScrollBarDraggingState 15897 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 15898 final Rect bounds = mScrollCache.mScrollBarBounds; 15899 getHorizontalScrollBarBounds(bounds, null); 15900 final int range = computeHorizontalScrollRange(); 15901 final int offset = computeHorizontalScrollOffset(); 15902 final int extent = computeHorizontalScrollExtent(); 15903 15904 final int thumbLength = ScrollBarUtils.getThumbLength( 15905 bounds.width(), bounds.height(), extent, range); 15906 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15907 bounds.width(), thumbLength, extent, range, offset); 15908 15909 final float diff = x - mScrollCache.mScrollBarDraggingPos; 15910 final float maxThumbOffset = bounds.width() - thumbLength; 15911 final float newThumbOffset = 15912 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15913 final int width = getWidth(); 15914 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15915 && width > 0 && extent > 0) { 15916 final int newX = Math.round((range - extent) 15917 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 15918 if (newX != getScrollX()) { 15919 mScrollCache.mScrollBarDraggingPos = x; 15920 setScrollX(newX); 15921 } 15922 } 15923 return true; 15924 } 15925 case MotionEvent.ACTION_DOWN: 15926 if (mScrollCache.state == ScrollabilityCache.OFF) { 15927 return false; 15928 } 15929 if (isOnVerticalScrollbarThumb(x, y)) { 15930 mScrollCache.mScrollBarDraggingState = 15931 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 15932 mScrollCache.mScrollBarDraggingPos = y; 15933 return true; 15934 } 15935 if (isOnHorizontalScrollbarThumb(x, y)) { 15936 mScrollCache.mScrollBarDraggingState = 15937 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 15938 mScrollCache.mScrollBarDraggingPos = x; 15939 return true; 15940 } 15941 } 15942 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15943 return false; 15944 } 15945 15946 /** 15947 * Implement this method to handle touch screen motion events. 15948 * <p> 15949 * If this method is used to detect click actions, it is recommended that 15950 * the actions be performed by implementing and calling 15951 * {@link #performClick()}. This will ensure consistent system behavior, 15952 * including: 15953 * <ul> 15954 * <li>obeying click sound preferences 15955 * <li>dispatching OnClickListener calls 15956 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 15957 * accessibility features are enabled 15958 * </ul> 15959 * 15960 * @param event The motion event. 15961 * @return True if the event was handled, false otherwise. 15962 */ onTouchEvent(MotionEvent event)15963 public boolean onTouchEvent(MotionEvent event) { 15964 final float x = event.getX(); 15965 final float y = event.getY(); 15966 final int viewFlags = mViewFlags; 15967 final int action = event.getAction(); 15968 15969 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 15970 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 15971 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15972 15973 if ((viewFlags & ENABLED_MASK) == DISABLED 15974 && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { 15975 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 15976 setPressed(false); 15977 } 15978 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15979 // A disabled view that is clickable still consumes the touch 15980 // events, it just doesn't respond to them. 15981 return clickable; 15982 } 15983 if (mTouchDelegate != null) { 15984 if (mTouchDelegate.onTouchEvent(event)) { 15985 return true; 15986 } 15987 } 15988 15989 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 15990 switch (action) { 15991 case MotionEvent.ACTION_UP: 15992 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15993 if ((viewFlags & TOOLTIP) == TOOLTIP) { 15994 handleTooltipUp(); 15995 } 15996 if (!clickable) { 15997 removeTapCallback(); 15998 removeLongPressCallback(); 15999 mInContextButtonPress = false; 16000 mHasPerformedLongPress = false; 16001 mIgnoreNextUpEvent = false; 16002 break; 16003 } 16004 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 16005 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 16006 // take focus if we don't have it already and we should in 16007 // touch mode. 16008 boolean focusTaken = false; 16009 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 16010 focusTaken = requestFocus(); 16011 } 16012 16013 if (prepressed) { 16014 // The button is being released before we actually 16015 // showed it as pressed. Make it show the pressed 16016 // state now (before scheduling the click) to ensure 16017 // the user sees it. 16018 setPressed(true, x, y); 16019 } 16020 16021 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 16022 // This is a tap, so remove the longpress check 16023 removeLongPressCallback(); 16024 16025 // Only perform take click actions if we were in the pressed state 16026 if (!focusTaken) { 16027 // Use a Runnable and post this rather than calling 16028 // performClick directly. This lets other visual state 16029 // of the view update before click actions start. 16030 if (mPerformClick == null) { 16031 mPerformClick = new PerformClick(); 16032 } 16033 if (!post(mPerformClick)) { 16034 performClickInternal(); 16035 } 16036 } 16037 } 16038 16039 if (mUnsetPressedState == null) { 16040 mUnsetPressedState = new UnsetPressedState(); 16041 } 16042 16043 if (prepressed) { 16044 postDelayed(mUnsetPressedState, 16045 ViewConfiguration.getPressedStateDuration()); 16046 } else if (!post(mUnsetPressedState)) { 16047 // If the post failed, unpress right now 16048 mUnsetPressedState.run(); 16049 } 16050 16051 removeTapCallback(); 16052 } 16053 mIgnoreNextUpEvent = false; 16054 break; 16055 16056 case MotionEvent.ACTION_DOWN: 16057 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 16058 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 16059 } 16060 mHasPerformedLongPress = false; 16061 16062 if (!clickable) { 16063 checkForLongClick( 16064 ViewConfiguration.getLongPressTimeout(), 16065 x, 16066 y, 16067 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16068 break; 16069 } 16070 16071 if (performButtonActionOnTouchDown(event)) { 16072 break; 16073 } 16074 16075 // Walk up the hierarchy to determine if we're inside a scrolling container. 16076 boolean isInScrollingContainer = isInScrollingContainer(); 16077 16078 // For views inside a scrolling container, delay the pressed feedback for 16079 // a short period in case this is a scroll. 16080 if (isInScrollingContainer) { 16081 mPrivateFlags |= PFLAG_PREPRESSED; 16082 if (mPendingCheckForTap == null) { 16083 mPendingCheckForTap = new CheckForTap(); 16084 } 16085 mPendingCheckForTap.x = event.getX(); 16086 mPendingCheckForTap.y = event.getY(); 16087 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 16088 } else { 16089 // Not inside a scrolling container, so show the feedback right away 16090 setPressed(true, x, y); 16091 checkForLongClick( 16092 ViewConfiguration.getLongPressTimeout(), 16093 x, 16094 y, 16095 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16096 } 16097 break; 16098 16099 case MotionEvent.ACTION_CANCEL: 16100 if (clickable) { 16101 setPressed(false); 16102 } 16103 removeTapCallback(); 16104 removeLongPressCallback(); 16105 mInContextButtonPress = false; 16106 mHasPerformedLongPress = false; 16107 mIgnoreNextUpEvent = false; 16108 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16109 break; 16110 16111 case MotionEvent.ACTION_MOVE: 16112 if (clickable) { 16113 drawableHotspotChanged(x, y); 16114 } 16115 16116 final int motionClassification = event.getClassification(); 16117 final boolean ambiguousGesture = 16118 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 16119 int touchSlop = mTouchSlop; 16120 if (ambiguousGesture && hasPendingLongPressCallback()) { 16121 if (!pointInView(x, y, touchSlop)) { 16122 // The default action here is to cancel long press. But instead, we 16123 // just extend the timeout here, in case the classification 16124 // stays ambiguous. 16125 removeLongPressCallback(); 16126 long delay = (long) (ViewConfiguration.getLongPressTimeout() 16127 * mAmbiguousGestureMultiplier); 16128 // Subtract the time already spent 16129 delay -= event.getEventTime() - event.getDownTime(); 16130 checkForLongClick( 16131 delay, 16132 x, 16133 y, 16134 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16135 } 16136 touchSlop *= mAmbiguousGestureMultiplier; 16137 } 16138 16139 // Be lenient about moving outside of buttons 16140 if (!pointInView(x, y, touchSlop)) { 16141 // Outside button 16142 // Remove any future long press/tap checks 16143 removeTapCallback(); 16144 removeLongPressCallback(); 16145 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 16146 setPressed(false); 16147 } 16148 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16149 } 16150 16151 final boolean deepPress = 16152 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 16153 if (deepPress && hasPendingLongPressCallback()) { 16154 // process the long click action immediately 16155 removeLongPressCallback(); 16156 checkForLongClick( 16157 0 /* send immediately */, 16158 x, 16159 y, 16160 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 16161 } 16162 16163 break; 16164 } 16165 16166 return true; 16167 } 16168 16169 return false; 16170 } 16171 16172 /** 16173 * @hide 16174 */ 16175 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isInScrollingContainer()16176 public boolean isInScrollingContainer() { 16177 ViewParent p = getParent(); 16178 while (p != null && p instanceof ViewGroup) { 16179 if (((ViewGroup) p).shouldDelayChildPressedState()) { 16180 return true; 16181 } 16182 p = p.getParent(); 16183 } 16184 return false; 16185 } 16186 16187 /** 16188 * Remove the longpress detection timer. 16189 */ removeLongPressCallback()16190 private void removeLongPressCallback() { 16191 if (mPendingCheckForLongPress != null) { 16192 removeCallbacks(mPendingCheckForLongPress); 16193 } 16194 } 16195 16196 /** 16197 * Return true if the long press callback is scheduled to run sometime in the future. 16198 * Return false if there is no scheduled long press callback at the moment. 16199 */ hasPendingLongPressCallback()16200 private boolean hasPendingLongPressCallback() { 16201 if (mPendingCheckForLongPress == null) { 16202 return false; 16203 } 16204 final AttachInfo attachInfo = mAttachInfo; 16205 if (attachInfo == null) { 16206 return false; 16207 } 16208 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 16209 } 16210 16211 /** 16212 * Remove the pending click action 16213 */ 16214 @UnsupportedAppUsage removePerformClickCallback()16215 private void removePerformClickCallback() { 16216 if (mPerformClick != null) { 16217 removeCallbacks(mPerformClick); 16218 } 16219 } 16220 16221 /** 16222 * Remove the prepress detection timer. 16223 */ removeUnsetPressCallback()16224 private void removeUnsetPressCallback() { 16225 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 16226 setPressed(false); 16227 removeCallbacks(mUnsetPressedState); 16228 } 16229 } 16230 16231 /** 16232 * Remove the tap detection timer. 16233 */ removeTapCallback()16234 private void removeTapCallback() { 16235 if (mPendingCheckForTap != null) { 16236 mPrivateFlags &= ~PFLAG_PREPRESSED; 16237 removeCallbacks(mPendingCheckForTap); 16238 } 16239 } 16240 16241 /** 16242 * Cancels a pending long press. Your subclass can use this if you 16243 * want the context menu to come up if the user presses and holds 16244 * at the same place, but you don't want it to come up if they press 16245 * and then move around enough to cause scrolling. 16246 */ cancelLongPress()16247 public void cancelLongPress() { 16248 removeLongPressCallback(); 16249 16250 /* 16251 * The prepressed state handled by the tap callback is a display 16252 * construct, but the tap callback will post a long press callback 16253 * less its own timeout. Remove it here. 16254 */ 16255 removeTapCallback(); 16256 } 16257 16258 /** 16259 * Sets the TouchDelegate for this View. 16260 */ setTouchDelegate(TouchDelegate delegate)16261 public void setTouchDelegate(TouchDelegate delegate) { 16262 mTouchDelegate = delegate; 16263 } 16264 16265 /** 16266 * Gets the TouchDelegate for this View. 16267 */ getTouchDelegate()16268 public TouchDelegate getTouchDelegate() { 16269 return mTouchDelegate; 16270 } 16271 16272 /** 16273 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 16274 * 16275 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 16276 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 16277 * available. This method should only be called for touch events. 16278 * 16279 * <p class="note">This API is not intended for most applications. Buffered dispatch 16280 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 16281 * streams will not improve your input latency. Side effects include: increased latency, 16282 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 16283 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 16284 * you.</p> 16285 * 16286 * To receive unbuffered events for arbitrary input device source classes, use 16287 * {@link #requestUnbufferedDispatch(int)}, 16288 * 16289 * @see View#requestUnbufferedDispatch(int) 16290 */ requestUnbufferedDispatch(MotionEvent event)16291 public final void requestUnbufferedDispatch(MotionEvent event) { 16292 final int action = event.getAction(); 16293 if (mAttachInfo == null 16294 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 16295 || !event.isTouchEvent()) { 16296 return; 16297 } 16298 mAttachInfo.mUnbufferedDispatchRequested = true; 16299 } 16300 16301 /** 16302 * Request unbuffered dispatch of the given event source class to this view. 16303 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 16304 * automatically terminate, and allows the specification of arbitrary input source classes. 16305 * 16306 * @param source The combined input source class to request unbuffered dispatch for. All 16307 * events coming from these source classes will not be buffered. Set to 16308 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 16309 * 16310 * @see View#requestUnbufferedDispatch(MotionEvent) 16311 */ requestUnbufferedDispatch(@nputSourceClass int source)16312 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 16313 if (mUnbufferedInputSource == source) { 16314 return; 16315 } 16316 mUnbufferedInputSource = source; 16317 if (mParent != null) { 16318 mParent.onDescendantUnbufferedRequested(); 16319 } 16320 } 16321 hasSize()16322 private boolean hasSize() { 16323 return (mBottom > mTop) && (mRight > mLeft); 16324 } 16325 canTakeFocus()16326 private boolean canTakeFocus() { 16327 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 16328 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 16329 && ((mViewFlags & ENABLED_MASK) == ENABLED) 16330 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 16331 } 16332 16333 /** 16334 * Set flags controlling behavior of this view. 16335 * 16336 * @param flags Constant indicating the value which should be set 16337 * @param mask Constant indicating the bit range that should be changed 16338 */ 16339 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)16340 void setFlags(int flags, int mask) { 16341 final boolean accessibilityEnabled = 16342 AccessibilityManager.getInstance(mContext).isEnabled(); 16343 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 16344 16345 int old = mViewFlags; 16346 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 16347 16348 int changed = mViewFlags ^ old; 16349 if (changed == 0) { 16350 return; 16351 } 16352 int privateFlags = mPrivateFlags; 16353 boolean shouldNotifyFocusableAvailable = false; 16354 16355 // If focusable is auto, update the FOCUSABLE bit. 16356 int focusableChangedByAuto = 0; 16357 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 16358 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 16359 // Heuristic only takes into account whether view is clickable. 16360 final int newFocus; 16361 if ((mViewFlags & CLICKABLE) != 0) { 16362 newFocus = FOCUSABLE; 16363 } else { 16364 newFocus = NOT_FOCUSABLE; 16365 } 16366 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 16367 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 16368 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 16369 } 16370 16371 /* Check if the FOCUSABLE bit has changed */ 16372 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 16373 if (((old & FOCUSABLE) == FOCUSABLE) 16374 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 16375 /* Give up focus if we are no longer focusable */ 16376 clearFocus(); 16377 if (mParent instanceof ViewGroup) { 16378 ((ViewGroup) mParent).clearFocusedInCluster(); 16379 } 16380 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 16381 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 16382 /* 16383 * Tell the view system that we are now available to take focus 16384 * if no one else already has it. 16385 */ 16386 if (mParent != null) { 16387 ViewRootImpl viewRootImpl = getViewRootImpl(); 16388 if (!sAutoFocusableOffUIThreadWontNotifyParents 16389 || focusableChangedByAuto == 0 16390 || viewRootImpl == null 16391 || viewRootImpl.mThread == Thread.currentThread()) { 16392 shouldNotifyFocusableAvailable = canTakeFocus(); 16393 } 16394 } 16395 } 16396 } 16397 16398 final int newVisibility = flags & VISIBILITY_MASK; 16399 if (newVisibility == VISIBLE) { 16400 if ((changed & VISIBILITY_MASK) != 0) { 16401 /* 16402 * If this view is becoming visible, invalidate it in case it changed while 16403 * it was not visible. Marking it drawn ensures that the invalidation will 16404 * go through. 16405 */ 16406 mPrivateFlags |= PFLAG_DRAWN; 16407 invalidate(true); 16408 16409 needGlobalAttributesUpdate(true); 16410 16411 // a view becoming visible is worth notifying the parent about in case nothing has 16412 // focus. Even if this specific view isn't focusable, it may contain something that 16413 // is, so let the root view try to give this focus if nothing else does. 16414 shouldNotifyFocusableAvailable = hasSize(); 16415 } 16416 } 16417 16418 if ((changed & ENABLED_MASK) != 0) { 16419 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 16420 // a view becoming enabled should notify the parent as long as the view is also 16421 // visible and the parent wasn't already notified by becoming visible during this 16422 // setFlags invocation. 16423 shouldNotifyFocusableAvailable = canTakeFocus(); 16424 } else { 16425 if (isFocused()) clearFocus(); 16426 } 16427 } 16428 16429 if (shouldNotifyFocusableAvailable && mParent != null) { 16430 mParent.focusableViewAvailable(this); 16431 } 16432 16433 /* Check if the GONE bit has changed */ 16434 if ((changed & GONE) != 0) { 16435 needGlobalAttributesUpdate(false); 16436 requestLayout(); 16437 16438 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 16439 if (hasFocus()) { 16440 clearFocus(); 16441 if (mParent instanceof ViewGroup) { 16442 ((ViewGroup) mParent).clearFocusedInCluster(); 16443 } 16444 } 16445 clearAccessibilityFocus(); 16446 destroyDrawingCache(); 16447 if (mParent instanceof View) { 16448 // GONE views noop invalidation, so invalidate the parent 16449 ((View) mParent).invalidate(true); 16450 } 16451 // Mark the view drawn to ensure that it gets invalidated properly the next 16452 // time it is visible and gets invalidated 16453 mPrivateFlags |= PFLAG_DRAWN; 16454 } 16455 if (mAttachInfo != null) { 16456 mAttachInfo.mViewVisibilityChanged = true; 16457 } 16458 } 16459 16460 /* Check if the VISIBLE bit has changed */ 16461 if ((changed & INVISIBLE) != 0) { 16462 needGlobalAttributesUpdate(false); 16463 /* 16464 * If this view is becoming invisible, set the DRAWN flag so that 16465 * the next invalidate() will not be skipped. 16466 */ 16467 mPrivateFlags |= PFLAG_DRAWN; 16468 16469 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 16470 // root view becoming invisible shouldn't clear focus and accessibility focus 16471 if (getRootView() != this) { 16472 if (hasFocus()) { 16473 clearFocus(); 16474 if (mParent instanceof ViewGroup) { 16475 ((ViewGroup) mParent).clearFocusedInCluster(); 16476 } 16477 } 16478 clearAccessibilityFocus(); 16479 } 16480 } 16481 if (mAttachInfo != null) { 16482 mAttachInfo.mViewVisibilityChanged = true; 16483 } 16484 } 16485 16486 if ((changed & VISIBILITY_MASK) != 0) { 16487 // If the view is invisible, cleanup its display list to free up resources 16488 if (newVisibility != VISIBLE && mAttachInfo != null) { 16489 cleanupDraw(); 16490 } 16491 16492 if (mParent instanceof ViewGroup) { 16493 ViewGroup parent = (ViewGroup) mParent; 16494 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 16495 newVisibility); 16496 parent.invalidate(true); 16497 } else if (mParent != null) { 16498 mParent.invalidateChild(this, null); 16499 } 16500 16501 if (mAttachInfo != null) { 16502 dispatchVisibilityChanged(this, newVisibility); 16503 16504 // Aggregated visibility changes are dispatched to attached views 16505 // in visible windows where the parent is currently shown/drawn 16506 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 16507 // discounting clipping or overlapping. This makes it a good place 16508 // to change animation states. 16509 if (mParent != null && getWindowVisibility() == VISIBLE && 16510 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 16511 dispatchVisibilityAggregated(newVisibility == VISIBLE); 16512 } 16513 // If this view is invisible from visible, then sending the A11y event by its 16514 // parent which is shown and has the accessibility important. 16515 if ((old & VISIBILITY_MASK) == VISIBLE) { 16516 notifySubtreeAccessibilityStateChangedByParentIfNeeded(); 16517 } else { 16518 notifySubtreeAccessibilityStateChangedIfNeeded(); 16519 } 16520 } 16521 } 16522 16523 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 16524 destroyDrawingCache(); 16525 } 16526 16527 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 16528 destroyDrawingCache(); 16529 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16530 invalidateParentCaches(); 16531 } 16532 16533 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 16534 destroyDrawingCache(); 16535 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16536 } 16537 16538 if ((changed & DRAW_MASK) != 0) { 16539 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 16540 if (mBackground != null 16541 || mDefaultFocusHighlight != null 16542 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 16543 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 16544 } else { 16545 mPrivateFlags |= PFLAG_SKIP_DRAW; 16546 } 16547 } else { 16548 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 16549 } 16550 requestLayout(); 16551 invalidate(true); 16552 } 16553 16554 if ((changed & KEEP_SCREEN_ON) != 0) { 16555 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 16556 mParent.recomputeViewAttributes(this); 16557 } 16558 } 16559 16560 if (accessibilityEnabled) { 16561 // If we're an accessibility pane and the visibility changed, we already have sent 16562 // a state change, so we really don't need to report other changes. 16563 if (isAccessibilityPane()) { 16564 changed &= ~VISIBILITY_MASK; 16565 } 16566 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 16567 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 16568 || (changed & CONTEXT_CLICKABLE) != 0) { 16569 if (oldIncludeForAccessibility != includeForAccessibility()) { 16570 notifySubtreeAccessibilityStateChangedIfNeeded(); 16571 } else { 16572 notifyViewAccessibilityStateChangedIfNeeded( 16573 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16574 } 16575 } else if ((changed & ENABLED_MASK) != 0) { 16576 notifyViewAccessibilityStateChangedIfNeeded( 16577 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16578 } 16579 } 16580 } 16581 16582 /** 16583 * Change the view's z order in the tree, so it's on top of other sibling 16584 * views. This ordering change may affect layout, if the parent container 16585 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 16586 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 16587 * method should be followed by calls to {@link #requestLayout()} and 16588 * {@link View#invalidate()} on the view's parent to force the parent to redraw 16589 * with the new child ordering. 16590 * 16591 * @see ViewGroup#bringChildToFront(View) 16592 */ bringToFront()16593 public void bringToFront() { 16594 if (mParent != null) { 16595 mParent.bringChildToFront(this); 16596 } 16597 } 16598 16599 /** 16600 * This is called in response to an internal scroll in this view (i.e., the 16601 * view scrolled its own contents). This is typically as a result of 16602 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 16603 * called. 16604 * 16605 * @param l Current horizontal scroll origin. 16606 * @param t Current vertical scroll origin. 16607 * @param oldl Previous horizontal scroll origin. 16608 * @param oldt Previous vertical scroll origin. 16609 */ onScrollChanged(int l, int t, int oldl, int oldt)16610 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 16611 notifySubtreeAccessibilityStateChangedIfNeeded(); 16612 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 16613 16614 mBackgroundSizeChanged = true; 16615 mDefaultFocusHighlightSizeChanged = true; 16616 if (mForegroundInfo != null) { 16617 mForegroundInfo.mBoundsChanged = true; 16618 } 16619 16620 final AttachInfo ai = mAttachInfo; 16621 if (ai != null) { 16622 ai.mViewScrollChanged = true; 16623 } 16624 16625 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 16626 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 16627 } 16628 } 16629 16630 /** 16631 * Interface definition for a callback to be invoked when the scroll 16632 * X or Y positions of a view change. 16633 * <p> 16634 * <b>Note:</b> Some views handle scrolling independently from View and may 16635 * have their own separate listeners for scroll-type events. For example, 16636 * {@link android.widget.ListView ListView} allows clients to register an 16637 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 16638 * to listen for changes in list scroll position. 16639 * 16640 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 16641 */ 16642 public interface OnScrollChangeListener { 16643 /** 16644 * Called when the scroll position of a view changes. 16645 * 16646 * @param v The view whose scroll position has changed. 16647 * @param scrollX Current horizontal scroll origin. 16648 * @param scrollY Current vertical scroll origin. 16649 * @param oldScrollX Previous horizontal scroll origin. 16650 * @param oldScrollY Previous vertical scroll origin. 16651 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)16652 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 16653 } 16654 16655 /** 16656 * Interface definition for a callback to be invoked when the layout bounds of a view 16657 * changes due to layout processing. 16658 */ 16659 public interface OnLayoutChangeListener { 16660 /** 16661 * Called when the layout bounds of a view changes due to layout processing. 16662 * 16663 * @param v The view whose bounds have changed. 16664 * @param left The new value of the view's left property. 16665 * @param top The new value of the view's top property. 16666 * @param right The new value of the view's right property. 16667 * @param bottom The new value of the view's bottom property. 16668 * @param oldLeft The previous value of the view's left property. 16669 * @param oldTop The previous value of the view's top property. 16670 * @param oldRight The previous value of the view's right property. 16671 * @param oldBottom The previous value of the view's bottom property. 16672 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)16673 void onLayoutChange(View v, int left, int top, int right, int bottom, 16674 int oldLeft, int oldTop, int oldRight, int oldBottom); 16675 } 16676 16677 /** 16678 * This is called during layout when the size of this view has changed. If 16679 * you were just added to the view hierarchy, you're called with the old 16680 * values of 0. 16681 * 16682 * @param w Current width of this view. 16683 * @param h Current height of this view. 16684 * @param oldw Old width of this view. 16685 * @param oldh Old height of this view. 16686 */ onSizeChanged(int w, int h, int oldw, int oldh)16687 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 16688 } 16689 16690 /** 16691 * Called by draw to draw the child views. This may be overridden 16692 * by derived classes to gain control just before its children are drawn 16693 * (but after its own view has been drawn). 16694 * @param canvas the canvas on which to draw the view 16695 */ dispatchDraw(Canvas canvas)16696 protected void dispatchDraw(Canvas canvas) { 16697 16698 } 16699 16700 /** 16701 * Gets the parent of this view. Note that the parent is a 16702 * ViewParent and not necessarily a View. 16703 * 16704 * @return Parent of this view. 16705 */ getParent()16706 public final ViewParent getParent() { 16707 return mParent; 16708 } 16709 16710 /** 16711 * Set the horizontal scrolled position of your view. This will cause a call to 16712 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16713 * invalidated. 16714 * @param value the x position to scroll to 16715 */ setScrollX(int value)16716 public void setScrollX(int value) { 16717 scrollTo(value, mScrollY); 16718 } 16719 16720 /** 16721 * Set the vertical scrolled position of your view. This will cause a call to 16722 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16723 * invalidated. 16724 * @param value the y position to scroll to 16725 */ setScrollY(int value)16726 public void setScrollY(int value) { 16727 scrollTo(mScrollX, value); 16728 } 16729 16730 /** 16731 * Return the scrolled left position of this view. This is the left edge of 16732 * the displayed part of your view. You do not need to draw any pixels 16733 * farther left, since those are outside of the frame of your view on 16734 * screen. 16735 * 16736 * @return The left edge of the displayed part of your view, in pixels. 16737 */ 16738 @InspectableProperty getScrollX()16739 public final int getScrollX() { 16740 return mScrollX; 16741 } 16742 16743 /** 16744 * Return the scrolled top position of this view. This is the top edge of 16745 * the displayed part of your view. You do not need to draw any pixels above 16746 * it, since those are outside of the frame of your view on screen. 16747 * 16748 * @return The top edge of the displayed part of your view, in pixels. 16749 */ 16750 @InspectableProperty getScrollY()16751 public final int getScrollY() { 16752 return mScrollY; 16753 } 16754 16755 /** 16756 * Return the width of your view. 16757 * 16758 * @return The width of your view, in pixels. 16759 */ 16760 @ViewDebug.ExportedProperty(category = "layout") getWidth()16761 public final int getWidth() { 16762 return mRight - mLeft; 16763 } 16764 16765 /** 16766 * Return the height of your view. 16767 * 16768 * @return The height of your view, in pixels. 16769 */ 16770 @ViewDebug.ExportedProperty(category = "layout") getHeight()16771 public final int getHeight() { 16772 return mBottom - mTop; 16773 } 16774 16775 /** 16776 * Return the visible drawing bounds of your view. Fills in the output 16777 * rectangle with the values from getScrollX(), getScrollY(), 16778 * getWidth(), and getHeight(). These bounds do not account for any 16779 * transformation properties currently set on the view, such as 16780 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 16781 * 16782 * @param outRect The (scrolled) drawing bounds of the view. 16783 */ getDrawingRect(Rect outRect)16784 public void getDrawingRect(Rect outRect) { 16785 outRect.left = mScrollX; 16786 outRect.top = mScrollY; 16787 outRect.right = mScrollX + (mRight - mLeft); 16788 outRect.bottom = mScrollY + (mBottom - mTop); 16789 } 16790 16791 /** 16792 * Like {@link #getMeasuredWidthAndState()}, but only returns the 16793 * raw width component (that is the result is masked by 16794 * {@link #MEASURED_SIZE_MASK}). 16795 * 16796 * @return The raw measured width of this view. 16797 */ getMeasuredWidth()16798 public final int getMeasuredWidth() { 16799 return mMeasuredWidth & MEASURED_SIZE_MASK; 16800 } 16801 16802 /** 16803 * Return the full width measurement information for this view as computed 16804 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16805 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16806 * This should be used during measurement and layout calculations only. Use 16807 * {@link #getWidth()} to see how wide a view is after layout. 16808 * 16809 * @return The measured width of this view as a bit mask. 16810 */ 16811 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16812 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16813 name = "MEASURED_STATE_TOO_SMALL"), 16814 }) getMeasuredWidthAndState()16815 public final int getMeasuredWidthAndState() { 16816 return mMeasuredWidth; 16817 } 16818 16819 /** 16820 * Like {@link #getMeasuredHeightAndState()}, but only returns the 16821 * raw height component (that is the result is masked by 16822 * {@link #MEASURED_SIZE_MASK}). 16823 * 16824 * @return The raw measured height of this view. 16825 */ getMeasuredHeight()16826 public final int getMeasuredHeight() { 16827 return mMeasuredHeight & MEASURED_SIZE_MASK; 16828 } 16829 16830 /** 16831 * Return the full height measurement information for this view as computed 16832 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16833 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16834 * This should be used during measurement and layout calculations only. Use 16835 * {@link #getHeight()} to see how high a view is after layout. 16836 * 16837 * @return The measured height of this view as a bit mask. 16838 */ 16839 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16840 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16841 name = "MEASURED_STATE_TOO_SMALL"), 16842 }) getMeasuredHeightAndState()16843 public final int getMeasuredHeightAndState() { 16844 return mMeasuredHeight; 16845 } 16846 16847 /** 16848 * Return only the state bits of {@link #getMeasuredWidthAndState()} 16849 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 16850 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 16851 * and the height component is at the shifted bits 16852 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 16853 */ getMeasuredState()16854 public final int getMeasuredState() { 16855 return (mMeasuredWidth&MEASURED_STATE_MASK) 16856 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 16857 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 16858 } 16859 16860 /** 16861 * The transform matrix of this view, which is calculated based on the current 16862 * rotation, scale, and pivot properties. 16863 * 16864 * @see #getRotation() 16865 * @see #getScaleX() 16866 * @see #getScaleY() 16867 * @see #getPivotX() 16868 * @see #getPivotY() 16869 * @return The current transform matrix for the view 16870 */ getMatrix()16871 public Matrix getMatrix() { 16872 ensureTransformationInfo(); 16873 final Matrix matrix = mTransformationInfo.mMatrix; 16874 mRenderNode.getMatrix(matrix); 16875 return matrix; 16876 } 16877 16878 /** 16879 * Returns true if the transform matrix is the identity matrix. 16880 * Recomputes the matrix if necessary. 16881 * 16882 * @return True if the transform matrix is the identity matrix, false otherwise. 16883 * @hide 16884 */ 16885 @UnsupportedAppUsage hasIdentityMatrix()16886 public final boolean hasIdentityMatrix() { 16887 return mRenderNode.hasIdentityMatrix(); 16888 } 16889 16890 @UnsupportedAppUsage ensureTransformationInfo()16891 void ensureTransformationInfo() { 16892 if (mTransformationInfo == null) { 16893 mTransformationInfo = new TransformationInfo(); 16894 } 16895 } 16896 16897 /** 16898 * Utility method to retrieve the inverse of the current mMatrix property. 16899 * We cache the matrix to avoid recalculating it when transform properties 16900 * have not changed. 16901 * 16902 * @return The inverse of the current matrix of this view. 16903 * @hide 16904 */ 16905 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getInverseMatrix()16906 public final Matrix getInverseMatrix() { 16907 ensureTransformationInfo(); 16908 if (mTransformationInfo.mInverseMatrix == null) { 16909 mTransformationInfo.mInverseMatrix = new Matrix(); 16910 } 16911 final Matrix matrix = mTransformationInfo.mInverseMatrix; 16912 mRenderNode.getInverseMatrix(matrix); 16913 return matrix; 16914 } 16915 16916 /** 16917 * Gets the distance along the Z axis from the camera to this view. 16918 * 16919 * @see #setCameraDistance(float) 16920 * 16921 * @return The distance along the Z axis. 16922 */ getCameraDistance()16923 public float getCameraDistance() { 16924 final float dpi = mResources.getDisplayMetrics().densityDpi; 16925 return mRenderNode.getCameraDistance() * dpi; 16926 } 16927 16928 /** 16929 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 16930 * views are drawn) from the camera to this view. The camera's distance 16931 * affects 3D transformations, for instance rotations around the X and Y 16932 * axis. If the rotationX or rotationY properties are changed and this view is 16933 * large (more than half the size of the screen), it is recommended to always 16934 * use a camera distance that's greater than the height (X axis rotation) or 16935 * the width (Y axis rotation) of this view.</p> 16936 * 16937 * <p>The distance of the camera from the view plane can have an affect on the 16938 * perspective distortion of the view when it is rotated around the x or y axis. 16939 * For example, a large distance will result in a large viewing angle, and there 16940 * will not be much perspective distortion of the view as it rotates. A short 16941 * distance may cause much more perspective distortion upon rotation, and can 16942 * also result in some drawing artifacts if the rotated view ends up partially 16943 * behind the camera (which is why the recommendation is to use a distance at 16944 * least as far as the size of the view, if the view is to be rotated.)</p> 16945 * 16946 * <p>The distance is expressed in "depth pixels." The default distance depends 16947 * on the screen density. For instance, on a medium density display, the 16948 * default distance is 1280. On a high density display, the default distance 16949 * is 1920.</p> 16950 * 16951 * <p>If you want to specify a distance that leads to visually consistent 16952 * results across various densities, use the following formula:</p> 16953 * <pre> 16954 * float scale = context.getResources().getDisplayMetrics().density; 16955 * view.setCameraDistance(distance * scale); 16956 * </pre> 16957 * 16958 * <p>The density scale factor of a high density display is 1.5, 16959 * and 1920 = 1280 * 1.5.</p> 16960 * 16961 * @param distance The distance in "depth pixels", if negative the opposite 16962 * value is used 16963 * 16964 * @see #setRotationX(float) 16965 * @see #setRotationY(float) 16966 */ setCameraDistance(float distance)16967 public void setCameraDistance(float distance) { 16968 final float dpi = mResources.getDisplayMetrics().densityDpi; 16969 16970 invalidateViewProperty(true, false); 16971 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 16972 invalidateViewProperty(false, false); 16973 16974 invalidateParentIfNeededAndWasQuickRejected(); 16975 } 16976 16977 /** 16978 * The degrees that the view is rotated around the pivot point. 16979 * 16980 * @see #setRotation(float) 16981 * @see #getPivotX() 16982 * @see #getPivotY() 16983 * 16984 * @return The degrees of rotation. 16985 */ 16986 @ViewDebug.ExportedProperty(category = "drawing") 16987 @InspectableProperty getRotation()16988 public float getRotation() { 16989 return mRenderNode.getRotationZ(); 16990 } 16991 16992 /** 16993 * Sets the degrees that the view is rotated around the pivot point. Increasing values 16994 * result in clockwise rotation. 16995 * 16996 * @param rotation The degrees of rotation. 16997 * 16998 * @see #getRotation() 16999 * @see #getPivotX() 17000 * @see #getPivotY() 17001 * @see #setRotationX(float) 17002 * @see #setRotationY(float) 17003 * 17004 * @attr ref android.R.styleable#View_rotation 17005 */ 17006 @RemotableViewMethod setRotation(float rotation)17007 public void setRotation(float rotation) { 17008 if (rotation != getRotation()) { 17009 // Double-invalidation is necessary to capture view's old and new areas 17010 invalidateViewProperty(true, false); 17011 mRenderNode.setRotationZ(rotation); 17012 invalidateViewProperty(false, true); 17013 17014 invalidateParentIfNeededAndWasQuickRejected(); 17015 notifySubtreeAccessibilityStateChangedIfNeeded(); 17016 } 17017 } 17018 17019 /** 17020 * The degrees that the view is rotated around the vertical axis through the pivot point. 17021 * 17022 * @see #getPivotX() 17023 * @see #getPivotY() 17024 * @see #setRotationY(float) 17025 * 17026 * @return The degrees of Y rotation. 17027 */ 17028 @ViewDebug.ExportedProperty(category = "drawing") 17029 @InspectableProperty getRotationY()17030 public float getRotationY() { 17031 return mRenderNode.getRotationY(); 17032 } 17033 17034 /** 17035 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 17036 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 17037 * down the y axis. 17038 * 17039 * When rotating large views, it is recommended to adjust the camera distance 17040 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 17041 * 17042 * @param rotationY The degrees of Y rotation. 17043 * 17044 * @see #getRotationY() 17045 * @see #getPivotX() 17046 * @see #getPivotY() 17047 * @see #setRotation(float) 17048 * @see #setRotationX(float) 17049 * @see #setCameraDistance(float) 17050 * 17051 * @attr ref android.R.styleable#View_rotationY 17052 */ 17053 @RemotableViewMethod setRotationY(float rotationY)17054 public void setRotationY(float rotationY) { 17055 if (rotationY != getRotationY()) { 17056 invalidateViewProperty(true, false); 17057 mRenderNode.setRotationY(rotationY); 17058 invalidateViewProperty(false, true); 17059 17060 invalidateParentIfNeededAndWasQuickRejected(); 17061 notifySubtreeAccessibilityStateChangedIfNeeded(); 17062 } 17063 } 17064 17065 /** 17066 * The degrees that the view is rotated around the horizontal axis through the pivot point. 17067 * 17068 * @see #getPivotX() 17069 * @see #getPivotY() 17070 * @see #setRotationX(float) 17071 * 17072 * @return The degrees of X rotation. 17073 */ 17074 @ViewDebug.ExportedProperty(category = "drawing") 17075 @InspectableProperty getRotationX()17076 public float getRotationX() { 17077 return mRenderNode.getRotationX(); 17078 } 17079 17080 /** 17081 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 17082 * Increasing values result in clockwise rotation from the viewpoint of looking down the 17083 * x axis. 17084 * 17085 * When rotating large views, it is recommended to adjust the camera distance 17086 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 17087 * 17088 * @param rotationX The degrees of X rotation. 17089 * 17090 * @see #getRotationX() 17091 * @see #getPivotX() 17092 * @see #getPivotY() 17093 * @see #setRotation(float) 17094 * @see #setRotationY(float) 17095 * @see #setCameraDistance(float) 17096 * 17097 * @attr ref android.R.styleable#View_rotationX 17098 */ 17099 @RemotableViewMethod setRotationX(float rotationX)17100 public void setRotationX(float rotationX) { 17101 if (rotationX != getRotationX()) { 17102 invalidateViewProperty(true, false); 17103 mRenderNode.setRotationX(rotationX); 17104 invalidateViewProperty(false, true); 17105 17106 invalidateParentIfNeededAndWasQuickRejected(); 17107 notifySubtreeAccessibilityStateChangedIfNeeded(); 17108 } 17109 } 17110 17111 /** 17112 * The amount that the view is scaled in x around the pivot point, as a proportion of 17113 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 17114 * 17115 * <p>By default, this is 1.0f. 17116 * 17117 * @see #getPivotX() 17118 * @see #getPivotY() 17119 * @return The scaling factor. 17120 */ 17121 @ViewDebug.ExportedProperty(category = "drawing") 17122 @InspectableProperty getScaleX()17123 public float getScaleX() { 17124 return mRenderNode.getScaleX(); 17125 } 17126 17127 /** 17128 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 17129 * the view's unscaled width. A value of 1 means that no scaling is applied. 17130 * 17131 * @param scaleX The scaling factor. 17132 * @see #getPivotX() 17133 * @see #getPivotY() 17134 * 17135 * @attr ref android.R.styleable#View_scaleX 17136 */ 17137 @RemotableViewMethod setScaleX(float scaleX)17138 public void setScaleX(float scaleX) { 17139 if (scaleX != getScaleX()) { 17140 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 17141 invalidateViewProperty(true, false); 17142 mRenderNode.setScaleX(scaleX); 17143 invalidateViewProperty(false, true); 17144 17145 invalidateParentIfNeededAndWasQuickRejected(); 17146 notifySubtreeAccessibilityStateChangedIfNeeded(); 17147 } 17148 } 17149 17150 /** 17151 * The amount that the view is scaled in y around the pivot point, as a proportion of 17152 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 17153 * 17154 * <p>By default, this is 1.0f. 17155 * 17156 * @see #getPivotX() 17157 * @see #getPivotY() 17158 * @return The scaling factor. 17159 */ 17160 @ViewDebug.ExportedProperty(category = "drawing") 17161 @InspectableProperty getScaleY()17162 public float getScaleY() { 17163 return mRenderNode.getScaleY(); 17164 } 17165 17166 /** 17167 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 17168 * the view's unscaled width. A value of 1 means that no scaling is applied. 17169 * 17170 * @param scaleY The scaling factor. 17171 * @see #getPivotX() 17172 * @see #getPivotY() 17173 * 17174 * @attr ref android.R.styleable#View_scaleY 17175 */ 17176 @RemotableViewMethod setScaleY(float scaleY)17177 public void setScaleY(float scaleY) { 17178 if (scaleY != getScaleY()) { 17179 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 17180 invalidateViewProperty(true, false); 17181 mRenderNode.setScaleY(scaleY); 17182 invalidateViewProperty(false, true); 17183 17184 invalidateParentIfNeededAndWasQuickRejected(); 17185 notifySubtreeAccessibilityStateChangedIfNeeded(); 17186 } 17187 } 17188 17189 /** 17190 * The x location of the point around which the view is {@link #setRotation(float) rotated} 17191 * and {@link #setScaleX(float) scaled}. 17192 * 17193 * @see #getRotation() 17194 * @see #getScaleX() 17195 * @see #getScaleY() 17196 * @see #getPivotY() 17197 * @return The x location of the pivot point. 17198 * 17199 * @attr ref android.R.styleable#View_transformPivotX 17200 */ 17201 @ViewDebug.ExportedProperty(category = "drawing") 17202 @InspectableProperty(name = "transformPivotX") getPivotX()17203 public float getPivotX() { 17204 return mRenderNode.getPivotX(); 17205 } 17206 17207 /** 17208 * Sets the x location of the point around which the view is 17209 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 17210 * By default, the pivot point is centered on the object. 17211 * Setting this property disables this behavior and causes the view to use only the 17212 * explicitly set pivotX and pivotY values. 17213 * 17214 * @param pivotX The x location of the pivot point. 17215 * @see #getRotation() 17216 * @see #getScaleX() 17217 * @see #getScaleY() 17218 * @see #getPivotY() 17219 * 17220 * @attr ref android.R.styleable#View_transformPivotX 17221 */ 17222 @RemotableViewMethod setPivotX(float pivotX)17223 public void setPivotX(float pivotX) { 17224 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 17225 invalidateViewProperty(true, false); 17226 mRenderNode.setPivotX(pivotX); 17227 invalidateViewProperty(false, true); 17228 17229 invalidateParentIfNeededAndWasQuickRejected(); 17230 } 17231 } 17232 17233 /** 17234 * The y location of the point around which the view is {@link #setRotation(float) rotated} 17235 * and {@link #setScaleY(float) scaled}. 17236 * 17237 * @see #getRotation() 17238 * @see #getScaleX() 17239 * @see #getScaleY() 17240 * @see #getPivotY() 17241 * @return The y location of the pivot point. 17242 * 17243 * @attr ref android.R.styleable#View_transformPivotY 17244 */ 17245 @ViewDebug.ExportedProperty(category = "drawing") 17246 @InspectableProperty(name = "transformPivotY") getPivotY()17247 public float getPivotY() { 17248 return mRenderNode.getPivotY(); 17249 } 17250 17251 /** 17252 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 17253 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 17254 * Setting this property disables this behavior and causes the view to use only the 17255 * explicitly set pivotX and pivotY values. 17256 * 17257 * @param pivotY The y location of the pivot point. 17258 * @see #getRotation() 17259 * @see #getScaleX() 17260 * @see #getScaleY() 17261 * @see #getPivotY() 17262 * 17263 * @attr ref android.R.styleable#View_transformPivotY 17264 */ 17265 @RemotableViewMethod setPivotY(float pivotY)17266 public void setPivotY(float pivotY) { 17267 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 17268 invalidateViewProperty(true, false); 17269 mRenderNode.setPivotY(pivotY); 17270 invalidateViewProperty(false, true); 17271 17272 invalidateParentIfNeededAndWasQuickRejected(); 17273 } 17274 } 17275 17276 /** 17277 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 17278 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 17279 * of the view. 17280 * 17281 * @return True if a pivot has been set, false if the default pivot is being used 17282 */ isPivotSet()17283 public boolean isPivotSet() { 17284 return mRenderNode.isPivotExplicitlySet(); 17285 } 17286 17287 /** 17288 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 17289 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 17290 * and the pivot used for rotation will return to default of being centered on the view. 17291 */ resetPivot()17292 public void resetPivot() { 17293 if (mRenderNode.resetPivot()) { 17294 invalidateViewProperty(false, false); 17295 } 17296 } 17297 17298 /** 17299 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 17300 * completely transparent and 1 means the view is completely opaque. 17301 * 17302 * <p>By default this is 1.0f. 17303 * @return The opacity of the view. 17304 */ 17305 @ViewDebug.ExportedProperty(category = "drawing") 17306 @InspectableProperty getAlpha()17307 public float getAlpha() { 17308 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 17309 } 17310 17311 /** 17312 * Sets the behavior for overlapping rendering for this view (see {@link 17313 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 17314 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 17315 * providing the value which is then used internally. That is, when {@link 17316 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 17317 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 17318 * instead. 17319 * 17320 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 17321 * instead of that returned by {@link #hasOverlappingRendering()}. 17322 * 17323 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 17324 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)17325 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 17326 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 17327 if (hasOverlappingRendering) { 17328 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17329 } else { 17330 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17331 } 17332 } 17333 17334 /** 17335 * Returns the value for overlapping rendering that is used internally. This is either 17336 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 17337 * the return value of {@link #hasOverlappingRendering()}, otherwise. 17338 * 17339 * @return The value for overlapping rendering being used internally. 17340 */ getHasOverlappingRendering()17341 public final boolean getHasOverlappingRendering() { 17342 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 17343 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 17344 hasOverlappingRendering(); 17345 } 17346 17347 /** 17348 * Returns whether this View has content which overlaps. 17349 * 17350 * <p>This function, intended to be overridden by specific View types, is an optimization when 17351 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 17352 * an offscreen buffer and then composited into place, which can be expensive. If the view has 17353 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 17354 * directly. An example of overlapping rendering is a TextView with a background image, such as 17355 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 17356 * ImageView with only the foreground image. The default implementation returns true; subclasses 17357 * should override if they have cases which can be optimized.</p> 17358 * 17359 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 17360 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 17361 * 17362 * @return true if the content in this view might overlap, false otherwise. 17363 */ 17364 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()17365 public boolean hasOverlappingRendering() { 17366 return true; 17367 } 17368 17369 /** 17370 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 17371 * completely transparent and 1 means the view is completely opaque. 17372 * 17373 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 17374 * can have significant performance implications, especially for large views. It is best to use 17375 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 17376 * 17377 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 17378 * strongly recommended for performance reasons to either override 17379 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 17380 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 17381 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 17382 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 17383 * of rendering cost, even for simple or small views. Starting with 17384 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 17385 * applied to the view at the rendering level.</p> 17386 * 17387 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 17388 * responsible for applying the opacity itself.</p> 17389 * 17390 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 17391 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 17392 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 17393 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 17394 * 17395 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 17396 * value will clip a View to its bounds, unless the View returns <code>false</code> from 17397 * {@link #hasOverlappingRendering}.</p> 17398 * 17399 * @param alpha The opacity of the view. 17400 * 17401 * @see #hasOverlappingRendering() 17402 * @see #setLayerType(int, android.graphics.Paint) 17403 * 17404 * @attr ref android.R.styleable#View_alpha 17405 */ 17406 @RemotableViewMethod setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)17407 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 17408 ensureTransformationInfo(); 17409 if (mTransformationInfo.mAlpha != alpha) { 17410 setAlphaInternal(alpha); 17411 if (onSetAlpha((int) (alpha * 255))) { 17412 mPrivateFlags |= PFLAG_ALPHA_SET; 17413 // subclass is handling alpha - don't optimize rendering cache invalidation 17414 invalidateParentCaches(); 17415 invalidate(true); 17416 } else { 17417 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17418 invalidateViewProperty(true, false); 17419 mRenderNode.setAlpha(getFinalAlpha()); 17420 } 17421 } 17422 } 17423 17424 /** 17425 * Faster version of setAlpha() which performs the same steps except there are 17426 * no calls to invalidate(). The caller of this function should perform proper invalidation 17427 * on the parent and this object. The return value indicates whether the subclass handles 17428 * alpha (the return value for onSetAlpha()). 17429 * 17430 * @param alpha The new value for the alpha property 17431 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 17432 * the new value for the alpha property is different from the old value 17433 */ 17434 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)17435 boolean setAlphaNoInvalidation(float alpha) { 17436 ensureTransformationInfo(); 17437 if (mTransformationInfo.mAlpha != alpha) { 17438 setAlphaInternal(alpha); 17439 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 17440 if (subclassHandlesAlpha) { 17441 mPrivateFlags |= PFLAG_ALPHA_SET; 17442 return true; 17443 } else { 17444 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17445 mRenderNode.setAlpha(getFinalAlpha()); 17446 } 17447 } 17448 return false; 17449 } 17450 setAlphaInternal(float alpha)17451 void setAlphaInternal(float alpha) { 17452 float oldAlpha = mTransformationInfo.mAlpha; 17453 mTransformationInfo.mAlpha = alpha; 17454 // Report visibility changes, which can affect children, to accessibility 17455 if ((alpha == 0) ^ (oldAlpha == 0)) { 17456 notifySubtreeAccessibilityStateChangedIfNeeded(); 17457 } 17458 } 17459 17460 /** 17461 * This property is intended only for use by the Fade transition, which animates it 17462 * to produce a visual translucency that does not side-effect (or get affected by) 17463 * the real alpha property. This value is composited with the other alpha value 17464 * (and the AlphaAnimation value, when that is present) to produce a final visual 17465 * translucency result, which is what is passed into the DisplayList. 17466 */ setTransitionAlpha(float alpha)17467 public void setTransitionAlpha(float alpha) { 17468 ensureTransformationInfo(); 17469 if (mTransformationInfo.mTransitionAlpha != alpha) { 17470 mTransformationInfo.mTransitionAlpha = alpha; 17471 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17472 invalidateViewProperty(true, false); 17473 mRenderNode.setAlpha(getFinalAlpha()); 17474 } 17475 } 17476 17477 /** 17478 * Calculates the visual alpha of this view, which is a combination of the actual 17479 * alpha value and the transitionAlpha value (if set). 17480 */ getFinalAlpha()17481 private float getFinalAlpha() { 17482 if (mTransformationInfo != null) { 17483 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 17484 } 17485 return 1; 17486 } 17487 17488 /** 17489 * This property is intended only for use by the Fade transition, which animates 17490 * it to produce a visual translucency that does not side-effect (or get affected 17491 * by) the real alpha property. This value is composited with the other alpha 17492 * value (and the AlphaAnimation value, when that is present) to produce a final 17493 * visual translucency result, which is what is passed into the DisplayList. 17494 */ 17495 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()17496 public float getTransitionAlpha() { 17497 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 17498 } 17499 17500 /** 17501 * Sets whether or not to allow force dark to apply to this view. 17502 * 17503 * Setting this to false will disable the auto-dark feature on everything this view 17504 * draws, including any descendants. 17505 * 17506 * Setting this to true will allow this view to be automatically made dark, however 17507 * a value of 'true' will not override any 'false' value in its parent chain nor will 17508 * it prevent any 'false' in any of its children. 17509 * 17510 * The default behavior of force dark is also influenced by the Theme's 17511 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 17512 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 17513 * 17514 * @param allow Whether or not to allow force dark. 17515 */ setForceDarkAllowed(boolean allow)17516 public void setForceDarkAllowed(boolean allow) { 17517 if (mRenderNode.setForceDarkAllowed(allow)) { 17518 // Currently toggling force-dark requires a new display list push to apply 17519 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 17520 invalidate(); 17521 } 17522 } 17523 17524 /** 17525 * See {@link #setForceDarkAllowed(boolean)} 17526 * 17527 * @return true if force dark is allowed (default), false if it is disabled 17528 */ 17529 @ViewDebug.ExportedProperty(category = "drawing") 17530 @InspectableProperty isForceDarkAllowed()17531 public boolean isForceDarkAllowed() { 17532 return mRenderNode.isForceDarkAllowed(); 17533 } 17534 17535 /** 17536 * Top position of this view relative to its parent. 17537 * 17538 * @return The top of this view, in pixels. 17539 */ 17540 @ViewDebug.CapturedViewProperty getTop()17541 public final int getTop() { 17542 return mTop; 17543 } 17544 17545 /** 17546 * Sets the top position of this view relative to its parent. This method is meant to be called 17547 * by the layout system and should not generally be called otherwise, because the property 17548 * may be changed at any time by the layout. 17549 * 17550 * @param top The top of this view, in pixels. 17551 */ setTop(int top)17552 public final void setTop(int top) { 17553 if (top != mTop) { 17554 final boolean matrixIsIdentity = hasIdentityMatrix(); 17555 if (matrixIsIdentity) { 17556 if (mAttachInfo != null) { 17557 int minTop; 17558 int yLoc; 17559 if (top < mTop) { 17560 minTop = top; 17561 yLoc = top - mTop; 17562 } else { 17563 minTop = mTop; 17564 yLoc = 0; 17565 } 17566 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 17567 } 17568 } else { 17569 // Double-invalidation is necessary to capture view's old and new areas 17570 invalidate(true); 17571 } 17572 17573 int width = mRight - mLeft; 17574 int oldHeight = mBottom - mTop; 17575 17576 mTop = top; 17577 mRenderNode.setTop(mTop); 17578 17579 sizeChange(width, mBottom - mTop, width, oldHeight); 17580 17581 if (!matrixIsIdentity) { 17582 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17583 invalidate(true); 17584 } 17585 mBackgroundSizeChanged = true; 17586 mDefaultFocusHighlightSizeChanged = true; 17587 if (mForegroundInfo != null) { 17588 mForegroundInfo.mBoundsChanged = true; 17589 } 17590 invalidateParentIfNeeded(); 17591 } 17592 } 17593 17594 /** 17595 * Bottom position of this view relative to its parent. 17596 * 17597 * @return The bottom of this view, in pixels. 17598 */ 17599 @ViewDebug.CapturedViewProperty getBottom()17600 public final int getBottom() { 17601 return mBottom; 17602 } 17603 17604 /** 17605 * True if this view has changed since the last time being drawn. 17606 * 17607 * @return The dirty state of this view. 17608 */ isDirty()17609 public boolean isDirty() { 17610 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 17611 } 17612 17613 /** 17614 * Sets the bottom position of this view relative to its parent. This method is meant to be 17615 * called by the layout system and should not generally be called otherwise, because the 17616 * property may be changed at any time by the layout. 17617 * 17618 * @param bottom The bottom of this view, in pixels. 17619 */ setBottom(int bottom)17620 public final void setBottom(int bottom) { 17621 if (bottom != mBottom) { 17622 final boolean matrixIsIdentity = hasIdentityMatrix(); 17623 if (matrixIsIdentity) { 17624 if (mAttachInfo != null) { 17625 int maxBottom; 17626 if (bottom < mBottom) { 17627 maxBottom = mBottom; 17628 } else { 17629 maxBottom = bottom; 17630 } 17631 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 17632 } 17633 } else { 17634 // Double-invalidation is necessary to capture view's old and new areas 17635 invalidate(true); 17636 } 17637 17638 int width = mRight - mLeft; 17639 int oldHeight = mBottom - mTop; 17640 17641 mBottom = bottom; 17642 mRenderNode.setBottom(mBottom); 17643 17644 sizeChange(width, mBottom - mTop, width, oldHeight); 17645 17646 if (!matrixIsIdentity) { 17647 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17648 invalidate(true); 17649 } 17650 mBackgroundSizeChanged = true; 17651 mDefaultFocusHighlightSizeChanged = true; 17652 if (mForegroundInfo != null) { 17653 mForegroundInfo.mBoundsChanged = true; 17654 } 17655 invalidateParentIfNeeded(); 17656 } 17657 } 17658 17659 /** 17660 * Left position of this view relative to its parent. 17661 * 17662 * @return The left edge of this view, in pixels. 17663 */ 17664 @ViewDebug.CapturedViewProperty getLeft()17665 public final int getLeft() { 17666 return mLeft; 17667 } 17668 17669 /** 17670 * Sets the left position of this view relative to its parent. This method is meant to be called 17671 * by the layout system and should not generally be called otherwise, because the property 17672 * may be changed at any time by the layout. 17673 * 17674 * @param left The left of this view, in pixels. 17675 */ setLeft(int left)17676 public final void setLeft(int left) { 17677 if (left != mLeft) { 17678 final boolean matrixIsIdentity = hasIdentityMatrix(); 17679 if (matrixIsIdentity) { 17680 if (mAttachInfo != null) { 17681 int minLeft; 17682 int xLoc; 17683 if (left < mLeft) { 17684 minLeft = left; 17685 xLoc = left - mLeft; 17686 } else { 17687 minLeft = mLeft; 17688 xLoc = 0; 17689 } 17690 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 17691 } 17692 } else { 17693 // Double-invalidation is necessary to capture view's old and new areas 17694 invalidate(true); 17695 } 17696 17697 int oldWidth = mRight - mLeft; 17698 int height = mBottom - mTop; 17699 17700 mLeft = left; 17701 mRenderNode.setLeft(left); 17702 17703 sizeChange(mRight - mLeft, height, oldWidth, height); 17704 17705 if (!matrixIsIdentity) { 17706 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17707 invalidate(true); 17708 } 17709 mBackgroundSizeChanged = true; 17710 mDefaultFocusHighlightSizeChanged = true; 17711 if (mForegroundInfo != null) { 17712 mForegroundInfo.mBoundsChanged = true; 17713 } 17714 invalidateParentIfNeeded(); 17715 } 17716 } 17717 17718 /** 17719 * Right position of this view relative to its parent. 17720 * 17721 * @return The right edge of this view, in pixels. 17722 */ 17723 @ViewDebug.CapturedViewProperty getRight()17724 public final int getRight() { 17725 return mRight; 17726 } 17727 17728 /** 17729 * Sets the right position of this view relative to its parent. This method is meant to be called 17730 * by the layout system and should not generally be called otherwise, because the property 17731 * may be changed at any time by the layout. 17732 * 17733 * @param right The right of this view, in pixels. 17734 */ setRight(int right)17735 public final void setRight(int right) { 17736 if (right != mRight) { 17737 final boolean matrixIsIdentity = hasIdentityMatrix(); 17738 if (matrixIsIdentity) { 17739 if (mAttachInfo != null) { 17740 int maxRight; 17741 if (right < mRight) { 17742 maxRight = mRight; 17743 } else { 17744 maxRight = right; 17745 } 17746 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 17747 } 17748 } else { 17749 // Double-invalidation is necessary to capture view's old and new areas 17750 invalidate(true); 17751 } 17752 17753 int oldWidth = mRight - mLeft; 17754 int height = mBottom - mTop; 17755 17756 mRight = right; 17757 mRenderNode.setRight(mRight); 17758 17759 sizeChange(mRight - mLeft, height, oldWidth, height); 17760 17761 if (!matrixIsIdentity) { 17762 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17763 invalidate(true); 17764 } 17765 mBackgroundSizeChanged = true; 17766 mDefaultFocusHighlightSizeChanged = true; 17767 if (mForegroundInfo != null) { 17768 mForegroundInfo.mBoundsChanged = true; 17769 } 17770 invalidateParentIfNeeded(); 17771 } 17772 } 17773 sanitizeFloatPropertyValue(float value, String propertyName)17774 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 17775 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 17776 } 17777 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)17778 private static float sanitizeFloatPropertyValue(float value, String propertyName, 17779 float min, float max) { 17780 // The expected "nothing bad happened" path 17781 if (value >= min && value <= max) return value; 17782 17783 if (value < min || value == Float.NEGATIVE_INFINITY) { 17784 if (sThrowOnInvalidFloatProperties) { 17785 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17786 + value + ", the value must be >= " + min); 17787 } 17788 return min; 17789 } 17790 17791 if (value > max || value == Float.POSITIVE_INFINITY) { 17792 if (sThrowOnInvalidFloatProperties) { 17793 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17794 + value + ", the value must be <= " + max); 17795 } 17796 return max; 17797 } 17798 17799 if (Float.isNaN(value)) { 17800 if (sThrowOnInvalidFloatProperties) { 17801 throw new IllegalArgumentException( 17802 "Cannot set '" + propertyName + "' to Float.NaN"); 17803 } 17804 return 0; // Unclear which direction this NaN went so... 0? 17805 } 17806 17807 // Shouldn't be possible to reach this. 17808 throw new IllegalStateException("How do you get here?? " + value); 17809 } 17810 17811 /** 17812 * The visual x position of this view, in pixels. This is equivalent to the 17813 * {@link #setTranslationX(float) translationX} property plus the current 17814 * {@link #getLeft() left} property. 17815 * 17816 * @return The visual x position of this view, in pixels. 17817 */ 17818 @ViewDebug.ExportedProperty(category = "drawing") getX()17819 public float getX() { 17820 return mLeft + getTranslationX(); 17821 } 17822 17823 /** 17824 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 17825 * {@link #setTranslationX(float) translationX} property to be the difference between 17826 * the x value passed in and the current {@link #getLeft() left} property. 17827 * 17828 * @param x The visual x position of this view, in pixels. 17829 */ setX(float x)17830 public void setX(float x) { 17831 setTranslationX(x - mLeft); 17832 } 17833 17834 /** 17835 * The visual y position of this view, in pixels. This is equivalent to the 17836 * {@link #setTranslationY(float) translationY} property plus the current 17837 * {@link #getTop() top} property. 17838 * 17839 * @return The visual y position of this view, in pixels. 17840 */ 17841 @ViewDebug.ExportedProperty(category = "drawing") getY()17842 public float getY() { 17843 return mTop + getTranslationY(); 17844 } 17845 17846 /** 17847 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 17848 * {@link #setTranslationY(float) translationY} property to be the difference between 17849 * the y value passed in and the current {@link #getTop() top} property. 17850 * 17851 * @param y The visual y position of this view, in pixels. 17852 */ setY(float y)17853 public void setY(float y) { 17854 setTranslationY(y - mTop); 17855 } 17856 17857 /** 17858 * The visual z position of this view, in pixels. This is equivalent to the 17859 * {@link #setTranslationZ(float) translationZ} property plus the current 17860 * {@link #getElevation() elevation} property. 17861 * 17862 * @return The visual z position of this view, in pixels. 17863 */ 17864 @ViewDebug.ExportedProperty(category = "drawing") getZ()17865 public float getZ() { 17866 return getElevation() + getTranslationZ(); 17867 } 17868 17869 /** 17870 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 17871 * {@link #setTranslationZ(float) translationZ} property to be the difference between 17872 * the z value passed in and the current {@link #getElevation() elevation} property. 17873 * 17874 * @param z The visual z position of this view, in pixels. 17875 */ setZ(float z)17876 public void setZ(float z) { 17877 setTranslationZ(z - getElevation()); 17878 } 17879 17880 /** 17881 * The base elevation of this view relative to its parent, in pixels. 17882 * 17883 * @return The base depth position of the view, in pixels. 17884 */ 17885 @ViewDebug.ExportedProperty(category = "drawing") 17886 @InspectableProperty getElevation()17887 public float getElevation() { 17888 return mRenderNode.getElevation(); 17889 } 17890 17891 /** 17892 * Sets the base elevation of this view, in pixels. 17893 * 17894 * @attr ref android.R.styleable#View_elevation 17895 */ 17896 @RemotableViewMethod setElevation(float elevation)17897 public void setElevation(float elevation) { 17898 if (elevation != getElevation()) { 17899 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 17900 invalidateViewProperty(true, false); 17901 mRenderNode.setElevation(elevation); 17902 invalidateViewProperty(false, true); 17903 17904 invalidateParentIfNeededAndWasQuickRejected(); 17905 } 17906 } 17907 17908 /** 17909 * The horizontal location of this view relative to its {@link #getLeft() left} position. 17910 * This position is post-layout, in addition to wherever the object's 17911 * layout placed it. 17912 * 17913 * @return The horizontal position of this view relative to its left position, in pixels. 17914 */ 17915 @ViewDebug.ExportedProperty(category = "drawing") 17916 @InspectableProperty getTranslationX()17917 public float getTranslationX() { 17918 return mRenderNode.getTranslationX(); 17919 } 17920 17921 /** 17922 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 17923 * This effectively positions the object post-layout, in addition to wherever the object's 17924 * layout placed it. 17925 * 17926 * @param translationX The horizontal position of this view relative to its left position, 17927 * in pixels. 17928 * 17929 * @attr ref android.R.styleable#View_translationX 17930 */ 17931 @RemotableViewMethod setTranslationX(float translationX)17932 public void setTranslationX(float translationX) { 17933 if (translationX != getTranslationX()) { 17934 invalidateViewProperty(true, false); 17935 mRenderNode.setTranslationX(translationX); 17936 invalidateViewProperty(false, true); 17937 17938 invalidateParentIfNeededAndWasQuickRejected(); 17939 notifySubtreeAccessibilityStateChangedIfNeeded(); 17940 } 17941 } 17942 17943 /** 17944 * The vertical location of this view relative to its {@link #getTop() top} position. 17945 * This position is post-layout, in addition to wherever the object's 17946 * layout placed it. 17947 * 17948 * @return The vertical position of this view relative to its top position, 17949 * in pixels. 17950 */ 17951 @ViewDebug.ExportedProperty(category = "drawing") 17952 @InspectableProperty getTranslationY()17953 public float getTranslationY() { 17954 return mRenderNode.getTranslationY(); 17955 } 17956 17957 /** 17958 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 17959 * This effectively positions the object post-layout, in addition to wherever the object's 17960 * layout placed it. 17961 * 17962 * @param translationY The vertical position of this view relative to its top position, 17963 * in pixels. 17964 * 17965 * @attr ref android.R.styleable#View_translationY 17966 */ 17967 @RemotableViewMethod setTranslationY(float translationY)17968 public void setTranslationY(float translationY) { 17969 if (translationY != getTranslationY()) { 17970 invalidateViewProperty(true, false); 17971 mRenderNode.setTranslationY(translationY); 17972 invalidateViewProperty(false, true); 17973 17974 invalidateParentIfNeededAndWasQuickRejected(); 17975 notifySubtreeAccessibilityStateChangedIfNeeded(); 17976 } 17977 } 17978 17979 /** 17980 * The depth location of this view relative to its {@link #getElevation() elevation}. 17981 * 17982 * @return The depth of this view relative to its elevation. 17983 */ 17984 @ViewDebug.ExportedProperty(category = "drawing") 17985 @InspectableProperty getTranslationZ()17986 public float getTranslationZ() { 17987 return mRenderNode.getTranslationZ(); 17988 } 17989 17990 /** 17991 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 17992 * 17993 * @attr ref android.R.styleable#View_translationZ 17994 */ 17995 @RemotableViewMethod setTranslationZ(float translationZ)17996 public void setTranslationZ(float translationZ) { 17997 if (translationZ != getTranslationZ()) { 17998 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 17999 invalidateViewProperty(true, false); 18000 mRenderNode.setTranslationZ(translationZ); 18001 invalidateViewProperty(false, true); 18002 18003 invalidateParentIfNeededAndWasQuickRejected(); 18004 } 18005 } 18006 18007 /** 18008 * Changes the transformation matrix on the view. This is used in animation frameworks, 18009 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 18010 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 18011 * Application developers should use transformation methods like {@link #setRotation(float)}, 18012 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 18013 * and {@link #setTranslationY(float)} (float)}} instead. 18014 * 18015 * @param matrix The matrix, null indicates that the matrix should be cleared. 18016 * @see #getAnimationMatrix() 18017 */ setAnimationMatrix(@ullable Matrix matrix)18018 public void setAnimationMatrix(@Nullable Matrix matrix) { 18019 invalidateViewProperty(true, false); 18020 mRenderNode.setAnimationMatrix(matrix); 18021 invalidateViewProperty(false, true); 18022 18023 invalidateParentIfNeededAndWasQuickRejected(); 18024 } 18025 18026 /** 18027 * Return the current transformation matrix of the view. This is used in animation frameworks, 18028 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 18029 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 18030 * Application developers should use transformation methods like {@link #setRotation(float)}, 18031 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 18032 * and {@link #setTranslationY(float)} (float)}} instead. 18033 * 18034 * @return the Matrix, null indicates there is no transformation 18035 * @see #setAnimationMatrix(Matrix) 18036 */ 18037 @Nullable getAnimationMatrix()18038 public Matrix getAnimationMatrix() { 18039 return mRenderNode.getAnimationMatrix(); 18040 } 18041 18042 /** 18043 * Returns the current StateListAnimator if exists. 18044 * 18045 * @return StateListAnimator or null if it does not exists 18046 * @see #setStateListAnimator(android.animation.StateListAnimator) 18047 */ 18048 @InspectableProperty getStateListAnimator()18049 public StateListAnimator getStateListAnimator() { 18050 return mStateListAnimator; 18051 } 18052 18053 /** 18054 * Attaches the provided StateListAnimator to this View. 18055 * <p> 18056 * Any previously attached StateListAnimator will be detached. 18057 * 18058 * @param stateListAnimator The StateListAnimator to update the view 18059 * @see android.animation.StateListAnimator 18060 */ setStateListAnimator(StateListAnimator stateListAnimator)18061 public void setStateListAnimator(StateListAnimator stateListAnimator) { 18062 if (mStateListAnimator == stateListAnimator) { 18063 return; 18064 } 18065 if (mStateListAnimator != null) { 18066 mStateListAnimator.setTarget(null); 18067 } 18068 mStateListAnimator = stateListAnimator; 18069 if (stateListAnimator != null) { 18070 stateListAnimator.setTarget(this); 18071 if (isAttachedToWindow()) { 18072 stateListAnimator.setState(getDrawableState()); 18073 } 18074 } 18075 } 18076 18077 /** 18078 * Returns whether the Outline should be used to clip the contents of the View. 18079 * <p> 18080 * Note that this flag will only be respected if the View's Outline returns true from 18081 * {@link Outline#canClip()}. 18082 * 18083 * @see #setOutlineProvider(ViewOutlineProvider) 18084 * @see #setClipToOutline(boolean) 18085 */ getClipToOutline()18086 public final boolean getClipToOutline() { 18087 return mRenderNode.getClipToOutline(); 18088 } 18089 18090 /** 18091 * Sets whether the View's Outline should be used to clip the contents of the View. 18092 * <p> 18093 * Only a single non-rectangular clip can be applied on a View at any time. 18094 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 18095 * circular reveal} animation take priority over Outline clipping, and 18096 * child Outline clipping takes priority over Outline clipping done by a 18097 * parent. 18098 * <p> 18099 * Note that this flag will only be respected if the View's Outline returns true from 18100 * {@link Outline#canClip()}. 18101 * 18102 * @see #setOutlineProvider(ViewOutlineProvider) 18103 * @see #getClipToOutline() 18104 * 18105 * @attr ref android.R.styleable#View_clipToOutline 18106 */ 18107 @RemotableViewMethod setClipToOutline(boolean clipToOutline)18108 public void setClipToOutline(boolean clipToOutline) { 18109 damageInParent(); 18110 if (getClipToOutline() != clipToOutline) { 18111 mRenderNode.setClipToOutline(clipToOutline); 18112 } 18113 } 18114 18115 // correspond to the enum values of View_outlineProvider 18116 private static final int PROVIDER_BACKGROUND = 0; 18117 private static final int PROVIDER_NONE = 1; 18118 private static final int PROVIDER_BOUNDS = 2; 18119 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)18120 private void setOutlineProviderFromAttribute(int providerInt) { 18121 switch (providerInt) { 18122 case PROVIDER_BACKGROUND: 18123 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 18124 break; 18125 case PROVIDER_NONE: 18126 setOutlineProvider(null); 18127 break; 18128 case PROVIDER_BOUNDS: 18129 setOutlineProvider(ViewOutlineProvider.BOUNDS); 18130 break; 18131 case PROVIDER_PADDED_BOUNDS: 18132 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 18133 break; 18134 } 18135 } 18136 18137 /** 18138 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 18139 * the shape of the shadow it casts, and enables outline clipping. 18140 * <p> 18141 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 18142 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 18143 * outline provider with this method allows this behavior to be overridden. 18144 * <p> 18145 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 18146 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 18147 * <p> 18148 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 18149 * 18150 * @see #setClipToOutline(boolean) 18151 * @see #getClipToOutline() 18152 * @see #getOutlineProvider() 18153 */ setOutlineProvider(ViewOutlineProvider provider)18154 public void setOutlineProvider(ViewOutlineProvider provider) { 18155 mOutlineProvider = provider; 18156 invalidateOutline(); 18157 } 18158 18159 /** 18160 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 18161 * that defines the shape of the shadow it casts, and enables outline clipping. 18162 * 18163 * @see #setOutlineProvider(ViewOutlineProvider) 18164 */ 18165 @InspectableProperty getOutlineProvider()18166 public ViewOutlineProvider getOutlineProvider() { 18167 return mOutlineProvider; 18168 } 18169 18170 /** 18171 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 18172 * 18173 * @see #setOutlineProvider(ViewOutlineProvider) 18174 */ invalidateOutline()18175 public void invalidateOutline() { 18176 rebuildOutline(); 18177 18178 notifySubtreeAccessibilityStateChangedIfNeeded(); 18179 invalidateViewProperty(false, false); 18180 } 18181 18182 /** 18183 * Internal version of {@link #invalidateOutline()} which invalidates the 18184 * outline without invalidating the view itself. This is intended to be called from 18185 * within methods in the View class itself which are the result of the view being 18186 * invalidated already. For example, when we are drawing the background of a View, 18187 * we invalidate the outline in case it changed in the meantime, but we do not 18188 * need to invalidate the view because we're already drawing the background as part 18189 * of drawing the view in response to an earlier invalidation of the view. 18190 */ rebuildOutline()18191 private void rebuildOutline() { 18192 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 18193 if (mAttachInfo == null) return; 18194 18195 if (mOutlineProvider == null) { 18196 // no provider, remove outline 18197 mRenderNode.setOutline(null); 18198 } else { 18199 final Outline outline = mAttachInfo.mTmpOutline; 18200 outline.setEmpty(); 18201 outline.setAlpha(1.0f); 18202 18203 mOutlineProvider.getOutline(this, outline); 18204 mRenderNode.setOutline(outline); 18205 } 18206 } 18207 18208 /** 18209 * HierarchyViewer only 18210 * 18211 * @hide 18212 */ 18213 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()18214 public boolean hasShadow() { 18215 return mRenderNode.hasShadow(); 18216 } 18217 18218 /** 18219 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 18220 * elevation value. 18221 * <p> 18222 * By default the shadow color is black. Generally, this color will be opaque so the intensity 18223 * of the shadow is consistent between different views with different colors. 18224 * <p> 18225 * The opacity of the final spot shadow is a function of the shadow caster height, the 18226 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 18227 * {@link android.R.attr#spotShadowAlpha} theme attribute. 18228 * 18229 * @attr ref android.R.styleable#View_outlineSpotShadowColor 18230 * @param color The color this View will cast for its elevation spot shadow. 18231 */ setOutlineSpotShadowColor(@olorInt int color)18232 public void setOutlineSpotShadowColor(@ColorInt int color) { 18233 if (mRenderNode.setSpotShadowColor(color)) { 18234 invalidateViewProperty(true, true); 18235 } 18236 } 18237 18238 /** 18239 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 18240 * was set 18241 */ 18242 @InspectableProperty getOutlineSpotShadowColor()18243 public @ColorInt int getOutlineSpotShadowColor() { 18244 return mRenderNode.getSpotShadowColor(); 18245 } 18246 18247 /** 18248 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 18249 * elevation value. 18250 * <p> 18251 * By default the shadow color is black. Generally, this color will be opaque so the intensity 18252 * of the shadow is consistent between different views with different colors. 18253 * <p> 18254 * The opacity of the final ambient shadow is a function of the shadow caster height, the 18255 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 18256 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 18257 * 18258 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 18259 * @param color The color this View will cast for its elevation shadow. 18260 */ setOutlineAmbientShadowColor(@olorInt int color)18261 public void setOutlineAmbientShadowColor(@ColorInt int color) { 18262 if (mRenderNode.setAmbientShadowColor(color)) { 18263 invalidateViewProperty(true, true); 18264 } 18265 } 18266 18267 /** 18268 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 18269 * nothing was set 18270 */ 18271 @InspectableProperty getOutlineAmbientShadowColor()18272 public @ColorInt int getOutlineAmbientShadowColor() { 18273 return mRenderNode.getAmbientShadowColor(); 18274 } 18275 18276 18277 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)18278 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 18279 mRenderNode.setRevealClip(shouldClip, x, y, radius); 18280 invalidateViewProperty(false, false); 18281 } 18282 18283 /** 18284 * Hit rectangle in parent's coordinates 18285 * 18286 * @param outRect The hit rectangle of the view. 18287 */ getHitRect(Rect outRect)18288 public void getHitRect(Rect outRect) { 18289 if (hasIdentityMatrix() || mAttachInfo == null) { 18290 outRect.set(mLeft, mTop, mRight, mBottom); 18291 } else { 18292 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 18293 tmpRect.set(0, 0, getWidth(), getHeight()); 18294 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 18295 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 18296 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 18297 } 18298 } 18299 18300 /** 18301 * Determines whether the given point, in local coordinates is inside the view. 18302 */ pointInView(float localX, float localY)18303 /*package*/ final boolean pointInView(float localX, float localY) { 18304 return pointInView(localX, localY, 0); 18305 } 18306 18307 /** 18308 * Utility method to determine whether the given point, in local coordinates, 18309 * is inside the view, where the area of the view is expanded by the slop factor. 18310 * This method is called while processing touch-move events to determine if the event 18311 * is still within the view. 18312 * 18313 * @hide 18314 */ 18315 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)18316 public boolean pointInView(float localX, float localY, float slop) { 18317 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 18318 localY < ((mBottom - mTop) + slop); 18319 } 18320 18321 /** 18322 * When a view has focus and the user navigates away from it, the next view is searched for 18323 * starting from the rectangle filled in by this method. 18324 * 18325 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 18326 * of the view. However, if your view maintains some idea of internal selection, 18327 * such as a cursor, or a selected row or column, you should override this method and 18328 * fill in a more specific rectangle. 18329 * 18330 * @param r The rectangle to fill in, in this view's coordinates. 18331 */ getFocusedRect(Rect r)18332 public void getFocusedRect(Rect r) { 18333 getDrawingRect(r); 18334 } 18335 18336 /** 18337 * If some part of this view is not clipped by any of its parents, then 18338 * return that area in r in global (root) coordinates. To convert r to local 18339 * coordinates (without taking possible View rotations into account), offset 18340 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 18341 * If the view is completely clipped or translated out, return false. 18342 * 18343 * @param r If true is returned, r holds the global coordinates of the 18344 * visible portion of this view. 18345 * @param globalOffset If true is returned, globalOffset holds the dx,dy 18346 * between this view and its root. globalOffet may be null. 18347 * @return true if r is non-empty (i.e. part of the view is visible at the 18348 * root level. 18349 */ getGlobalVisibleRect(Rect r, Point globalOffset)18350 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 18351 int width = mRight - mLeft; 18352 int height = mBottom - mTop; 18353 if (width > 0 && height > 0) { 18354 r.set(0, 0, width, height); 18355 if (globalOffset != null) { 18356 globalOffset.set(-mScrollX, -mScrollY); 18357 } 18358 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 18359 } 18360 return false; 18361 } 18362 getGlobalVisibleRect(Rect r)18363 public final boolean getGlobalVisibleRect(Rect r) { 18364 return getGlobalVisibleRect(r, null); 18365 } 18366 getLocalVisibleRect(Rect r)18367 public final boolean getLocalVisibleRect(Rect r) { 18368 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 18369 if (getGlobalVisibleRect(r, offset)) { 18370 r.offset(-offset.x, -offset.y); // make r local 18371 return true; 18372 } 18373 return false; 18374 } 18375 18376 /** 18377 * Offset this view's vertical location by the specified number of pixels. 18378 * 18379 * @param offset the number of pixels to offset the view by 18380 */ offsetTopAndBottom(int offset)18381 public void offsetTopAndBottom(int offset) { 18382 if (offset != 0) { 18383 final boolean matrixIsIdentity = hasIdentityMatrix(); 18384 if (matrixIsIdentity) { 18385 if (isHardwareAccelerated()) { 18386 invalidateViewProperty(false, false); 18387 } else { 18388 final ViewParent p = mParent; 18389 if (p != null && mAttachInfo != null) { 18390 final Rect r = mAttachInfo.mTmpInvalRect; 18391 int minTop; 18392 int maxBottom; 18393 int yLoc; 18394 if (offset < 0) { 18395 minTop = mTop + offset; 18396 maxBottom = mBottom; 18397 yLoc = offset; 18398 } else { 18399 minTop = mTop; 18400 maxBottom = mBottom + offset; 18401 yLoc = 0; 18402 } 18403 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 18404 p.invalidateChild(this, r); 18405 } 18406 } 18407 } else { 18408 invalidateViewProperty(false, false); 18409 } 18410 18411 mTop += offset; 18412 mBottom += offset; 18413 mRenderNode.offsetTopAndBottom(offset); 18414 if (isHardwareAccelerated()) { 18415 invalidateViewProperty(false, false); 18416 invalidateParentIfNeededAndWasQuickRejected(); 18417 } else { 18418 if (!matrixIsIdentity) { 18419 invalidateViewProperty(false, true); 18420 } 18421 invalidateParentIfNeeded(); 18422 } 18423 notifySubtreeAccessibilityStateChangedIfNeeded(); 18424 } 18425 } 18426 18427 /** 18428 * Offset this view's horizontal location by the specified amount of pixels. 18429 * 18430 * @param offset the number of pixels to offset the view by 18431 */ offsetLeftAndRight(int offset)18432 public void offsetLeftAndRight(int offset) { 18433 if (offset != 0) { 18434 final boolean matrixIsIdentity = hasIdentityMatrix(); 18435 if (matrixIsIdentity) { 18436 if (isHardwareAccelerated()) { 18437 invalidateViewProperty(false, false); 18438 } else { 18439 final ViewParent p = mParent; 18440 if (p != null && mAttachInfo != null) { 18441 final Rect r = mAttachInfo.mTmpInvalRect; 18442 int minLeft; 18443 int maxRight; 18444 if (offset < 0) { 18445 minLeft = mLeft + offset; 18446 maxRight = mRight; 18447 } else { 18448 minLeft = mLeft; 18449 maxRight = mRight + offset; 18450 } 18451 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 18452 p.invalidateChild(this, r); 18453 } 18454 } 18455 } else { 18456 invalidateViewProperty(false, false); 18457 } 18458 18459 mLeft += offset; 18460 mRight += offset; 18461 mRenderNode.offsetLeftAndRight(offset); 18462 if (isHardwareAccelerated()) { 18463 invalidateViewProperty(false, false); 18464 invalidateParentIfNeededAndWasQuickRejected(); 18465 } else { 18466 if (!matrixIsIdentity) { 18467 invalidateViewProperty(false, true); 18468 } 18469 invalidateParentIfNeeded(); 18470 } 18471 notifySubtreeAccessibilityStateChangedIfNeeded(); 18472 } 18473 } 18474 18475 /** 18476 * Get the LayoutParams associated with this view. All views should have 18477 * layout parameters. These supply parameters to the <i>parent</i> of this 18478 * view specifying how it should be arranged. There are many subclasses of 18479 * ViewGroup.LayoutParams, and these correspond to the different subclasses 18480 * of ViewGroup that are responsible for arranging their children. 18481 * 18482 * This method may return null if this View is not attached to a parent 18483 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 18484 * was not invoked successfully. When a View is attached to a parent 18485 * ViewGroup, this method must not return null. 18486 * 18487 * @return The LayoutParams associated with this view, or null if no 18488 * parameters have been set yet 18489 */ 18490 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()18491 public ViewGroup.LayoutParams getLayoutParams() { 18492 return mLayoutParams; 18493 } 18494 18495 /** 18496 * Set the layout parameters associated with this view. These supply 18497 * parameters to the <i>parent</i> of this view specifying how it should be 18498 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 18499 * correspond to the different subclasses of ViewGroup that are responsible 18500 * for arranging their children. 18501 * 18502 * @param params The layout parameters for this view, cannot be null 18503 */ setLayoutParams(ViewGroup.LayoutParams params)18504 public void setLayoutParams(ViewGroup.LayoutParams params) { 18505 if (params == null) { 18506 throw new NullPointerException("Layout parameters cannot be null"); 18507 } 18508 mLayoutParams = params; 18509 resolveLayoutParams(); 18510 if (mParent instanceof ViewGroup) { 18511 ((ViewGroup) mParent).onSetLayoutParams(this, params); 18512 } 18513 requestLayout(); 18514 } 18515 18516 /** 18517 * Resolve the layout parameters depending on the resolved layout direction 18518 * 18519 * @hide 18520 */ resolveLayoutParams()18521 public void resolveLayoutParams() { 18522 if (mLayoutParams != null) { 18523 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 18524 } 18525 } 18526 18527 /** 18528 * Set the scrolled position of your view. This will cause a call to 18529 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18530 * invalidated. 18531 * @param x the x position to scroll to 18532 * @param y the y position to scroll to 18533 */ scrollTo(int x, int y)18534 public void scrollTo(int x, int y) { 18535 if (mScrollX != x || mScrollY != y) { 18536 int oldX = mScrollX; 18537 int oldY = mScrollY; 18538 mScrollX = x; 18539 mScrollY = y; 18540 invalidateParentCaches(); 18541 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 18542 if (!awakenScrollBars()) { 18543 postInvalidateOnAnimation(); 18544 } 18545 } 18546 } 18547 18548 /** 18549 * Move the scrolled position of your view. This will cause a call to 18550 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18551 * invalidated. 18552 * @param x the amount of pixels to scroll by horizontally 18553 * @param y the amount of pixels to scroll by vertically 18554 */ scrollBy(int x, int y)18555 public void scrollBy(int x, int y) { 18556 scrollTo(mScrollX + x, mScrollY + y); 18557 } 18558 18559 /** 18560 * <p>Trigger the scrollbars to draw. When invoked this method starts an 18561 * animation to fade the scrollbars out after a default delay. If a subclass 18562 * provides animated scrolling, the start delay should equal the duration 18563 * of the scrolling animation.</p> 18564 * 18565 * <p>The animation starts only if at least one of the scrollbars is 18566 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 18567 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18568 * this method returns true, and false otherwise. If the animation is 18569 * started, this method calls {@link #invalidate()}; in that case the 18570 * caller should not call {@link #invalidate()}.</p> 18571 * 18572 * <p>This method should be invoked every time a subclass directly updates 18573 * the scroll parameters.</p> 18574 * 18575 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 18576 * and {@link #scrollTo(int, int)}.</p> 18577 * 18578 * @return true if the animation is played, false otherwise 18579 * 18580 * @see #awakenScrollBars(int) 18581 * @see #scrollBy(int, int) 18582 * @see #scrollTo(int, int) 18583 * @see #isHorizontalScrollBarEnabled() 18584 * @see #isVerticalScrollBarEnabled() 18585 * @see #setHorizontalScrollBarEnabled(boolean) 18586 * @see #setVerticalScrollBarEnabled(boolean) 18587 */ awakenScrollBars()18588 protected boolean awakenScrollBars() { 18589 return mScrollCache != null && 18590 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 18591 } 18592 18593 /** 18594 * Trigger the scrollbars to draw. 18595 * This method differs from awakenScrollBars() only in its default duration. 18596 * initialAwakenScrollBars() will show the scroll bars for longer than 18597 * usual to give the user more of a chance to notice them. 18598 * 18599 * @return true if the animation is played, false otherwise. 18600 */ initialAwakenScrollBars()18601 private boolean initialAwakenScrollBars() { 18602 return mScrollCache != null && 18603 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 18604 } 18605 18606 /** 18607 * <p> 18608 * Trigger the scrollbars to draw. When invoked this method starts an 18609 * animation to fade the scrollbars out after a fixed delay. If a subclass 18610 * provides animated scrolling, the start delay should equal the duration of 18611 * the scrolling animation. 18612 * </p> 18613 * 18614 * <p> 18615 * The animation starts only if at least one of the scrollbars is enabled, 18616 * as specified by {@link #isHorizontalScrollBarEnabled()} and 18617 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18618 * this method returns true, and false otherwise. If the animation is 18619 * started, this method calls {@link #invalidate()}; in that case the caller 18620 * should not call {@link #invalidate()}. 18621 * </p> 18622 * 18623 * <p> 18624 * This method should be invoked every time a subclass directly updates the 18625 * scroll parameters. 18626 * </p> 18627 * 18628 * @param startDelay the delay, in milliseconds, after which the animation 18629 * should start; when the delay is 0, the animation starts 18630 * immediately 18631 * @return true if the animation is played, false otherwise 18632 * 18633 * @see #scrollBy(int, int) 18634 * @see #scrollTo(int, int) 18635 * @see #isHorizontalScrollBarEnabled() 18636 * @see #isVerticalScrollBarEnabled() 18637 * @see #setHorizontalScrollBarEnabled(boolean) 18638 * @see #setVerticalScrollBarEnabled(boolean) 18639 */ awakenScrollBars(int startDelay)18640 protected boolean awakenScrollBars(int startDelay) { 18641 return awakenScrollBars(startDelay, true); 18642 } 18643 18644 /** 18645 * <p> 18646 * Trigger the scrollbars to draw. When invoked this method starts an 18647 * animation to fade the scrollbars out after a fixed delay. If a subclass 18648 * provides animated scrolling, the start delay should equal the duration of 18649 * the scrolling animation. 18650 * </p> 18651 * 18652 * <p> 18653 * The animation starts only if at least one of the scrollbars is enabled, 18654 * as specified by {@link #isHorizontalScrollBarEnabled()} and 18655 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18656 * this method returns true, and false otherwise. If the animation is 18657 * started, this method calls {@link #invalidate()} if the invalidate parameter 18658 * is set to true; in that case the caller 18659 * should not call {@link #invalidate()}. 18660 * </p> 18661 * 18662 * <p> 18663 * This method should be invoked every time a subclass directly updates the 18664 * scroll parameters. 18665 * </p> 18666 * 18667 * @param startDelay the delay, in milliseconds, after which the animation 18668 * should start; when the delay is 0, the animation starts 18669 * immediately 18670 * 18671 * @param invalidate Whether this method should call invalidate 18672 * 18673 * @return true if the animation is played, false otherwise 18674 * 18675 * @see #scrollBy(int, int) 18676 * @see #scrollTo(int, int) 18677 * @see #isHorizontalScrollBarEnabled() 18678 * @see #isVerticalScrollBarEnabled() 18679 * @see #setHorizontalScrollBarEnabled(boolean) 18680 * @see #setVerticalScrollBarEnabled(boolean) 18681 */ awakenScrollBars(int startDelay, boolean invalidate)18682 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 18683 final ScrollabilityCache scrollCache = mScrollCache; 18684 18685 if (scrollCache == null || !scrollCache.fadeScrollBars) { 18686 return false; 18687 } 18688 18689 if (scrollCache.scrollBar == null) { 18690 scrollCache.scrollBar = new ScrollBarDrawable(); 18691 scrollCache.scrollBar.setState(getDrawableState()); 18692 scrollCache.scrollBar.setCallback(this); 18693 } 18694 18695 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 18696 18697 if (invalidate) { 18698 // Invalidate to show the scrollbars 18699 postInvalidateOnAnimation(); 18700 } 18701 18702 if (scrollCache.state == ScrollabilityCache.OFF) { 18703 // FIXME: this is copied from WindowManagerService. 18704 // We should get this value from the system when it 18705 // is possible to do so. 18706 final int KEY_REPEAT_FIRST_DELAY = 750; 18707 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 18708 } 18709 18710 // Tell mScrollCache when we should start fading. This may 18711 // extend the fade start time if one was already scheduled 18712 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 18713 scrollCache.fadeStartTime = fadeStartTime; 18714 scrollCache.state = ScrollabilityCache.ON; 18715 18716 // Schedule our fader to run, unscheduling any old ones first 18717 if (mAttachInfo != null) { 18718 mAttachInfo.mHandler.removeCallbacks(scrollCache); 18719 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 18720 } 18721 18722 return true; 18723 } 18724 18725 return false; 18726 } 18727 18728 /** 18729 * Do not invalidate views which are not visible and which are not running an animation. They 18730 * will not get drawn and they should not set dirty flags as if they will be drawn 18731 */ skipInvalidate()18732 private boolean skipInvalidate() { 18733 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 18734 (!(mParent instanceof ViewGroup) || 18735 !((ViewGroup) mParent).isViewTransitioning(this)); 18736 } 18737 18738 /** 18739 * Mark the area defined by dirty as needing to be drawn. If the view is 18740 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18741 * point in the future. 18742 * <p> 18743 * This must be called from a UI thread. To call from a non-UI thread, call 18744 * {@link #postInvalidate()}. 18745 * <p> 18746 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 18747 * {@code dirty}. 18748 * 18749 * @param dirty the rectangle representing the bounds of the dirty region 18750 * 18751 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18752 * the importance of the dirty rectangle. In API 21 the given rectangle is 18753 * ignored entirely in favor of an internally-calculated area instead. 18754 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18755 */ 18756 @Deprecated invalidate(Rect dirty)18757 public void invalidate(Rect dirty) { 18758 final int scrollX = mScrollX; 18759 final int scrollY = mScrollY; 18760 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 18761 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 18762 } 18763 18764 /** 18765 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 18766 * coordinates of the dirty rect are relative to the view. If the view is 18767 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18768 * point in the future. 18769 * <p> 18770 * This must be called from a UI thread. To call from a non-UI thread, call 18771 * {@link #postInvalidate()}. 18772 * 18773 * @param l the left position of the dirty region 18774 * @param t the top position of the dirty region 18775 * @param r the right position of the dirty region 18776 * @param b the bottom position of the dirty region 18777 * 18778 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18779 * the importance of the dirty rectangle. In API 21 the given rectangle is 18780 * ignored entirely in favor of an internally-calculated area instead. 18781 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18782 */ 18783 @Deprecated invalidate(int l, int t, int r, int b)18784 public void invalidate(int l, int t, int r, int b) { 18785 final int scrollX = mScrollX; 18786 final int scrollY = mScrollY; 18787 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 18788 } 18789 18790 /** 18791 * Invalidate the whole view. If the view is visible, 18792 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 18793 * the future. 18794 * <p> 18795 * This must be called from a UI thread. To call from a non-UI thread, call 18796 * {@link #postInvalidate()}. 18797 */ invalidate()18798 public void invalidate() { 18799 invalidate(true); 18800 } 18801 18802 /** 18803 * This is where the invalidate() work actually happens. A full invalidate() 18804 * causes the drawing cache to be invalidated, but this function can be 18805 * called with invalidateCache set to false to skip that invalidation step 18806 * for cases that do not need it (for example, a component that remains at 18807 * the same dimensions with the same content). 18808 * 18809 * @param invalidateCache Whether the drawing cache for this view should be 18810 * invalidated as well. This is usually true for a full 18811 * invalidate, but may be set to false if the View's contents or 18812 * dimensions have not changed. 18813 * @hide 18814 */ 18815 @UnsupportedAppUsage invalidate(boolean invalidateCache)18816 public void invalidate(boolean invalidateCache) { 18817 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 18818 } 18819 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)18820 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 18821 boolean fullInvalidate) { 18822 if (mGhostView != null) { 18823 mGhostView.invalidate(true); 18824 return; 18825 } 18826 18827 if (skipInvalidate()) { 18828 return; 18829 } 18830 18831 // Reset content capture caches 18832 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 18833 mContentCaptureSessionCached = false; 18834 18835 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 18836 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 18837 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 18838 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 18839 if (fullInvalidate) { 18840 mLastIsOpaque = isOpaque(); 18841 mPrivateFlags &= ~PFLAG_DRAWN; 18842 } 18843 18844 mPrivateFlags |= PFLAG_DIRTY; 18845 18846 if (invalidateCache) { 18847 mPrivateFlags |= PFLAG_INVALIDATED; 18848 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18849 } 18850 18851 // Propagate the damage rectangle to the parent view. 18852 final AttachInfo ai = mAttachInfo; 18853 final ViewParent p = mParent; 18854 if (p != null && ai != null && l < r && t < b) { 18855 final Rect damage = ai.mTmpInvalRect; 18856 damage.set(l, t, r, b); 18857 p.invalidateChild(this, damage); 18858 } 18859 18860 // Damage the entire projection receiver, if necessary. 18861 if (mBackground != null && mBackground.isProjected()) { 18862 final View receiver = getProjectionReceiver(); 18863 if (receiver != null) { 18864 receiver.damageInParent(); 18865 } 18866 } 18867 } 18868 } 18869 18870 /** 18871 * @return this view's projection receiver, or {@code null} if none exists 18872 */ getProjectionReceiver()18873 private View getProjectionReceiver() { 18874 ViewParent p = getParent(); 18875 while (p != null && p instanceof View) { 18876 final View v = (View) p; 18877 if (v.isProjectionReceiver()) { 18878 return v; 18879 } 18880 p = p.getParent(); 18881 } 18882 18883 return null; 18884 } 18885 18886 /** 18887 * @return whether the view is a projection receiver 18888 */ isProjectionReceiver()18889 private boolean isProjectionReceiver() { 18890 return mBackground != null; 18891 } 18892 18893 /** 18894 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 18895 * set any flags or handle all of the cases handled by the default invalidation methods. 18896 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 18897 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 18898 * walk up the hierarchy, transforming the dirty rect as necessary. 18899 * 18900 * The method also handles normal invalidation logic if display list properties are not 18901 * being used in this view. The invalidateParent and forceRedraw flags are used by that 18902 * backup approach, to handle these cases used in the various property-setting methods. 18903 * 18904 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 18905 * are not being used in this view 18906 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 18907 * list properties are not being used in this view 18908 */ 18909 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)18910 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 18911 if (!isHardwareAccelerated() 18912 || !mRenderNode.hasDisplayList() 18913 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 18914 if (invalidateParent) { 18915 invalidateParentCaches(); 18916 } 18917 if (forceRedraw) { 18918 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18919 } 18920 invalidate(false); 18921 } else { 18922 damageInParent(); 18923 } 18924 } 18925 18926 /** 18927 * Tells the parent view to damage this view's bounds. 18928 * 18929 * @hide 18930 */ damageInParent()18931 protected void damageInParent() { 18932 if (mParent != null && mAttachInfo != null) { 18933 mParent.onDescendantInvalidated(this, this); 18934 } 18935 } 18936 18937 /** 18938 * Used to indicate that the parent of this view should clear its caches. This functionality 18939 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18940 * which is necessary when various parent-managed properties of the view change, such as 18941 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 18942 * clears the parent caches and does not causes an invalidate event. 18943 * 18944 * @hide 18945 */ 18946 @UnsupportedAppUsage invalidateParentCaches()18947 protected void invalidateParentCaches() { 18948 if (mParent instanceof View) { 18949 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 18950 } 18951 } 18952 18953 /** 18954 * Used to indicate that the parent of this view should be invalidated. This functionality 18955 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18956 * which is necessary when various parent-managed properties of the view change, such as 18957 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 18958 * an invalidation event to the parent. 18959 * 18960 * @hide 18961 */ 18962 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) invalidateParentIfNeeded()18963 protected void invalidateParentIfNeeded() { 18964 if (isHardwareAccelerated() && mParent instanceof View) { 18965 ((View) mParent).invalidate(true); 18966 } 18967 } 18968 18969 /** 18970 * @hide 18971 */ invalidateParentIfNeededAndWasQuickRejected()18972 protected void invalidateParentIfNeededAndWasQuickRejected() { 18973 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 18974 // View was rejected last time it was drawn by its parent; this may have changed 18975 invalidateParentIfNeeded(); 18976 } 18977 } 18978 18979 /** 18980 * Indicates whether this View is opaque. An opaque View guarantees that it will 18981 * draw all the pixels overlapping its bounds using a fully opaque color. 18982 * 18983 * Subclasses of View should override this method whenever possible to indicate 18984 * whether an instance is opaque. Opaque Views are treated in a special way by 18985 * the View hierarchy, possibly allowing it to perform optimizations during 18986 * invalidate/draw passes. 18987 * 18988 * @return True if this View is guaranteed to be fully opaque, false otherwise. 18989 */ 18990 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()18991 public boolean isOpaque() { 18992 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 18993 getFinalAlpha() >= 1.0f; 18994 } 18995 18996 /** 18997 * @hide 18998 */ 18999 @UnsupportedAppUsage computeOpaqueFlags()19000 protected void computeOpaqueFlags() { 19001 // Opaque if: 19002 // - Has a background 19003 // - Background is opaque 19004 // - Doesn't have scrollbars or scrollbars overlay 19005 19006 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 19007 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 19008 } else { 19009 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 19010 } 19011 19012 final int flags = mViewFlags; 19013 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 19014 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 19015 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 19016 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 19017 } else { 19018 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 19019 } 19020 } 19021 19022 /** 19023 * @hide 19024 */ hasOpaqueScrollbars()19025 protected boolean hasOpaqueScrollbars() { 19026 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 19027 } 19028 19029 /** 19030 * @return A handler associated with the thread running the View. This 19031 * handler can be used to pump events in the UI events queue. 19032 */ getHandler()19033 public Handler getHandler() { 19034 final AttachInfo attachInfo = mAttachInfo; 19035 if (attachInfo != null) { 19036 return attachInfo.mHandler; 19037 } 19038 return null; 19039 } 19040 19041 /** 19042 * Returns the queue of runnable for this view. 19043 * 19044 * @return the queue of runnables for this view 19045 */ getRunQueue()19046 private HandlerActionQueue getRunQueue() { 19047 if (mRunQueue == null) { 19048 mRunQueue = new HandlerActionQueue(); 19049 } 19050 return mRunQueue; 19051 } 19052 19053 /** 19054 * Gets the view root associated with the View. 19055 * @return The view root, or null if none. 19056 * @hide 19057 */ 19058 @UnsupportedAppUsage getViewRootImpl()19059 public ViewRootImpl getViewRootImpl() { 19060 if (mAttachInfo != null) { 19061 return mAttachInfo.mViewRootImpl; 19062 } 19063 return null; 19064 } 19065 19066 /** 19067 * @hide 19068 */ 19069 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getThreadedRenderer()19070 public ThreadedRenderer getThreadedRenderer() { 19071 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 19072 } 19073 19074 /** 19075 * <p>Causes the Runnable to be added to the message queue. 19076 * The runnable will be run on the user interface thread.</p> 19077 * 19078 * @param action The Runnable that will be executed. 19079 * 19080 * @return Returns true if the Runnable was successfully placed in to the 19081 * message queue. Returns false on failure, usually because the 19082 * looper processing the message queue is exiting. 19083 * 19084 * @see #postDelayed 19085 * @see #removeCallbacks 19086 */ post(Runnable action)19087 public boolean post(Runnable action) { 19088 final AttachInfo attachInfo = mAttachInfo; 19089 if (attachInfo != null) { 19090 return attachInfo.mHandler.post(action); 19091 } 19092 19093 // Postpone the runnable until we know on which thread it needs to run. 19094 // Assume that the runnable will be successfully placed after attach. 19095 getRunQueue().post(action); 19096 return true; 19097 } 19098 19099 /** 19100 * <p>Causes the Runnable to be added to the message queue, to be run 19101 * after the specified amount of time elapses. 19102 * The runnable will be run on the user interface thread.</p> 19103 * 19104 * @param action The Runnable that will be executed. 19105 * @param delayMillis The delay (in milliseconds) until the Runnable 19106 * will be executed. 19107 * 19108 * @return true if the Runnable was successfully placed in to the 19109 * message queue. Returns false on failure, usually because the 19110 * looper processing the message queue is exiting. Note that a 19111 * result of true does not mean the Runnable will be processed -- 19112 * if the looper is quit before the delivery time of the message 19113 * occurs then the message will be dropped. 19114 * 19115 * @see #post 19116 * @see #removeCallbacks 19117 */ postDelayed(Runnable action, long delayMillis)19118 public boolean postDelayed(Runnable action, long delayMillis) { 19119 final AttachInfo attachInfo = mAttachInfo; 19120 if (attachInfo != null) { 19121 return attachInfo.mHandler.postDelayed(action, delayMillis); 19122 } 19123 19124 // Postpone the runnable until we know on which thread it needs to run. 19125 // Assume that the runnable will be successfully placed after attach. 19126 getRunQueue().postDelayed(action, delayMillis); 19127 return true; 19128 } 19129 19130 /** 19131 * <p>Causes the Runnable to execute on the next animation time step. 19132 * The runnable will be run on the user interface thread.</p> 19133 * 19134 * @param action The Runnable that will be executed. 19135 * 19136 * @see #postOnAnimationDelayed 19137 * @see #removeCallbacks 19138 */ postOnAnimation(Runnable action)19139 public void postOnAnimation(Runnable action) { 19140 final AttachInfo attachInfo = mAttachInfo; 19141 if (attachInfo != null) { 19142 attachInfo.mViewRootImpl.mChoreographer.postCallback( 19143 Choreographer.CALLBACK_ANIMATION, action, null); 19144 } else { 19145 // Postpone the runnable until we know 19146 // on which thread it needs to run. 19147 getRunQueue().post(action); 19148 } 19149 } 19150 19151 /** 19152 * <p>Causes the Runnable to execute on the next animation time step, 19153 * after the specified amount of time elapses. 19154 * The runnable will be run on the user interface thread.</p> 19155 * 19156 * @param action The Runnable that will be executed. 19157 * @param delayMillis The delay (in milliseconds) until the Runnable 19158 * will be executed. 19159 * 19160 * @see #postOnAnimation 19161 * @see #removeCallbacks 19162 */ postOnAnimationDelayed(Runnable action, long delayMillis)19163 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 19164 final AttachInfo attachInfo = mAttachInfo; 19165 if (attachInfo != null) { 19166 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19167 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 19168 } else { 19169 // Postpone the runnable until we know 19170 // on which thread it needs to run. 19171 getRunQueue().postDelayed(action, delayMillis); 19172 } 19173 } 19174 19175 /** 19176 * <p>Removes the specified Runnable from the message queue.</p> 19177 * 19178 * @param action The Runnable to remove from the message handling queue 19179 * 19180 * @return true if this view could ask the Handler to remove the Runnable, 19181 * false otherwise. When the returned value is true, the Runnable 19182 * may or may not have been actually removed from the message queue 19183 * (for instance, if the Runnable was not in the queue already.) 19184 * 19185 * @see #post 19186 * @see #postDelayed 19187 * @see #postOnAnimation 19188 * @see #postOnAnimationDelayed 19189 */ removeCallbacks(Runnable action)19190 public boolean removeCallbacks(Runnable action) { 19191 if (action != null) { 19192 final AttachInfo attachInfo = mAttachInfo; 19193 if (attachInfo != null) { 19194 attachInfo.mHandler.removeCallbacks(action); 19195 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19196 Choreographer.CALLBACK_ANIMATION, action, null); 19197 } 19198 getRunQueue().removeCallbacks(action); 19199 } 19200 return true; 19201 } 19202 19203 /** 19204 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 19205 * Use this to invalidate the View from a non-UI thread.</p> 19206 * 19207 * <p>This method can be invoked from outside of the UI thread 19208 * only when this View is attached to a window.</p> 19209 * 19210 * @see #invalidate() 19211 * @see #postInvalidateDelayed(long) 19212 */ postInvalidate()19213 public void postInvalidate() { 19214 postInvalidateDelayed(0); 19215 } 19216 19217 /** 19218 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 19219 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 19220 * 19221 * <p>This method can be invoked from outside of the UI thread 19222 * only when this View is attached to a window.</p> 19223 * 19224 * @param left The left coordinate of the rectangle to invalidate. 19225 * @param top The top coordinate of the rectangle to invalidate. 19226 * @param right The right coordinate of the rectangle to invalidate. 19227 * @param bottom The bottom coordinate of the rectangle to invalidate. 19228 * 19229 * @see #invalidate(int, int, int, int) 19230 * @see #invalidate(Rect) 19231 * @see #postInvalidateDelayed(long, int, int, int, int) 19232 */ postInvalidate(int left, int top, int right, int bottom)19233 public void postInvalidate(int left, int top, int right, int bottom) { 19234 postInvalidateDelayed(0, left, top, right, bottom); 19235 } 19236 19237 /** 19238 * <p>Cause an invalidate to happen on a subsequent cycle through the event 19239 * loop. Waits for the specified amount of time.</p> 19240 * 19241 * <p>This method can be invoked from outside of the UI thread 19242 * only when this View is attached to a window.</p> 19243 * 19244 * @param delayMilliseconds the duration in milliseconds to delay the 19245 * invalidation by 19246 * 19247 * @see #invalidate() 19248 * @see #postInvalidate() 19249 */ postInvalidateDelayed(long delayMilliseconds)19250 public void postInvalidateDelayed(long delayMilliseconds) { 19251 // We try only with the AttachInfo because there's no point in invalidating 19252 // if we are not attached to our window 19253 final AttachInfo attachInfo = mAttachInfo; 19254 if (attachInfo != null) { 19255 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 19256 } 19257 } 19258 19259 /** 19260 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 19261 * through the event loop. Waits for the specified amount of time.</p> 19262 * 19263 * <p>This method can be invoked from outside of the UI thread 19264 * only when this View is attached to a window.</p> 19265 * 19266 * @param delayMilliseconds the duration in milliseconds to delay the 19267 * invalidation by 19268 * @param left The left coordinate of the rectangle to invalidate. 19269 * @param top The top coordinate of the rectangle to invalidate. 19270 * @param right The right coordinate of the rectangle to invalidate. 19271 * @param bottom The bottom coordinate of the rectangle to invalidate. 19272 * 19273 * @see #invalidate(int, int, int, int) 19274 * @see #invalidate(Rect) 19275 * @see #postInvalidate(int, int, int, int) 19276 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)19277 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 19278 int right, int bottom) { 19279 19280 // We try only with the AttachInfo because there's no point in invalidating 19281 // if we are not attached to our window 19282 final AttachInfo attachInfo = mAttachInfo; 19283 if (attachInfo != null) { 19284 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19285 info.target = this; 19286 info.left = left; 19287 info.top = top; 19288 info.right = right; 19289 info.bottom = bottom; 19290 19291 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 19292 } 19293 } 19294 19295 /** 19296 * <p>Cause an invalidate to happen on the next animation time step, typically the 19297 * next display frame.</p> 19298 * 19299 * <p>This method can be invoked from outside of the UI thread 19300 * only when this View is attached to a window.</p> 19301 * 19302 * @see #invalidate() 19303 */ postInvalidateOnAnimation()19304 public void postInvalidateOnAnimation() { 19305 // We try only with the AttachInfo because there's no point in invalidating 19306 // if we are not attached to our window 19307 final AttachInfo attachInfo = mAttachInfo; 19308 if (attachInfo != null) { 19309 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 19310 } 19311 } 19312 19313 /** 19314 * <p>Cause an invalidate of the specified area to happen on the next animation 19315 * time step, typically the next display frame.</p> 19316 * 19317 * <p>This method can be invoked from outside of the UI thread 19318 * only when this View is attached to a window.</p> 19319 * 19320 * @param left The left coordinate of the rectangle to invalidate. 19321 * @param top The top coordinate of the rectangle to invalidate. 19322 * @param right The right coordinate of the rectangle to invalidate. 19323 * @param bottom The bottom coordinate of the rectangle to invalidate. 19324 * 19325 * @see #invalidate(int, int, int, int) 19326 * @see #invalidate(Rect) 19327 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)19328 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 19329 // We try only with the AttachInfo because there's no point in invalidating 19330 // if we are not attached to our window 19331 final AttachInfo attachInfo = mAttachInfo; 19332 if (attachInfo != null) { 19333 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19334 info.target = this; 19335 info.left = left; 19336 info.top = top; 19337 info.right = right; 19338 info.bottom = bottom; 19339 19340 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 19341 } 19342 } 19343 19344 /** 19345 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 19346 * This event is sent at most once every 19347 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 19348 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)19349 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 19350 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 19351 AccessibilityEvent event = 19352 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 19353 event.setScrollDeltaX(dx); 19354 event.setScrollDeltaY(dy); 19355 sendAccessibilityEventUnchecked(event); 19356 } 19357 } 19358 19359 /** 19360 * Called by a parent to request that a child update its values for mScrollX 19361 * and mScrollY if necessary. This will typically be done if the child is 19362 * animating a scroll using a {@link android.widget.Scroller Scroller} 19363 * object. 19364 */ computeScroll()19365 public void computeScroll() { 19366 } 19367 19368 /** 19369 * <p>Indicate whether the horizontal edges are faded when the view is 19370 * scrolled horizontally.</p> 19371 * 19372 * @return true if the horizontal edges should are faded on scroll, false 19373 * otherwise 19374 * 19375 * @see #setHorizontalFadingEdgeEnabled(boolean) 19376 * 19377 * @attr ref android.R.styleable#View_requiresFadingEdge 19378 */ isHorizontalFadingEdgeEnabled()19379 public boolean isHorizontalFadingEdgeEnabled() { 19380 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 19381 } 19382 19383 /** 19384 * <p>Define whether the horizontal edges should be faded when this view 19385 * is scrolled horizontally.</p> 19386 * 19387 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 19388 * be faded when the view is scrolled 19389 * horizontally 19390 * 19391 * @see #isHorizontalFadingEdgeEnabled() 19392 * 19393 * @attr ref android.R.styleable#View_requiresFadingEdge 19394 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)19395 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 19396 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 19397 if (horizontalFadingEdgeEnabled) { 19398 initScrollCache(); 19399 } 19400 19401 mViewFlags ^= FADING_EDGE_HORIZONTAL; 19402 } 19403 } 19404 19405 /** 19406 * <p>Indicate whether the vertical edges are faded when the view is 19407 * scrolled horizontally.</p> 19408 * 19409 * @return true if the vertical edges should are faded on scroll, false 19410 * otherwise 19411 * 19412 * @see #setVerticalFadingEdgeEnabled(boolean) 19413 * 19414 * @attr ref android.R.styleable#View_requiresFadingEdge 19415 */ isVerticalFadingEdgeEnabled()19416 public boolean isVerticalFadingEdgeEnabled() { 19417 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 19418 } 19419 19420 /** 19421 * <p>Define whether the vertical edges should be faded when this view 19422 * is scrolled vertically.</p> 19423 * 19424 * @param verticalFadingEdgeEnabled true if the vertical edges should 19425 * be faded when the view is scrolled 19426 * vertically 19427 * 19428 * @see #isVerticalFadingEdgeEnabled() 19429 * 19430 * @attr ref android.R.styleable#View_requiresFadingEdge 19431 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)19432 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 19433 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 19434 if (verticalFadingEdgeEnabled) { 19435 initScrollCache(); 19436 } 19437 19438 mViewFlags ^= FADING_EDGE_VERTICAL; 19439 } 19440 } 19441 19442 /** 19443 * Get the fading edge flags, used for inspection. 19444 * 19445 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 19446 * or {@link #FADING_EDGE_HORIZONTAL} 19447 * @hide 19448 */ 19449 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 19450 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 19451 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 19452 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 19453 }) getFadingEdge()19454 public int getFadingEdge() { 19455 return mViewFlags & FADING_EDGE_MASK; 19456 } 19457 19458 /** 19459 * Get the fading edge length, used for inspection 19460 * 19461 * @return The fading edge length or 0 19462 * @hide 19463 */ 19464 @InspectableProperty getFadingEdgeLength()19465 public int getFadingEdgeLength() { 19466 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 19467 return mScrollCache.fadingEdgeLength; 19468 } 19469 return 0; 19470 } 19471 19472 /** 19473 * Returns the strength, or intensity, of the top faded edge. The strength is 19474 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19475 * returns 0.0 or 1.0 but no value in between. 19476 * 19477 * Subclasses should override this method to provide a smoother fade transition 19478 * when scrolling occurs. 19479 * 19480 * @return the intensity of the top fade as a float between 0.0f and 1.0f 19481 */ getTopFadingEdgeStrength()19482 protected float getTopFadingEdgeStrength() { 19483 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 19484 } 19485 19486 /** 19487 * Returns the strength, or intensity, of the bottom faded edge. The strength is 19488 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19489 * returns 0.0 or 1.0 but no value in between. 19490 * 19491 * Subclasses should override this method to provide a smoother fade transition 19492 * when scrolling occurs. 19493 * 19494 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 19495 */ getBottomFadingEdgeStrength()19496 protected float getBottomFadingEdgeStrength() { 19497 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 19498 computeVerticalScrollRange() ? 1.0f : 0.0f; 19499 } 19500 19501 /** 19502 * Returns the strength, or intensity, of the left faded edge. The strength is 19503 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19504 * returns 0.0 or 1.0 but no value in between. 19505 * 19506 * Subclasses should override this method to provide a smoother fade transition 19507 * when scrolling occurs. 19508 * 19509 * @return the intensity of the left fade as a float between 0.0f and 1.0f 19510 */ getLeftFadingEdgeStrength()19511 protected float getLeftFadingEdgeStrength() { 19512 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 19513 } 19514 19515 /** 19516 * Returns the strength, or intensity, of the right faded edge. The strength is 19517 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19518 * returns 0.0 or 1.0 but no value in between. 19519 * 19520 * Subclasses should override this method to provide a smoother fade transition 19521 * when scrolling occurs. 19522 * 19523 * @return the intensity of the right fade as a float between 0.0f and 1.0f 19524 */ getRightFadingEdgeStrength()19525 protected float getRightFadingEdgeStrength() { 19526 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 19527 computeHorizontalScrollRange() ? 1.0f : 0.0f; 19528 } 19529 19530 /** 19531 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 19532 * scrollbar is not drawn by default.</p> 19533 * 19534 * @return true if the horizontal scrollbar should be painted, false 19535 * otherwise 19536 * 19537 * @see #setHorizontalScrollBarEnabled(boolean) 19538 */ isHorizontalScrollBarEnabled()19539 public boolean isHorizontalScrollBarEnabled() { 19540 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 19541 } 19542 19543 /** 19544 * <p>Define whether the horizontal scrollbar should be drawn or not. The 19545 * scrollbar is not drawn by default.</p> 19546 * 19547 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 19548 * be painted 19549 * 19550 * @see #isHorizontalScrollBarEnabled() 19551 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)19552 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 19553 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 19554 mViewFlags ^= SCROLLBARS_HORIZONTAL; 19555 computeOpaqueFlags(); 19556 resolvePadding(); 19557 } 19558 } 19559 19560 /** 19561 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 19562 * scrollbar is not drawn by default.</p> 19563 * 19564 * @return true if the vertical scrollbar should be painted, false 19565 * otherwise 19566 * 19567 * @see #setVerticalScrollBarEnabled(boolean) 19568 */ isVerticalScrollBarEnabled()19569 public boolean isVerticalScrollBarEnabled() { 19570 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 19571 } 19572 19573 /** 19574 * <p>Define whether the vertical scrollbar should be drawn or not. The 19575 * scrollbar is not drawn by default.</p> 19576 * 19577 * @param verticalScrollBarEnabled true if the vertical scrollbar should 19578 * be painted 19579 * 19580 * @see #isVerticalScrollBarEnabled() 19581 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)19582 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 19583 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 19584 mViewFlags ^= SCROLLBARS_VERTICAL; 19585 computeOpaqueFlags(); 19586 resolvePadding(); 19587 } 19588 } 19589 19590 /** 19591 * @hide 19592 */ 19593 @UnsupportedAppUsage recomputePadding()19594 protected void recomputePadding() { 19595 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 19596 } 19597 19598 /** 19599 * Define whether scrollbars will fade when the view is not scrolling. 19600 * 19601 * @param fadeScrollbars whether to enable fading 19602 * 19603 * @attr ref android.R.styleable#View_fadeScrollbars 19604 */ setScrollbarFadingEnabled(boolean fadeScrollbars)19605 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 19606 initScrollCache(); 19607 final ScrollabilityCache scrollabilityCache = mScrollCache; 19608 scrollabilityCache.fadeScrollBars = fadeScrollbars; 19609 if (fadeScrollbars) { 19610 scrollabilityCache.state = ScrollabilityCache.OFF; 19611 } else { 19612 scrollabilityCache.state = ScrollabilityCache.ON; 19613 } 19614 } 19615 19616 /** 19617 * 19618 * Returns true if scrollbars will fade when this view is not scrolling 19619 * 19620 * @return true if scrollbar fading is enabled 19621 * 19622 * @attr ref android.R.styleable#View_fadeScrollbars 19623 */ isScrollbarFadingEnabled()19624 public boolean isScrollbarFadingEnabled() { 19625 return mScrollCache != null && mScrollCache.fadeScrollBars; 19626 } 19627 19628 /** 19629 * 19630 * Returns the delay before scrollbars fade. 19631 * 19632 * @return the delay before scrollbars fade 19633 * 19634 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 19635 */ 19636 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()19637 public int getScrollBarDefaultDelayBeforeFade() { 19638 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 19639 mScrollCache.scrollBarDefaultDelayBeforeFade; 19640 } 19641 19642 /** 19643 * Define the delay before scrollbars fade. 19644 * 19645 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 19646 * 19647 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 19648 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)19649 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 19650 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 19651 } 19652 19653 /** 19654 * 19655 * Returns the scrollbar fade duration. 19656 * 19657 * @return the scrollbar fade duration, in milliseconds 19658 * 19659 * @attr ref android.R.styleable#View_scrollbarFadeDuration 19660 */ 19661 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()19662 public int getScrollBarFadeDuration() { 19663 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 19664 mScrollCache.scrollBarFadeDuration; 19665 } 19666 19667 /** 19668 * Define the scrollbar fade duration. 19669 * 19670 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 19671 * 19672 * @attr ref android.R.styleable#View_scrollbarFadeDuration 19673 */ setScrollBarFadeDuration(int scrollBarFadeDuration)19674 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 19675 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 19676 } 19677 19678 /** 19679 * 19680 * Returns the scrollbar size. 19681 * 19682 * @return the scrollbar size 19683 * 19684 * @attr ref android.R.styleable#View_scrollbarSize 19685 */ 19686 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()19687 public int getScrollBarSize() { 19688 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 19689 mScrollCache.scrollBarSize; 19690 } 19691 19692 /** 19693 * Define the scrollbar size. 19694 * 19695 * @param scrollBarSize - the scrollbar size 19696 * 19697 * @attr ref android.R.styleable#View_scrollbarSize 19698 */ setScrollBarSize(int scrollBarSize)19699 public void setScrollBarSize(int scrollBarSize) { 19700 getScrollCache().scrollBarSize = scrollBarSize; 19701 } 19702 19703 /** 19704 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 19705 * inset. When inset, they add to the padding of the view. And the scrollbars 19706 * can be drawn inside the padding area or on the edge of the view. For example, 19707 * if a view has a background drawable and you want to draw the scrollbars 19708 * inside the padding specified by the drawable, you can use 19709 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 19710 * appear at the edge of the view, ignoring the padding, then you can use 19711 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 19712 * @param style the style of the scrollbars. Should be one of 19713 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 19714 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 19715 * @see #SCROLLBARS_INSIDE_OVERLAY 19716 * @see #SCROLLBARS_INSIDE_INSET 19717 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19718 * @see #SCROLLBARS_OUTSIDE_INSET 19719 * 19720 * @attr ref android.R.styleable#View_scrollbarStyle 19721 */ setScrollBarStyle(@crollBarStyle int style)19722 public void setScrollBarStyle(@ScrollBarStyle int style) { 19723 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 19724 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 19725 computeOpaqueFlags(); 19726 resolvePadding(); 19727 } 19728 } 19729 19730 /** 19731 * <p>Returns the current scrollbar style.</p> 19732 * @return the current scrollbar style 19733 * @see #SCROLLBARS_INSIDE_OVERLAY 19734 * @see #SCROLLBARS_INSIDE_INSET 19735 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19736 * @see #SCROLLBARS_OUTSIDE_INSET 19737 * 19738 * @attr ref android.R.styleable#View_scrollbarStyle 19739 */ 19740 @ViewDebug.ExportedProperty(mapping = { 19741 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 19742 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 19743 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 19744 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 19745 }) 19746 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 19747 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 19748 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 19749 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 19750 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 19751 }) 19752 @ScrollBarStyle getScrollBarStyle()19753 public int getScrollBarStyle() { 19754 return mViewFlags & SCROLLBARS_STYLE_MASK; 19755 } 19756 19757 /** 19758 * <p>Compute the horizontal range that the horizontal scrollbar 19759 * represents.</p> 19760 * 19761 * <p>The range is expressed in arbitrary units that must be the same as the 19762 * units used by {@link #computeHorizontalScrollExtent()} and 19763 * {@link #computeHorizontalScrollOffset()}.</p> 19764 * 19765 * <p>The default range is the drawing width of this view.</p> 19766 * 19767 * @return the total horizontal range represented by the horizontal 19768 * scrollbar 19769 * 19770 * @see #computeHorizontalScrollExtent() 19771 * @see #computeHorizontalScrollOffset() 19772 */ computeHorizontalScrollRange()19773 protected int computeHorizontalScrollRange() { 19774 return getWidth(); 19775 } 19776 19777 /** 19778 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 19779 * within the horizontal range. This value is used to compute the position 19780 * of the thumb within the scrollbar's track.</p> 19781 * 19782 * <p>The range is expressed in arbitrary units that must be the same as the 19783 * units used by {@link #computeHorizontalScrollRange()} and 19784 * {@link #computeHorizontalScrollExtent()}.</p> 19785 * 19786 * <p>The default offset is the scroll offset of this view.</p> 19787 * 19788 * @return the horizontal offset of the scrollbar's thumb 19789 * 19790 * @see #computeHorizontalScrollRange() 19791 * @see #computeHorizontalScrollExtent() 19792 */ computeHorizontalScrollOffset()19793 protected int computeHorizontalScrollOffset() { 19794 return mScrollX; 19795 } 19796 19797 /** 19798 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 19799 * within the horizontal range. This value is used to compute the length 19800 * of the thumb within the scrollbar's track.</p> 19801 * 19802 * <p>The range is expressed in arbitrary units that must be the same as the 19803 * units used by {@link #computeHorizontalScrollRange()} and 19804 * {@link #computeHorizontalScrollOffset()}.</p> 19805 * 19806 * <p>The default extent is the drawing width of this view.</p> 19807 * 19808 * @return the horizontal extent of the scrollbar's thumb 19809 * 19810 * @see #computeHorizontalScrollRange() 19811 * @see #computeHorizontalScrollOffset() 19812 */ computeHorizontalScrollExtent()19813 protected int computeHorizontalScrollExtent() { 19814 return getWidth(); 19815 } 19816 19817 /** 19818 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 19819 * 19820 * <p>The range is expressed in arbitrary units that must be the same as the 19821 * units used by {@link #computeVerticalScrollExtent()} and 19822 * {@link #computeVerticalScrollOffset()}.</p> 19823 * 19824 * @return the total vertical range represented by the vertical scrollbar 19825 * 19826 * <p>The default range is the drawing height of this view.</p> 19827 * 19828 * @see #computeVerticalScrollExtent() 19829 * @see #computeVerticalScrollOffset() 19830 */ computeVerticalScrollRange()19831 protected int computeVerticalScrollRange() { 19832 return getHeight(); 19833 } 19834 19835 /** 19836 * <p>Compute the vertical offset of the vertical scrollbar's thumb 19837 * within the horizontal range. This value is used to compute the position 19838 * of the thumb within the scrollbar's track.</p> 19839 * 19840 * <p>The range is expressed in arbitrary units that must be the same as the 19841 * units used by {@link #computeVerticalScrollRange()} and 19842 * {@link #computeVerticalScrollExtent()}.</p> 19843 * 19844 * <p>The default offset is the scroll offset of this view.</p> 19845 * 19846 * @return the vertical offset of the scrollbar's thumb 19847 * 19848 * @see #computeVerticalScrollRange() 19849 * @see #computeVerticalScrollExtent() 19850 */ computeVerticalScrollOffset()19851 protected int computeVerticalScrollOffset() { 19852 return mScrollY; 19853 } 19854 19855 /** 19856 * <p>Compute the vertical extent of the vertical scrollbar's thumb 19857 * within the vertical range. This value is used to compute the length 19858 * of the thumb within the scrollbar's track.</p> 19859 * 19860 * <p>The range is expressed in arbitrary units that must be the same as the 19861 * units used by {@link #computeVerticalScrollRange()} and 19862 * {@link #computeVerticalScrollOffset()}.</p> 19863 * 19864 * <p>The default extent is the drawing height of this view.</p> 19865 * 19866 * @return the vertical extent of the scrollbar's thumb 19867 * 19868 * @see #computeVerticalScrollRange() 19869 * @see #computeVerticalScrollOffset() 19870 */ computeVerticalScrollExtent()19871 protected int computeVerticalScrollExtent() { 19872 return getHeight(); 19873 } 19874 19875 /** 19876 * Check if this view can be scrolled horizontally in a certain direction. 19877 * 19878 * @param direction Negative to check scrolling left, positive to check scrolling right. 19879 * @return true if this view can be scrolled in the specified direction, false otherwise. 19880 */ canScrollHorizontally(int direction)19881 public boolean canScrollHorizontally(int direction) { 19882 final int offset = computeHorizontalScrollOffset(); 19883 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 19884 if (range == 0) return false; 19885 if (direction < 0) { 19886 return offset > 0; 19887 } else { 19888 return offset < range - 1; 19889 } 19890 } 19891 19892 /** 19893 * Check if this view can be scrolled vertically in a certain direction. 19894 * 19895 * @param direction Negative to check scrolling up, positive to check scrolling down. 19896 * @return true if this view can be scrolled in the specified direction, false otherwise. 19897 */ canScrollVertically(int direction)19898 public boolean canScrollVertically(int direction) { 19899 final int offset = computeVerticalScrollOffset(); 19900 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 19901 if (range == 0) return false; 19902 if (direction < 0) { 19903 return offset > 0; 19904 } else { 19905 return offset < range - 1; 19906 } 19907 } 19908 getScrollIndicatorBounds(@onNull Rect out)19909 void getScrollIndicatorBounds(@NonNull Rect out) { 19910 out.left = mScrollX; 19911 out.right = mScrollX + mRight - mLeft; 19912 out.top = mScrollY; 19913 out.bottom = mScrollY + mBottom - mTop; 19914 } 19915 onDrawScrollIndicators(Canvas c)19916 private void onDrawScrollIndicators(Canvas c) { 19917 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 19918 // No scroll indicators enabled. 19919 return; 19920 } 19921 19922 final Drawable dr = mScrollIndicatorDrawable; 19923 if (dr == null) { 19924 // Scroll indicators aren't supported here. 19925 return; 19926 } 19927 19928 if (mAttachInfo == null) { 19929 // View is not attached. 19930 return; 19931 } 19932 19933 final int h = dr.getIntrinsicHeight(); 19934 final int w = dr.getIntrinsicWidth(); 19935 final Rect rect = mAttachInfo.mTmpInvalRect; 19936 getScrollIndicatorBounds(rect); 19937 19938 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 19939 final boolean canScrollUp = canScrollVertically(-1); 19940 if (canScrollUp) { 19941 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 19942 dr.draw(c); 19943 } 19944 } 19945 19946 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 19947 final boolean canScrollDown = canScrollVertically(1); 19948 if (canScrollDown) { 19949 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 19950 dr.draw(c); 19951 } 19952 } 19953 19954 final int leftRtl; 19955 final int rightRtl; 19956 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 19957 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 19958 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 19959 } else { 19960 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 19961 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 19962 } 19963 19964 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 19965 if ((mPrivateFlags3 & leftMask) != 0) { 19966 final boolean canScrollLeft = canScrollHorizontally(-1); 19967 if (canScrollLeft) { 19968 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 19969 dr.draw(c); 19970 } 19971 } 19972 19973 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 19974 if ((mPrivateFlags3 & rightMask) != 0) { 19975 final boolean canScrollRight = canScrollHorizontally(1); 19976 if (canScrollRight) { 19977 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 19978 dr.draw(c); 19979 } 19980 } 19981 } 19982 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19983 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 19984 @Nullable Rect touchBounds) { 19985 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19986 if (bounds == null) { 19987 return; 19988 } 19989 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19990 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 19991 && !isVerticalScrollBarHidden(); 19992 final int size = getHorizontalScrollbarHeight(); 19993 final int verticalScrollBarGap = drawVerticalScrollBar ? 19994 getVerticalScrollbarWidth() : 0; 19995 final int width = mRight - mLeft; 19996 final int height = mBottom - mTop; 19997 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 19998 bounds.left = mScrollX + (mPaddingLeft & inside); 19999 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 20000 bounds.bottom = bounds.top + size; 20001 20002 if (touchBounds == null) { 20003 return; 20004 } 20005 if (touchBounds != bounds) { 20006 touchBounds.set(bounds); 20007 } 20008 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 20009 if (touchBounds.height() < minTouchTarget) { 20010 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 20011 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 20012 touchBounds.top = touchBounds.bottom - minTouchTarget; 20013 } 20014 if (touchBounds.width() < minTouchTarget) { 20015 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 20016 touchBounds.left -= adjust; 20017 touchBounds.right = touchBounds.left + minTouchTarget; 20018 } 20019 } 20020 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)20021 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 20022 if (mRoundScrollbarRenderer == null) { 20023 getStraightVerticalScrollBarBounds(bounds, touchBounds); 20024 } else { 20025 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 20026 } 20027 } 20028 getRoundVerticalScrollBarBounds(Rect bounds)20029 private void getRoundVerticalScrollBarBounds(Rect bounds) { 20030 final int width = mRight - mLeft; 20031 final int height = mBottom - mTop; 20032 // Do not take padding into account as we always want the scrollbars 20033 // to hug the screen for round wearable devices. 20034 bounds.left = mScrollX; 20035 bounds.top = mScrollY; 20036 bounds.right = bounds.left + width; 20037 bounds.bottom = mScrollY + height; 20038 } 20039 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)20040 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 20041 @Nullable Rect touchBounds) { 20042 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 20043 if (bounds == null) { 20044 return; 20045 } 20046 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 20047 final int size = getVerticalScrollbarWidth(); 20048 int verticalScrollbarPosition = mVerticalScrollbarPosition; 20049 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 20050 verticalScrollbarPosition = isLayoutRtl() ? 20051 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 20052 } 20053 final int width = mRight - mLeft; 20054 final int height = mBottom - mTop; 20055 switch (verticalScrollbarPosition) { 20056 default: 20057 case SCROLLBAR_POSITION_RIGHT: 20058 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 20059 break; 20060 case SCROLLBAR_POSITION_LEFT: 20061 bounds.left = mScrollX + (mUserPaddingLeft & inside); 20062 break; 20063 } 20064 bounds.top = mScrollY + (mPaddingTop & inside); 20065 bounds.right = bounds.left + size; 20066 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 20067 20068 if (touchBounds == null) { 20069 return; 20070 } 20071 if (touchBounds != bounds) { 20072 touchBounds.set(bounds); 20073 } 20074 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 20075 if (touchBounds.width() < minTouchTarget) { 20076 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 20077 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 20078 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 20079 touchBounds.left = touchBounds.right - minTouchTarget; 20080 } else { 20081 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 20082 touchBounds.right = touchBounds.left + minTouchTarget; 20083 } 20084 } 20085 if (touchBounds.height() < minTouchTarget) { 20086 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 20087 touchBounds.top -= adjust; 20088 touchBounds.bottom = touchBounds.top + minTouchTarget; 20089 } 20090 } 20091 20092 /** 20093 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 20094 * scrollbars are painted only if they have been awakened first.</p> 20095 * 20096 * @param canvas the canvas on which to draw the scrollbars 20097 * 20098 * @see #awakenScrollBars(int) 20099 */ onDrawScrollBars(Canvas canvas)20100 protected final void onDrawScrollBars(Canvas canvas) { 20101 // scrollbars are drawn only when the animation is running 20102 final ScrollabilityCache cache = mScrollCache; 20103 20104 if (cache != null) { 20105 20106 int state = cache.state; 20107 20108 if (state == ScrollabilityCache.OFF) { 20109 return; 20110 } 20111 20112 boolean invalidate = false; 20113 20114 if (state == ScrollabilityCache.FADING) { 20115 // We're fading -- get our fade interpolation 20116 if (cache.interpolatorValues == null) { 20117 cache.interpolatorValues = new float[1]; 20118 } 20119 20120 float[] values = cache.interpolatorValues; 20121 20122 // Stops the animation if we're done 20123 if (cache.scrollBarInterpolator.timeToValues(values) == 20124 Interpolator.Result.FREEZE_END) { 20125 cache.state = ScrollabilityCache.OFF; 20126 } else { 20127 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 20128 } 20129 20130 // This will make the scroll bars inval themselves after 20131 // drawing. We only want this when we're fading so that 20132 // we prevent excessive redraws 20133 invalidate = true; 20134 } else { 20135 // We're just on -- but we may have been fading before so 20136 // reset alpha 20137 cache.scrollBar.mutate().setAlpha(255); 20138 } 20139 20140 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 20141 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 20142 && !isVerticalScrollBarHidden(); 20143 20144 // Fork out the scroll bar drawing for round wearable devices. 20145 if (mRoundScrollbarRenderer != null) { 20146 if (drawVerticalScrollBar) { 20147 final Rect bounds = cache.mScrollBarBounds; 20148 getVerticalScrollBarBounds(bounds, null); 20149 mRoundScrollbarRenderer.drawRoundScrollbars( 20150 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 20151 if (invalidate) { 20152 invalidate(); 20153 } 20154 } 20155 // Do not draw horizontal scroll bars for round wearable devices. 20156 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 20157 final ScrollBarDrawable scrollBar = cache.scrollBar; 20158 20159 if (drawHorizontalScrollBar) { 20160 scrollBar.setParameters(computeHorizontalScrollRange(), 20161 computeHorizontalScrollOffset(), 20162 computeHorizontalScrollExtent(), false); 20163 final Rect bounds = cache.mScrollBarBounds; 20164 getHorizontalScrollBarBounds(bounds, null); 20165 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 20166 bounds.right, bounds.bottom); 20167 if (invalidate) { 20168 invalidate(bounds); 20169 } 20170 } 20171 20172 if (drawVerticalScrollBar) { 20173 scrollBar.setParameters(computeVerticalScrollRange(), 20174 computeVerticalScrollOffset(), 20175 computeVerticalScrollExtent(), true); 20176 final Rect bounds = cache.mScrollBarBounds; 20177 getVerticalScrollBarBounds(bounds, null); 20178 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 20179 bounds.right, bounds.bottom); 20180 if (invalidate) { 20181 invalidate(bounds); 20182 } 20183 } 20184 } 20185 } 20186 } 20187 20188 /** 20189 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 20190 * FastScroller is visible. 20191 * @return whether to temporarily hide the vertical scrollbar 20192 * @hide 20193 */ isVerticalScrollBarHidden()20194 protected boolean isVerticalScrollBarHidden() { 20195 return false; 20196 } 20197 20198 /** 20199 * <p>Draw the horizontal scrollbar if 20200 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 20201 * 20202 * @param canvas the canvas on which to draw the scrollbar 20203 * @param scrollBar the scrollbar's drawable 20204 * 20205 * @see #isHorizontalScrollBarEnabled() 20206 * @see #computeHorizontalScrollRange() 20207 * @see #computeHorizontalScrollExtent() 20208 * @see #computeHorizontalScrollOffset() 20209 * @hide 20210 */ 20211 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)20212 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 20213 int l, int t, int r, int b) { 20214 scrollBar.setBounds(l, t, r, b); 20215 scrollBar.draw(canvas); 20216 } 20217 20218 /** 20219 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 20220 * returns true.</p> 20221 * 20222 * @param canvas the canvas on which to draw the scrollbar 20223 * @param scrollBar the scrollbar's drawable 20224 * 20225 * @see #isVerticalScrollBarEnabled() 20226 * @see #computeVerticalScrollRange() 20227 * @see #computeVerticalScrollExtent() 20228 * @see #computeVerticalScrollOffset() 20229 * @hide 20230 */ 20231 @UnsupportedAppUsage onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)20232 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 20233 int l, int t, int r, int b) { 20234 scrollBar.setBounds(l, t, r, b); 20235 scrollBar.draw(canvas); 20236 } 20237 20238 /** 20239 * Implement this to do your drawing. 20240 * 20241 * @param canvas the canvas on which the background will be drawn 20242 */ onDraw(Canvas canvas)20243 protected void onDraw(Canvas canvas) { 20244 } 20245 20246 /* 20247 * Caller is responsible for calling requestLayout if necessary. 20248 * (This allows addViewInLayout to not request a new layout.) 20249 */ 20250 @UnsupportedAppUsage assignParent(ViewParent parent)20251 void assignParent(ViewParent parent) { 20252 if (mParent == null) { 20253 mParent = parent; 20254 } else if (parent == null) { 20255 mParent = null; 20256 } else { 20257 throw new RuntimeException("view " + this + " being added, but" 20258 + " it already has a parent"); 20259 } 20260 } 20261 20262 /** 20263 * This is called when the view is attached to a window. At this point it 20264 * has a Surface and will start drawing. Note that this function is 20265 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 20266 * however it may be called any time before the first onDraw -- including 20267 * before or after {@link #onMeasure(int, int)}. 20268 * 20269 * @see #onDetachedFromWindow() 20270 */ 20271 @CallSuper onAttachedToWindow()20272 protected void onAttachedToWindow() { 20273 if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 20274 mParent.requestTransparentRegion(this); 20275 } 20276 20277 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 20278 20279 jumpDrawablesToCurrentState(); 20280 20281 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 20282 resetSubtreeAccessibilityStateChanged(); 20283 20284 // rebuild, since Outline not maintained while View is detached 20285 rebuildOutline(); 20286 20287 if (isFocused()) { 20288 notifyFocusChangeToImeFocusController(true /* hasFocus */); 20289 } 20290 } 20291 20292 /** 20293 * Resolve all RTL related properties. 20294 * 20295 * @return true if resolution of RTL properties has been done 20296 * 20297 * @hide 20298 */ resolveRtlPropertiesIfNeeded()20299 public boolean resolveRtlPropertiesIfNeeded() { 20300 if (!needRtlPropertiesResolution()) return false; 20301 20302 // Order is important here: LayoutDirection MUST be resolved first 20303 if (!isLayoutDirectionResolved()) { 20304 resolveLayoutDirection(); 20305 resolveLayoutParams(); 20306 } 20307 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 20308 if (!isTextDirectionResolved()) { 20309 resolveTextDirection(); 20310 } 20311 if (!isTextAlignmentResolved()) { 20312 resolveTextAlignment(); 20313 } 20314 // Should resolve Drawables before Padding because we need the layout direction of the 20315 // Drawable to correctly resolve Padding. 20316 if (!areDrawablesResolved()) { 20317 resolveDrawables(); 20318 } 20319 if (!isPaddingResolved()) { 20320 resolvePadding(); 20321 } 20322 onRtlPropertiesChanged(getLayoutDirection()); 20323 return true; 20324 } 20325 20326 /** 20327 * Reset resolution of all RTL related properties. 20328 * 20329 * @hide 20330 */ 20331 @TestApi resetRtlProperties()20332 public void resetRtlProperties() { 20333 resetResolvedLayoutDirection(); 20334 resetResolvedTextDirection(); 20335 resetResolvedTextAlignment(); 20336 resetResolvedPadding(); 20337 resetResolvedDrawables(); 20338 } 20339 20340 /** 20341 * @see #onScreenStateChanged(int) 20342 */ dispatchScreenStateChanged(int screenState)20343 void dispatchScreenStateChanged(int screenState) { 20344 onScreenStateChanged(screenState); 20345 } 20346 20347 /** 20348 * This method is called whenever the state of the screen this view is 20349 * attached to changes. A state change will usually occurs when the screen 20350 * turns on or off (whether it happens automatically or the user does it 20351 * manually.) 20352 * 20353 * @param screenState The new state of the screen. Can be either 20354 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 20355 */ onScreenStateChanged(int screenState)20356 public void onScreenStateChanged(int screenState) { 20357 } 20358 20359 /** 20360 * @see #onMovedToDisplay(int, Configuration) 20361 */ dispatchMovedToDisplay(Display display, Configuration config)20362 void dispatchMovedToDisplay(Display display, Configuration config) { 20363 mAttachInfo.mDisplay = display; 20364 mAttachInfo.mDisplayState = display.getState(); 20365 onMovedToDisplay(display.getDisplayId(), config); 20366 } 20367 20368 /** 20369 * Called by the system when the hosting activity is moved from one display to another without 20370 * recreation. This means that the activity is declared to handle all changes to configuration 20371 * that happened when it was switched to another display, so it wasn't destroyed and created 20372 * again. 20373 * 20374 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 20375 * applied configuration actually changed. It is up to app developer to choose whether to handle 20376 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 20377 * call. 20378 * 20379 * <p>Use this callback to track changes to the displays if some functionality relies on an 20380 * association with some display properties. 20381 * 20382 * @param displayId The id of the display to which the view was moved. 20383 * @param config Configuration of the resources on new display after move. 20384 * 20385 * @see #onConfigurationChanged(Configuration) 20386 * @hide 20387 */ onMovedToDisplay(int displayId, Configuration config)20388 public void onMovedToDisplay(int displayId, Configuration config) { 20389 } 20390 20391 /** 20392 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 20393 */ 20394 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hasRtlSupport()20395 private boolean hasRtlSupport() { 20396 return mContext.getApplicationInfo().hasRtlSupport(); 20397 } 20398 20399 /** 20400 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 20401 * RTL not supported) 20402 */ isRtlCompatibilityMode()20403 private boolean isRtlCompatibilityMode() { 20404 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 20405 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 20406 } 20407 20408 /** 20409 * @return true if RTL properties need resolution. 20410 * 20411 */ needRtlPropertiesResolution()20412 private boolean needRtlPropertiesResolution() { 20413 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 20414 } 20415 20416 /** 20417 * Called when any RTL property (layout direction or text direction or text alignment) has 20418 * been changed. 20419 * 20420 * Subclasses need to override this method to take care of cached information that depends on the 20421 * resolved layout direction, or to inform child views that inherit their layout direction. 20422 * 20423 * The default implementation does nothing. 20424 * 20425 * @param layoutDirection the direction of the layout 20426 * 20427 * @see #LAYOUT_DIRECTION_LTR 20428 * @see #LAYOUT_DIRECTION_RTL 20429 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)20430 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 20431 } 20432 20433 /** 20434 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 20435 * that the parent directionality can and will be resolved before its children. 20436 * 20437 * @return true if resolution has been done, false otherwise. 20438 * 20439 * @hide 20440 */ resolveLayoutDirection()20441 public boolean resolveLayoutDirection() { 20442 // Clear any previous layout direction resolution 20443 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20444 20445 if (hasRtlSupport()) { 20446 // Set resolved depending on layout direction 20447 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 20448 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 20449 case LAYOUT_DIRECTION_INHERIT: 20450 // We cannot resolve yet. LTR is by default and let the resolution happen again 20451 // later to get the correct resolved value 20452 if (!canResolveLayoutDirection()) return false; 20453 20454 // Parent has not yet resolved, LTR is still the default 20455 try { 20456 if (!mParent.isLayoutDirectionResolved()) return false; 20457 20458 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 20459 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20460 } 20461 } catch (AbstractMethodError e) { 20462 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20463 " does not fully implement ViewParent", e); 20464 } 20465 break; 20466 case LAYOUT_DIRECTION_RTL: 20467 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20468 break; 20469 case LAYOUT_DIRECTION_LOCALE: 20470 if((LAYOUT_DIRECTION_RTL == 20471 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 20472 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20473 } 20474 break; 20475 default: 20476 // Nothing to do, LTR by default 20477 } 20478 } 20479 20480 // Set to resolved 20481 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 20482 return true; 20483 } 20484 20485 /** 20486 * Check if layout direction resolution can be done. 20487 * 20488 * @return true if layout direction resolution can be done otherwise return false. 20489 */ canResolveLayoutDirection()20490 public boolean canResolveLayoutDirection() { 20491 switch (getRawLayoutDirection()) { 20492 case LAYOUT_DIRECTION_INHERIT: 20493 if (mParent != null) { 20494 try { 20495 return mParent.canResolveLayoutDirection(); 20496 } catch (AbstractMethodError e) { 20497 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20498 " does not fully implement ViewParent", e); 20499 } 20500 } 20501 return false; 20502 20503 default: 20504 return true; 20505 } 20506 } 20507 20508 /** 20509 * Reset the resolved layout direction. Layout direction will be resolved during a call to 20510 * {@link #onMeasure(int, int)}. 20511 * 20512 * @hide 20513 */ 20514 @TestApi resetResolvedLayoutDirection()20515 public void resetResolvedLayoutDirection() { 20516 // Reset the current resolved bits 20517 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20518 } 20519 20520 /** 20521 * @return true if the layout direction is inherited. 20522 * 20523 * @hide 20524 */ isLayoutDirectionInherited()20525 public boolean isLayoutDirectionInherited() { 20526 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 20527 } 20528 20529 /** 20530 * @return true if layout direction has been resolved. 20531 */ isLayoutDirectionResolved()20532 public boolean isLayoutDirectionResolved() { 20533 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 20534 } 20535 20536 /** 20537 * Return if padding has been resolved 20538 * 20539 * @hide 20540 */ 20541 @UnsupportedAppUsage isPaddingResolved()20542 boolean isPaddingResolved() { 20543 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 20544 } 20545 20546 /** 20547 * Resolves padding depending on layout direction, if applicable, and 20548 * recomputes internal padding values to adjust for scroll bars. 20549 * 20550 * @hide 20551 */ 20552 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolvePadding()20553 public void resolvePadding() { 20554 final int resolvedLayoutDirection = getLayoutDirection(); 20555 20556 if (!isRtlCompatibilityMode()) { 20557 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 20558 // If start / end padding are defined, they will be resolved (hence overriding) to 20559 // left / right or right / left depending on the resolved layout direction. 20560 // If start / end padding are not defined, use the left / right ones. 20561 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 20562 Rect padding = sThreadLocal.get(); 20563 if (padding == null) { 20564 padding = new Rect(); 20565 sThreadLocal.set(padding); 20566 } 20567 mBackground.getPadding(padding); 20568 if (!mLeftPaddingDefined) { 20569 mUserPaddingLeftInitial = padding.left; 20570 } 20571 if (!mRightPaddingDefined) { 20572 mUserPaddingRightInitial = padding.right; 20573 } 20574 } 20575 switch (resolvedLayoutDirection) { 20576 case LAYOUT_DIRECTION_RTL: 20577 if (mUserPaddingStart != UNDEFINED_PADDING) { 20578 mUserPaddingRight = mUserPaddingStart; 20579 } else { 20580 mUserPaddingRight = mUserPaddingRightInitial; 20581 } 20582 if (mUserPaddingEnd != UNDEFINED_PADDING) { 20583 mUserPaddingLeft = mUserPaddingEnd; 20584 } else { 20585 mUserPaddingLeft = mUserPaddingLeftInitial; 20586 } 20587 break; 20588 case LAYOUT_DIRECTION_LTR: 20589 default: 20590 if (mUserPaddingStart != UNDEFINED_PADDING) { 20591 mUserPaddingLeft = mUserPaddingStart; 20592 } else { 20593 mUserPaddingLeft = mUserPaddingLeftInitial; 20594 } 20595 if (mUserPaddingEnd != UNDEFINED_PADDING) { 20596 mUserPaddingRight = mUserPaddingEnd; 20597 } else { 20598 mUserPaddingRight = mUserPaddingRightInitial; 20599 } 20600 } 20601 20602 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 20603 } 20604 20605 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 20606 onRtlPropertiesChanged(resolvedLayoutDirection); 20607 20608 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 20609 } 20610 20611 /** 20612 * Reset the resolved layout direction. 20613 * 20614 * @hide 20615 */ 20616 @TestApi resetResolvedPadding()20617 public void resetResolvedPadding() { 20618 resetResolvedPaddingInternal(); 20619 } 20620 20621 /** 20622 * Used when we only want to reset *this* view's padding and not trigger overrides 20623 * in ViewGroup that reset children too. 20624 */ resetResolvedPaddingInternal()20625 void resetResolvedPaddingInternal() { 20626 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 20627 } 20628 20629 /** 20630 * This is called when the view is detached from a window. At this point it 20631 * no longer has a surface for drawing. 20632 * 20633 * @see #onAttachedToWindow() 20634 */ 20635 @CallSuper onDetachedFromWindow()20636 protected void onDetachedFromWindow() { 20637 } 20638 20639 /** 20640 * This is a framework-internal mirror of onDetachedFromWindow() that's called 20641 * after onDetachedFromWindow(). 20642 * 20643 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 20644 * The super method should be called at the end of the overridden method to ensure 20645 * subclasses are destroyed first 20646 * 20647 * @hide 20648 */ 20649 @CallSuper 20650 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()20651 protected void onDetachedFromWindowInternal() { 20652 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 20653 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 20654 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 20655 20656 removeUnsetPressCallback(); 20657 removeLongPressCallback(); 20658 removePerformClickCallback(); 20659 clearAccessibilityThrottles(); 20660 stopNestedScroll(); 20661 20662 // Anything that started animating right before detach should already 20663 // be in its final state when re-attached. 20664 jumpDrawablesToCurrentState(); 20665 20666 destroyDrawingCache(); 20667 20668 cleanupDraw(); 20669 mCurrentAnimation = null; 20670 20671 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 20672 hideTooltip(); 20673 } 20674 20675 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 20676 } 20677 cleanupDraw()20678 private void cleanupDraw() { 20679 resetDisplayList(); 20680 if (mAttachInfo != null) { 20681 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 20682 } 20683 } 20684 invalidateInheritedLayoutMode(int layoutModeOfRoot)20685 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 20686 } 20687 20688 /** 20689 * @return The number of times this view has been attached to a window 20690 */ getWindowAttachCount()20691 protected int getWindowAttachCount() { 20692 return mWindowAttachCount; 20693 } 20694 20695 /** 20696 * Retrieve a unique token identifying the window this view is attached to. 20697 * @return Return the window's token for use in 20698 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 20699 */ getWindowToken()20700 public IBinder getWindowToken() { 20701 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 20702 } 20703 20704 /** 20705 * Retrieve the {@link WindowId} for the window this view is 20706 * currently attached to. 20707 */ getWindowId()20708 public WindowId getWindowId() { 20709 AttachInfo ai = mAttachInfo; 20710 if (ai == null) { 20711 return null; 20712 } 20713 if (ai.mWindowId == null) { 20714 try { 20715 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 20716 if (ai.mIWindowId != null) { 20717 ai.mWindowId = new WindowId(ai.mIWindowId); 20718 } 20719 } catch (RemoteException e) { 20720 } 20721 } 20722 return ai.mWindowId; 20723 } 20724 20725 /** 20726 * Retrieve a unique token identifying the top-level "real" window of 20727 * the window that this view is attached to. That is, this is like 20728 * {@link #getWindowToken}, except if the window this view in is a panel 20729 * window (attached to another containing window), then the token of 20730 * the containing window is returned instead. 20731 * 20732 * @return Returns the associated window token, either 20733 * {@link #getWindowToken()} or the containing window's token. 20734 */ getApplicationWindowToken()20735 public IBinder getApplicationWindowToken() { 20736 AttachInfo ai = mAttachInfo; 20737 if (ai != null) { 20738 IBinder appWindowToken = ai.mPanelParentWindowToken; 20739 if (appWindowToken == null) { 20740 appWindowToken = ai.mWindowToken; 20741 } 20742 return appWindowToken; 20743 } 20744 return null; 20745 } 20746 20747 /** 20748 * Gets the logical display to which the view's window has been attached. 20749 * 20750 * @return The logical display, or null if the view is not currently attached to a window. 20751 */ getDisplay()20752 public Display getDisplay() { 20753 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 20754 } 20755 20756 /** 20757 * Retrieve private session object this view hierarchy is using to 20758 * communicate with the window manager. 20759 * @return the session object to communicate with the window manager 20760 */ 20761 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()20762 /*package*/ IWindowSession getWindowSession() { 20763 return mAttachInfo != null ? mAttachInfo.mSession : null; 20764 } 20765 20766 /** 20767 * Return the window this view is currently attached to. 20768 * @hide 20769 */ getWindow()20770 protected IWindow getWindow() { 20771 return mAttachInfo != null ? mAttachInfo.mWindow : null; 20772 } 20773 20774 /** 20775 * Return the visibility value of the least visible component passed. 20776 */ combineVisibility(int vis1, int vis2)20777 int combineVisibility(int vis1, int vis2) { 20778 // This works because VISIBLE < INVISIBLE < GONE. 20779 return Math.max(vis1, vis2); 20780 } 20781 20782 /** 20783 * @param info the {@link android.view.View.AttachInfo} to associated with 20784 * this view 20785 */ 20786 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)20787 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 20788 mAttachInfo = info; 20789 if (mOverlay != null) { 20790 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 20791 } 20792 mWindowAttachCount++; 20793 // We will need to evaluate the drawable state at least once. 20794 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20795 if (mFloatingTreeObserver != null) { 20796 info.mTreeObserver.merge(mFloatingTreeObserver); 20797 mFloatingTreeObserver = null; 20798 } 20799 20800 registerPendingFrameMetricsObservers(); 20801 20802 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 20803 mAttachInfo.mScrollContainers.add(this); 20804 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 20805 } 20806 // Transfer all pending runnables. 20807 if (mRunQueue != null) { 20808 mRunQueue.executeActions(info.mHandler); 20809 mRunQueue = null; 20810 } 20811 performCollectViewAttributes(mAttachInfo, visibility); 20812 onAttachedToWindow(); 20813 20814 ListenerInfo li = mListenerInfo; 20815 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20816 li != null ? li.mOnAttachStateChangeListeners : null; 20817 if (listeners != null && listeners.size() > 0) { 20818 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20819 // perform the dispatching. The iterator is a safe guard against listeners that 20820 // could mutate the list by calling the various add/remove methods. This prevents 20821 // the array from being modified while we iterate it. 20822 for (OnAttachStateChangeListener listener : listeners) { 20823 listener.onViewAttachedToWindow(this); 20824 } 20825 } 20826 20827 int vis = info.mWindowVisibility; 20828 if (vis != GONE) { 20829 onWindowVisibilityChanged(vis); 20830 if (isShown()) { 20831 // Calling onVisibilityAggregated directly here since the subtree will also 20832 // receive dispatchAttachedToWindow and this same call 20833 onVisibilityAggregated(vis == VISIBLE); 20834 } 20835 } 20836 20837 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 20838 // As all views in the subtree will already receive dispatchAttachedToWindow 20839 // traversing the subtree again here is not desired. 20840 onVisibilityChanged(this, visibility); 20841 20842 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 20843 // If nobody has evaluated the drawable state yet, then do it now. 20844 refreshDrawableState(); 20845 } 20846 needGlobalAttributesUpdate(false); 20847 20848 notifyEnterOrExitForAutoFillIfNeeded(true); 20849 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 20850 } 20851 20852 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()20853 void dispatchDetachedFromWindow() { 20854 AttachInfo info = mAttachInfo; 20855 if (info != null) { 20856 int vis = info.mWindowVisibility; 20857 if (vis != GONE) { 20858 onWindowVisibilityChanged(GONE); 20859 if (isShown()) { 20860 // Invoking onVisibilityAggregated directly here since the subtree 20861 // will also receive detached from window 20862 onVisibilityAggregated(false); 20863 } 20864 } 20865 } 20866 20867 onDetachedFromWindow(); 20868 onDetachedFromWindowInternal(); 20869 20870 if (info != null) { 20871 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 20872 } 20873 20874 ListenerInfo li = mListenerInfo; 20875 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20876 li != null ? li.mOnAttachStateChangeListeners : null; 20877 if (listeners != null && listeners.size() > 0) { 20878 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20879 // perform the dispatching. The iterator is a safe guard against listeners that 20880 // could mutate the list by calling the various add/remove methods. This prevents 20881 // the array from being modified while we iterate it. 20882 for (OnAttachStateChangeListener listener : listeners) { 20883 listener.onViewDetachedFromWindow(this); 20884 } 20885 } 20886 20887 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 20888 mAttachInfo.mScrollContainers.remove(this); 20889 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 20890 } 20891 20892 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 20893 20894 mAttachInfo = null; 20895 if (mOverlay != null) { 20896 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 20897 } 20898 20899 notifyEnterOrExitForAutoFillIfNeeded(false); 20900 } 20901 20902 /** 20903 * Cancel any deferred high-level input events that were previously posted to the event queue. 20904 * 20905 * <p>Many views post high-level events such as click handlers to the event queue 20906 * to run deferred in order to preserve a desired user experience - clearing visible 20907 * pressed states before executing, etc. This method will abort any events of this nature 20908 * that are currently in flight.</p> 20909 * 20910 * <p>Custom views that generate their own high-level deferred input events should override 20911 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 20912 * 20913 * <p>This will also cancel pending input events for any child views.</p> 20914 * 20915 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 20916 * This will not impact newer events posted after this call that may occur as a result of 20917 * lower-level input events still waiting in the queue. If you are trying to prevent 20918 * double-submitted events for the duration of some sort of asynchronous transaction 20919 * you should also take other steps to protect against unexpected double inputs e.g. calling 20920 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 20921 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 20922 */ cancelPendingInputEvents()20923 public final void cancelPendingInputEvents() { 20924 dispatchCancelPendingInputEvents(); 20925 } 20926 20927 /** 20928 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 20929 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 20930 */ dispatchCancelPendingInputEvents()20931 void dispatchCancelPendingInputEvents() { 20932 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 20933 onCancelPendingInputEvents(); 20934 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 20935 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 20936 " did not call through to super.onCancelPendingInputEvents()"); 20937 } 20938 } 20939 20940 /** 20941 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 20942 * a parent view. 20943 * 20944 * <p>This method is responsible for removing any pending high-level input events that were 20945 * posted to the event queue to run later. Custom view classes that post their own deferred 20946 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 20947 * {@link android.os.Handler} should override this method, call 20948 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 20949 * </p> 20950 */ onCancelPendingInputEvents()20951 public void onCancelPendingInputEvents() { 20952 removePerformClickCallback(); 20953 cancelLongPress(); 20954 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 20955 } 20956 20957 /** 20958 * Store this view hierarchy's frozen state into the given container. 20959 * 20960 * @param container The SparseArray in which to save the view's state. 20961 * 20962 * @see #restoreHierarchyState(android.util.SparseArray) 20963 * @see #dispatchSaveInstanceState(android.util.SparseArray) 20964 * @see #onSaveInstanceState() 20965 */ saveHierarchyState(SparseArray<Parcelable> container)20966 public void saveHierarchyState(SparseArray<Parcelable> container) { 20967 dispatchSaveInstanceState(container); 20968 } 20969 20970 /** 20971 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 20972 * this view and its children. May be overridden to modify how freezing happens to a 20973 * view's children; for example, some views may want to not store state for their children. 20974 * 20975 * @param container The SparseArray in which to save the view's state. 20976 * 20977 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20978 * @see #saveHierarchyState(android.util.SparseArray) 20979 * @see #onSaveInstanceState() 20980 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)20981 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 20982 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 20983 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 20984 Parcelable state = onSaveInstanceState(); 20985 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 20986 throw new IllegalStateException( 20987 "Derived class did not call super.onSaveInstanceState()"); 20988 } 20989 if (state != null) { 20990 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 20991 // + ": " + state); 20992 container.put(mID, state); 20993 } 20994 } 20995 } 20996 20997 /** 20998 * Hook allowing a view to generate a representation of its internal state 20999 * that can later be used to create a new instance with that same state. 21000 * This state should only contain information that is not persistent or can 21001 * not be reconstructed later. For example, you will never store your 21002 * current position on screen because that will be computed again when a 21003 * new instance of the view is placed in its view hierarchy. 21004 * <p> 21005 * Some examples of things you may store here: the current cursor position 21006 * in a text view (but usually not the text itself since that is stored in a 21007 * content provider or other persistent storage), the currently selected 21008 * item in a list view. 21009 * 21010 * @return Returns a Parcelable object containing the view's current dynamic 21011 * state, or null if there is nothing interesting to save. 21012 * @see #onRestoreInstanceState(Parcelable) 21013 * @see #saveHierarchyState(SparseArray) 21014 * @see #dispatchSaveInstanceState(SparseArray) 21015 * @see #setSaveEnabled(boolean) 21016 */ 21017 @CallSuper onSaveInstanceState()21018 @Nullable protected Parcelable onSaveInstanceState() { 21019 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 21020 if (mStartActivityRequestWho != null || isAutofilled() 21021 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 21022 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 21023 21024 if (mStartActivityRequestWho != null) { 21025 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 21026 } 21027 21028 if (isAutofilled()) { 21029 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 21030 } 21031 21032 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 21033 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 21034 } 21035 21036 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 21037 state.mIsAutofilled = isAutofilled(); 21038 state.mHideHighlight = hideAutofillHighlight(); 21039 state.mAutofillViewId = mAutofillViewId; 21040 return state; 21041 } 21042 return BaseSavedState.EMPTY_STATE; 21043 } 21044 21045 /** 21046 * Restore this view hierarchy's frozen state from the given container. 21047 * 21048 * @param container The SparseArray which holds previously frozen states. 21049 * 21050 * @see #saveHierarchyState(android.util.SparseArray) 21051 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 21052 * @see #onRestoreInstanceState(android.os.Parcelable) 21053 */ restoreHierarchyState(SparseArray<Parcelable> container)21054 public void restoreHierarchyState(SparseArray<Parcelable> container) { 21055 dispatchRestoreInstanceState(container); 21056 } 21057 21058 /** 21059 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 21060 * state for this view and its children. May be overridden to modify how restoring 21061 * happens to a view's children; for example, some views may want to not store state 21062 * for their children. 21063 * 21064 * @param container The SparseArray which holds previously saved state. 21065 * 21066 * @see #dispatchSaveInstanceState(android.util.SparseArray) 21067 * @see #restoreHierarchyState(android.util.SparseArray) 21068 * @see #onRestoreInstanceState(android.os.Parcelable) 21069 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)21070 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 21071 if (mID != NO_ID) { 21072 Parcelable state = container.get(mID); 21073 if (state != null) { 21074 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 21075 // + ": " + state); 21076 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 21077 onRestoreInstanceState(state); 21078 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 21079 throw new IllegalStateException( 21080 "Derived class did not call super.onRestoreInstanceState()"); 21081 } 21082 } 21083 } 21084 } 21085 21086 /** 21087 * Hook allowing a view to re-apply a representation of its internal state that had previously 21088 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 21089 * null state. 21090 * 21091 * @param state The frozen state that had previously been returned by 21092 * {@link #onSaveInstanceState}. 21093 * 21094 * @see #onSaveInstanceState() 21095 * @see #restoreHierarchyState(android.util.SparseArray) 21096 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 21097 */ 21098 @CallSuper onRestoreInstanceState(Parcelable state)21099 protected void onRestoreInstanceState(Parcelable state) { 21100 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 21101 if (state != null && !(state instanceof AbsSavedState)) { 21102 throw new IllegalArgumentException("Wrong state class, expecting View State but " 21103 + "received " + state.getClass().toString() + " instead. This usually happens " 21104 + "when two views of different type have the same id in the same hierarchy. " 21105 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 21106 + "other views do not use the same id."); 21107 } 21108 if (state != null && state instanceof BaseSavedState) { 21109 BaseSavedState baseState = (BaseSavedState) state; 21110 21111 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 21112 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 21113 } 21114 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 21115 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 21116 } 21117 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 21118 // It can happen that views have the same view id and the restoration path will not 21119 // be able to distinguish between them. The autofill id needs to be unique though. 21120 // Hence prevent the same autofill view id from being restored multiple times. 21121 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 21122 21123 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 21124 // Ignore when view already set it through setAutofillId(); 21125 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 21126 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 21127 + "to " + baseState.mAutofillViewId + " because view explicitly set" 21128 + " it to " + mAutofillId); 21129 } 21130 } else { 21131 mAutofillViewId = baseState.mAutofillViewId; 21132 mAutofillId = null; // will be set on demand by getAutofillId() 21133 } 21134 } 21135 } 21136 } 21137 21138 /** 21139 * <p>Return the time at which the drawing of the view hierarchy started.</p> 21140 * 21141 * @return the drawing start time in milliseconds 21142 */ getDrawingTime()21143 public long getDrawingTime() { 21144 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 21145 } 21146 21147 /** 21148 * <p>Enables or disables the duplication of the parent's state into this view. When 21149 * duplication is enabled, this view gets its drawable state from its parent rather 21150 * than from its own internal properties.</p> 21151 * 21152 * <p>Note: in the current implementation, setting this property to true after the 21153 * view was added to a ViewGroup might have no effect at all. This property should 21154 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 21155 * 21156 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 21157 * property is enabled, an exception will be thrown.</p> 21158 * 21159 * <p>Note: if the child view uses and updates additional states which are unknown to the 21160 * parent, these states should not be affected by this method.</p> 21161 * 21162 * @param enabled True to enable duplication of the parent's drawable state, false 21163 * to disable it. 21164 * 21165 * @see #getDrawableState() 21166 * @see #isDuplicateParentStateEnabled() 21167 */ setDuplicateParentStateEnabled(boolean enabled)21168 public void setDuplicateParentStateEnabled(boolean enabled) { 21169 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 21170 } 21171 21172 /** 21173 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 21174 * 21175 * @return True if this view's drawable state is duplicated from the parent, 21176 * false otherwise 21177 * 21178 * @see #getDrawableState() 21179 * @see #setDuplicateParentStateEnabled(boolean) 21180 */ 21181 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()21182 public boolean isDuplicateParentStateEnabled() { 21183 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 21184 } 21185 21186 /** 21187 * <p>Specifies the type of layer backing this view. The layer can be 21188 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21189 * {@link #LAYER_TYPE_HARDWARE}.</p> 21190 * 21191 * <p>A layer is associated with an optional {@link android.graphics.Paint} 21192 * instance that controls how the layer is composed on screen. The following 21193 * properties of the paint are taken into account when composing the layer:</p> 21194 * <ul> 21195 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 21196 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 21197 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 21198 * </ul> 21199 * 21200 * <p>If this view has an alpha value set to < 1.0 by calling 21201 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 21202 * by this view's alpha value.</p> 21203 * 21204 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 21205 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 21206 * for more information on when and how to use layers.</p> 21207 * 21208 * @param layerType The type of layer to use with this view, must be one of 21209 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21210 * {@link #LAYER_TYPE_HARDWARE} 21211 * @param paint The paint used to compose the layer. This argument is optional 21212 * and can be null. It is ignored when the layer type is 21213 * {@link #LAYER_TYPE_NONE} 21214 * 21215 * @see #getLayerType() 21216 * @see #LAYER_TYPE_NONE 21217 * @see #LAYER_TYPE_SOFTWARE 21218 * @see #LAYER_TYPE_HARDWARE 21219 * @see #setAlpha(float) 21220 * 21221 * @attr ref android.R.styleable#View_layerType 21222 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)21223 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 21224 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 21225 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 21226 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 21227 } 21228 21229 boolean typeChanged = mRenderNode.setLayerType(layerType); 21230 21231 if (!typeChanged) { 21232 setLayerPaint(paint); 21233 return; 21234 } 21235 21236 if (layerType != LAYER_TYPE_SOFTWARE) { 21237 // Destroy any previous software drawing cache if present 21238 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 21239 // drawing cache created in View#draw when drawing to a SW canvas. 21240 destroyDrawingCache(); 21241 } 21242 21243 mLayerType = layerType; 21244 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 21245 mRenderNode.setLayerPaint(mLayerPaint); 21246 21247 // draw() behaves differently if we are on a layer, so we need to 21248 // invalidate() here 21249 invalidateParentCaches(); 21250 invalidate(true); 21251 } 21252 21253 /** 21254 * Configure the {@link android.graphics.RenderEffect} to apply to this View. 21255 * This will apply a visual effect to the results of the View before it is drawn. For example if 21256 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 21257 * is provided, the contents will be drawn in a separate layer, then this layer will be blurred 21258 * when this View is drawn. 21259 * @param renderEffect to be applied to the View. Passing null clears the previously configured 21260 * {@link RenderEffect} 21261 */ setRenderEffect(@ullable RenderEffect renderEffect)21262 public void setRenderEffect(@Nullable RenderEffect renderEffect) { 21263 if (mRenderNode.setRenderEffect(renderEffect)) { 21264 invalidateViewProperty(true, true); 21265 } 21266 } 21267 21268 /** 21269 * Updates the {@link Paint} object used with the current layer (used only if the current 21270 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 21271 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 21272 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 21273 * ensure that the view gets redrawn immediately. 21274 * 21275 * <p>A layer is associated with an optional {@link android.graphics.Paint} 21276 * instance that controls how the layer is composed on screen. The following 21277 * properties of the paint are taken into account when composing the layer:</p> 21278 * <ul> 21279 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 21280 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 21281 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 21282 * </ul> 21283 * 21284 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 21285 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 21286 * 21287 * @param paint The paint used to compose the layer. This argument is optional 21288 * and can be null. It is ignored when the layer type is 21289 * {@link #LAYER_TYPE_NONE} 21290 * 21291 * @see #setLayerType(int, android.graphics.Paint) 21292 */ setLayerPaint(@ullable Paint paint)21293 public void setLayerPaint(@Nullable Paint paint) { 21294 int layerType = getLayerType(); 21295 if (layerType != LAYER_TYPE_NONE) { 21296 mLayerPaint = paint; 21297 if (layerType == LAYER_TYPE_HARDWARE) { 21298 if (mRenderNode.setLayerPaint(paint)) { 21299 invalidateViewProperty(false, false); 21300 } 21301 } else { 21302 invalidate(); 21303 } 21304 } 21305 } 21306 21307 /** 21308 * Indicates what type of layer is currently associated with this view. By default 21309 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 21310 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 21311 * for more information on the different types of layers. 21312 * 21313 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21314 * {@link #LAYER_TYPE_HARDWARE} 21315 * 21316 * @see #setLayerType(int, android.graphics.Paint) 21317 * @see #buildLayer() 21318 * @see #LAYER_TYPE_NONE 21319 * @see #LAYER_TYPE_SOFTWARE 21320 * @see #LAYER_TYPE_HARDWARE 21321 */ 21322 @InspectableProperty(enumMapping = { 21323 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 21324 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 21325 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 21326 }) 21327 @LayerType getLayerType()21328 public int getLayerType() { 21329 return mLayerType; 21330 } 21331 21332 /** 21333 * Forces this view's layer to be created and this view to be rendered 21334 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 21335 * invoking this method will have no effect. 21336 * 21337 * This method can for instance be used to render a view into its layer before 21338 * starting an animation. If this view is complex, rendering into the layer 21339 * before starting the animation will avoid skipping frames. 21340 * 21341 * @throws IllegalStateException If this view is not attached to a window 21342 * 21343 * @see #setLayerType(int, android.graphics.Paint) 21344 */ buildLayer()21345 public void buildLayer() { 21346 if (mLayerType == LAYER_TYPE_NONE) return; 21347 21348 final AttachInfo attachInfo = mAttachInfo; 21349 if (attachInfo == null) { 21350 throw new IllegalStateException("This view must be attached to a window first"); 21351 } 21352 21353 if (getWidth() == 0 || getHeight() == 0) { 21354 return; 21355 } 21356 21357 switch (mLayerType) { 21358 case LAYER_TYPE_HARDWARE: 21359 updateDisplayListIfDirty(); 21360 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 21361 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 21362 } 21363 break; 21364 case LAYER_TYPE_SOFTWARE: 21365 buildDrawingCache(true); 21366 break; 21367 } 21368 } 21369 21370 /** 21371 * Destroys all hardware rendering resources. This method is invoked 21372 * when the system needs to reclaim resources. Upon execution of this 21373 * method, you should free any OpenGL resources created by the view. 21374 * 21375 * Note: you <strong>must</strong> call 21376 * <code>super.destroyHardwareResources()</code> when overriding 21377 * this method. 21378 * 21379 * @hide 21380 */ 21381 @CallSuper 21382 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareResources()21383 protected void destroyHardwareResources() { 21384 if (mOverlay != null) { 21385 mOverlay.getOverlayView().destroyHardwareResources(); 21386 } 21387 if (mGhostView != null) { 21388 mGhostView.destroyHardwareResources(); 21389 } 21390 } 21391 21392 /** 21393 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 21394 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 21395 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 21396 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 21397 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 21398 * null.</p> 21399 * 21400 * <p>Enabling the drawing cache is similar to 21401 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 21402 * acceleration is turned off. When hardware acceleration is turned on, enabling the 21403 * drawing cache has no effect on rendering because the system uses a different mechanism 21404 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 21405 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 21406 * for information on how to enable software and hardware layers.</p> 21407 * 21408 * <p>This API can be used to manually generate 21409 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 21410 * {@link #getDrawingCache()}.</p> 21411 * 21412 * @param enabled true to enable the drawing cache, false otherwise 21413 * 21414 * @see #isDrawingCacheEnabled() 21415 * @see #getDrawingCache() 21416 * @see #buildDrawingCache() 21417 * @see #setLayerType(int, android.graphics.Paint) 21418 * 21419 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21420 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21421 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21422 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21423 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21424 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21425 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21426 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21427 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21428 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21429 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21430 * reports or unit testing the {@link PixelCopy} API is recommended. 21431 */ 21432 @Deprecated setDrawingCacheEnabled(boolean enabled)21433 public void setDrawingCacheEnabled(boolean enabled) { 21434 mCachingFailed = false; 21435 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 21436 } 21437 21438 /** 21439 * <p>Indicates whether the drawing cache is enabled for this view.</p> 21440 * 21441 * @return true if the drawing cache is enabled 21442 * 21443 * @see #setDrawingCacheEnabled(boolean) 21444 * @see #getDrawingCache() 21445 * 21446 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21447 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21448 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21449 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21450 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21451 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21452 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21453 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21454 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21455 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21456 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21457 * reports or unit testing the {@link PixelCopy} API is recommended. 21458 */ 21459 @Deprecated 21460 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()21461 public boolean isDrawingCacheEnabled() { 21462 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 21463 } 21464 21465 /** 21466 * Debugging utility which recursively outputs the dirty state of a view and its 21467 * descendants. 21468 * 21469 * @hide 21470 */ 21471 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)21472 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 21473 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 21474 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 21475 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 21476 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 21477 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 21478 if (clear) { 21479 mPrivateFlags &= clearMask; 21480 } 21481 if (this instanceof ViewGroup) { 21482 ViewGroup parent = (ViewGroup) this; 21483 final int count = parent.getChildCount(); 21484 for (int i = 0; i < count; i++) { 21485 final View child = parent.getChildAt(i); 21486 child.outputDirtyFlags(indent + " ", clear, clearMask); 21487 } 21488 } 21489 } 21490 21491 /** 21492 * This method is used by ViewGroup to cause its children to restore or recreate their 21493 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 21494 * to recreate its own display list, which would happen if it went through the normal 21495 * draw/dispatchDraw mechanisms. 21496 * 21497 * @hide 21498 */ dispatchGetDisplayList()21499 protected void dispatchGetDisplayList() {} 21500 21501 /** 21502 * A view that is not attached or hardware accelerated cannot create a display list. 21503 * This method checks these conditions and returns the appropriate result. 21504 * 21505 * @return true if view has the ability to create a display list, false otherwise. 21506 * 21507 * @hide 21508 */ canHaveDisplayList()21509 public boolean canHaveDisplayList() { 21510 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 21511 } 21512 21513 /** 21514 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 21515 * @hide 21516 */ 21517 @NonNull 21518 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateDisplayListIfDirty()21519 public RenderNode updateDisplayListIfDirty() { 21520 final RenderNode renderNode = mRenderNode; 21521 if (!canHaveDisplayList()) { 21522 // can't populate RenderNode, don't try 21523 return renderNode; 21524 } 21525 21526 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 21527 || !renderNode.hasDisplayList() 21528 || (mRecreateDisplayList)) { 21529 // Don't need to recreate the display list, just need to tell our 21530 // children to restore/recreate theirs 21531 if (renderNode.hasDisplayList() 21532 && !mRecreateDisplayList) { 21533 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21534 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21535 dispatchGetDisplayList(); 21536 21537 return renderNode; // no work needed 21538 } 21539 21540 // If we got here, we're recreating it. Mark it as such to ensure that 21541 // we copy in child display lists into ours in drawChild() 21542 mRecreateDisplayList = true; 21543 21544 int width = mRight - mLeft; 21545 int height = mBottom - mTop; 21546 int layerType = getLayerType(); 21547 21548 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 21549 // instead of being "stateful" like other RenderNode properties 21550 renderNode.clearStretch(); 21551 21552 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 21553 21554 try { 21555 if (layerType == LAYER_TYPE_SOFTWARE) { 21556 buildDrawingCache(true); 21557 Bitmap cache = getDrawingCache(true); 21558 if (cache != null) { 21559 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 21560 } 21561 } else { 21562 computeScroll(); 21563 21564 canvas.translate(-mScrollX, -mScrollY); 21565 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21566 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21567 21568 // Fast path for layouts with no backgrounds 21569 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21570 dispatchDraw(canvas); 21571 drawAutofilledHighlight(canvas); 21572 if (mOverlay != null && !mOverlay.isEmpty()) { 21573 mOverlay.getOverlayView().draw(canvas); 21574 } 21575 if (isShowingLayoutBounds()) { 21576 debugDrawFocus(canvas); 21577 } 21578 } else { 21579 draw(canvas); 21580 } 21581 } 21582 } finally { 21583 renderNode.endRecording(); 21584 setDisplayListProperties(renderNode); 21585 } 21586 } else { 21587 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21588 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21589 } 21590 return renderNode; 21591 } 21592 21593 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resetDisplayList()21594 private void resetDisplayList() { 21595 mRenderNode.discardDisplayList(); 21596 if (mBackgroundRenderNode != null) { 21597 mBackgroundRenderNode.discardDisplayList(); 21598 } 21599 } 21600 21601 /** 21602 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 21603 * 21604 * @return A non-scaled bitmap representing this view or null if cache is disabled. 21605 * 21606 * @see #getDrawingCache(boolean) 21607 * 21608 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21609 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21610 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21611 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21612 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21613 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21614 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21615 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21616 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21617 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21618 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21619 * reports or unit testing the {@link PixelCopy} API is recommended. 21620 */ 21621 @Deprecated getDrawingCache()21622 public Bitmap getDrawingCache() { 21623 return getDrawingCache(false); 21624 } 21625 21626 /** 21627 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 21628 * is null when caching is disabled. If caching is enabled and the cache is not ready, 21629 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 21630 * draw from the cache when the cache is enabled. To benefit from the cache, you must 21631 * request the drawing cache by calling this method and draw it on screen if the 21632 * returned bitmap is not null.</p> 21633 * 21634 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21635 * this method will create a bitmap of the same size as this view. Because this bitmap 21636 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21637 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21638 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21639 * size than the view. This implies that your application must be able to handle this 21640 * size.</p> 21641 * 21642 * @param autoScale Indicates whether the generated bitmap should be scaled based on 21643 * the current density of the screen when the application is in compatibility 21644 * mode. 21645 * 21646 * @return A bitmap representing this view or null if cache is disabled. 21647 * 21648 * @see #setDrawingCacheEnabled(boolean) 21649 * @see #isDrawingCacheEnabled() 21650 * @see #buildDrawingCache(boolean) 21651 * @see #destroyDrawingCache() 21652 * 21653 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21654 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21655 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21656 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21657 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21658 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21659 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21660 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21661 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21662 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21663 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21664 * reports or unit testing the {@link PixelCopy} API is recommended. 21665 */ 21666 @Deprecated getDrawingCache(boolean autoScale)21667 public Bitmap getDrawingCache(boolean autoScale) { 21668 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 21669 return null; 21670 } 21671 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 21672 buildDrawingCache(autoScale); 21673 } 21674 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 21675 } 21676 21677 /** 21678 * <p>Frees the resources used by the drawing cache. If you call 21679 * {@link #buildDrawingCache()} manually without calling 21680 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21681 * should cleanup the cache with this method afterwards.</p> 21682 * 21683 * @see #setDrawingCacheEnabled(boolean) 21684 * @see #buildDrawingCache() 21685 * @see #getDrawingCache() 21686 * 21687 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21688 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21689 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21690 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21691 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21692 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21693 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21694 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21695 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21696 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21697 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21698 * reports or unit testing the {@link PixelCopy} API is recommended. 21699 */ 21700 @Deprecated destroyDrawingCache()21701 public void destroyDrawingCache() { 21702 if (mDrawingCache != null) { 21703 mDrawingCache.recycle(); 21704 mDrawingCache = null; 21705 } 21706 if (mUnscaledDrawingCache != null) { 21707 mUnscaledDrawingCache.recycle(); 21708 mUnscaledDrawingCache = null; 21709 } 21710 } 21711 21712 /** 21713 * Setting a solid background color for the drawing cache's bitmaps will improve 21714 * performance and memory usage. Note, though that this should only be used if this 21715 * view will always be drawn on top of a solid color. 21716 * 21717 * @param color The background color to use for the drawing cache's bitmap 21718 * 21719 * @see #setDrawingCacheEnabled(boolean) 21720 * @see #buildDrawingCache() 21721 * @see #getDrawingCache() 21722 * 21723 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21724 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21725 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21726 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21727 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21728 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21729 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21730 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21731 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21732 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21733 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21734 * reports or unit testing the {@link PixelCopy} API is recommended. 21735 */ 21736 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)21737 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 21738 if (color != mDrawingCacheBackgroundColor) { 21739 mDrawingCacheBackgroundColor = color; 21740 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 21741 } 21742 } 21743 21744 /** 21745 * @see #setDrawingCacheBackgroundColor(int) 21746 * 21747 * @return The background color to used for the drawing cache's bitmap 21748 * 21749 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21750 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21751 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21752 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21753 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21754 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21755 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21756 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21757 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21758 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21759 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21760 * reports or unit testing the {@link PixelCopy} API is recommended. 21761 */ 21762 @Deprecated 21763 @ColorInt getDrawingCacheBackgroundColor()21764 public int getDrawingCacheBackgroundColor() { 21765 return mDrawingCacheBackgroundColor; 21766 } 21767 21768 /** 21769 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 21770 * 21771 * @see #buildDrawingCache(boolean) 21772 * 21773 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21774 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21775 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21776 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21777 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21778 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21779 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21780 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21781 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21782 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21783 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21784 * reports or unit testing the {@link PixelCopy} API is recommended. 21785 */ 21786 @Deprecated buildDrawingCache()21787 public void buildDrawingCache() { 21788 buildDrawingCache(false); 21789 } 21790 21791 /** 21792 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 21793 * 21794 * <p>If you call {@link #buildDrawingCache()} manually without calling 21795 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21796 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 21797 * 21798 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21799 * this method will create a bitmap of the same size as this view. Because this bitmap 21800 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21801 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21802 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21803 * size than the view. This implies that your application must be able to handle this 21804 * size.</p> 21805 * 21806 * <p>You should avoid calling this method when hardware acceleration is enabled. If 21807 * you do not need the drawing cache bitmap, calling this method will increase memory 21808 * usage and cause the view to be rendered in software once, thus negatively impacting 21809 * performance.</p> 21810 * 21811 * @see #getDrawingCache() 21812 * @see #destroyDrawingCache() 21813 * 21814 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21815 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21816 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21817 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21818 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21819 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21820 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21821 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21822 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21823 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21824 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21825 * reports or unit testing the {@link PixelCopy} API is recommended. 21826 */ 21827 @Deprecated buildDrawingCache(boolean autoScale)21828 public void buildDrawingCache(boolean autoScale) { 21829 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 21830 mDrawingCache == null : mUnscaledDrawingCache == null)) { 21831 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 21832 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 21833 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 21834 } 21835 try { 21836 buildDrawingCacheImpl(autoScale); 21837 } finally { 21838 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 21839 } 21840 } 21841 } 21842 21843 /** 21844 * private, internal implementation of buildDrawingCache, used to enable tracing 21845 */ buildDrawingCacheImpl(boolean autoScale)21846 private void buildDrawingCacheImpl(boolean autoScale) { 21847 mCachingFailed = false; 21848 21849 int width = mRight - mLeft; 21850 int height = mBottom - mTop; 21851 21852 final AttachInfo attachInfo = mAttachInfo; 21853 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 21854 21855 if (autoScale && scalingRequired) { 21856 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 21857 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 21858 } 21859 21860 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 21861 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 21862 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 21863 21864 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 21865 final long drawingCacheSize = 21866 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 21867 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 21868 if (width > 0 && height > 0) { 21869 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 21870 + " too large to fit into a software layer (or drawing cache), needs " 21871 + projectedBitmapSize + " bytes, only " 21872 + drawingCacheSize + " available"); 21873 } 21874 destroyDrawingCache(); 21875 mCachingFailed = true; 21876 return; 21877 } 21878 21879 boolean clear = true; 21880 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 21881 21882 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 21883 Bitmap.Config quality; 21884 if (!opaque) { 21885 // Never pick ARGB_4444 because it looks awful 21886 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 21887 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 21888 case DRAWING_CACHE_QUALITY_AUTO: 21889 case DRAWING_CACHE_QUALITY_LOW: 21890 case DRAWING_CACHE_QUALITY_HIGH: 21891 default: 21892 quality = Bitmap.Config.ARGB_8888; 21893 break; 21894 } 21895 } else { 21896 // Optimization for translucent windows 21897 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 21898 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 21899 } 21900 21901 // Try to cleanup memory 21902 if (bitmap != null) bitmap.recycle(); 21903 21904 try { 21905 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 21906 width, height, quality); 21907 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 21908 if (autoScale) { 21909 mDrawingCache = bitmap; 21910 } else { 21911 mUnscaledDrawingCache = bitmap; 21912 } 21913 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 21914 } catch (OutOfMemoryError e) { 21915 // If there is not enough memory to create the bitmap cache, just 21916 // ignore the issue as bitmap caches are not required to draw the 21917 // view hierarchy 21918 if (autoScale) { 21919 mDrawingCache = null; 21920 } else { 21921 mUnscaledDrawingCache = null; 21922 } 21923 mCachingFailed = true; 21924 return; 21925 } 21926 21927 clear = drawingCacheBackgroundColor != 0; 21928 } 21929 21930 Canvas canvas; 21931 if (attachInfo != null) { 21932 canvas = attachInfo.mCanvas; 21933 if (canvas == null) { 21934 canvas = new Canvas(); 21935 } 21936 canvas.setBitmap(bitmap); 21937 // Temporarily clobber the cached Canvas in case one of our children 21938 // is also using a drawing cache. Without this, the children would 21939 // steal the canvas by attaching their own bitmap to it and bad, bad 21940 // thing would happen (invisible views, corrupted drawings, etc.) 21941 attachInfo.mCanvas = null; 21942 } else { 21943 // This case should hopefully never or seldom happen 21944 canvas = new Canvas(bitmap); 21945 } 21946 21947 if (clear) { 21948 bitmap.eraseColor(drawingCacheBackgroundColor); 21949 } 21950 21951 computeScroll(); 21952 final int restoreCount = canvas.save(); 21953 21954 if (autoScale && scalingRequired) { 21955 final float scale = attachInfo.mApplicationScale; 21956 canvas.scale(scale, scale); 21957 } 21958 21959 canvas.translate(-mScrollX, -mScrollY); 21960 21961 mPrivateFlags |= PFLAG_DRAWN; 21962 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 21963 mLayerType != LAYER_TYPE_NONE) { 21964 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 21965 } 21966 21967 // Fast path for layouts with no backgrounds 21968 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21969 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21970 dispatchDraw(canvas); 21971 drawAutofilledHighlight(canvas); 21972 if (mOverlay != null && !mOverlay.isEmpty()) { 21973 mOverlay.getOverlayView().draw(canvas); 21974 } 21975 } else { 21976 draw(canvas); 21977 } 21978 21979 canvas.restoreToCount(restoreCount); 21980 canvas.setBitmap(null); 21981 21982 if (attachInfo != null) { 21983 // Restore the cached Canvas for our siblings 21984 attachInfo.mCanvas = canvas; 21985 } 21986 } 21987 21988 /** 21989 * Create a snapshot of the view into a bitmap. We should probably make 21990 * some form of this public, but should think about the API. 21991 * 21992 * @hide 21993 */ 21994 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)21995 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 21996 int width = mRight - mLeft; 21997 int height = mBottom - mTop; 21998 21999 final AttachInfo attachInfo = mAttachInfo; 22000 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 22001 width = (int) ((width * scale) + 0.5f); 22002 height = (int) ((height * scale) + 0.5f); 22003 22004 Canvas oldCanvas = null; 22005 try { 22006 Canvas canvas = canvasProvider.getCanvas(this, 22007 width > 0 ? width : 1, height > 0 ? height : 1); 22008 22009 if (attachInfo != null) { 22010 oldCanvas = attachInfo.mCanvas; 22011 // Temporarily clobber the cached Canvas in case one of our children 22012 // is also using a drawing cache. Without this, the children would 22013 // steal the canvas by attaching their own bitmap to it and bad, bad 22014 // things would happen (invisible views, corrupted drawings, etc.) 22015 attachInfo.mCanvas = null; 22016 } 22017 22018 computeScroll(); 22019 final int restoreCount = canvas.save(); 22020 canvas.scale(scale, scale); 22021 canvas.translate(-mScrollX, -mScrollY); 22022 22023 // Temporarily remove the dirty mask 22024 int flags = mPrivateFlags; 22025 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22026 22027 // Fast path for layouts with no backgrounds 22028 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22029 dispatchDraw(canvas); 22030 drawAutofilledHighlight(canvas); 22031 if (mOverlay != null && !mOverlay.isEmpty()) { 22032 mOverlay.getOverlayView().draw(canvas); 22033 } 22034 } else { 22035 draw(canvas); 22036 } 22037 22038 mPrivateFlags = flags; 22039 canvas.restoreToCount(restoreCount); 22040 return canvasProvider.createBitmap(); 22041 } finally { 22042 if (oldCanvas != null) { 22043 attachInfo.mCanvas = oldCanvas; 22044 } 22045 } 22046 } 22047 22048 /** 22049 * Indicates whether this View is currently in edit mode. A View is usually 22050 * in edit mode when displayed within a developer tool. For instance, if 22051 * this View is being drawn by a visual user interface builder, this method 22052 * should return true. 22053 * 22054 * Subclasses should check the return value of this method to provide 22055 * different behaviors if their normal behavior might interfere with the 22056 * host environment. For instance: the class spawns a thread in its 22057 * constructor, the drawing code relies on device-specific features, etc. 22058 * 22059 * This method is usually checked in the drawing code of custom widgets. 22060 * 22061 * @return True if this View is in edit mode, false otherwise. 22062 */ isInEditMode()22063 public boolean isInEditMode() { 22064 return false; 22065 } 22066 22067 /** 22068 * If the View draws content inside its padding and enables fading edges, 22069 * it needs to support padding offsets. Padding offsets are added to the 22070 * fading edges to extend the length of the fade so that it covers pixels 22071 * drawn inside the padding. 22072 * 22073 * Subclasses of this class should override this method if they need 22074 * to draw content inside the padding. 22075 * 22076 * @return True if padding offset must be applied, false otherwise. 22077 * 22078 * @see #getLeftPaddingOffset() 22079 * @see #getRightPaddingOffset() 22080 * @see #getTopPaddingOffset() 22081 * @see #getBottomPaddingOffset() 22082 * 22083 * @since CURRENT 22084 */ isPaddingOffsetRequired()22085 protected boolean isPaddingOffsetRequired() { 22086 return false; 22087 } 22088 22089 /** 22090 * Amount by which to extend the left fading region. Called only when 22091 * {@link #isPaddingOffsetRequired()} returns true. 22092 * 22093 * @return The left padding offset in pixels. 22094 * 22095 * @see #isPaddingOffsetRequired() 22096 * 22097 * @since CURRENT 22098 */ getLeftPaddingOffset()22099 protected int getLeftPaddingOffset() { 22100 return 0; 22101 } 22102 22103 /** 22104 * Amount by which to extend the right fading region. Called only when 22105 * {@link #isPaddingOffsetRequired()} returns true. 22106 * 22107 * @return The right padding offset in pixels. 22108 * 22109 * @see #isPaddingOffsetRequired() 22110 * 22111 * @since CURRENT 22112 */ getRightPaddingOffset()22113 protected int getRightPaddingOffset() { 22114 return 0; 22115 } 22116 22117 /** 22118 * Amount by which to extend the top fading region. Called only when 22119 * {@link #isPaddingOffsetRequired()} returns true. 22120 * 22121 * @return The top padding offset in pixels. 22122 * 22123 * @see #isPaddingOffsetRequired() 22124 * 22125 * @since CURRENT 22126 */ getTopPaddingOffset()22127 protected int getTopPaddingOffset() { 22128 return 0; 22129 } 22130 22131 /** 22132 * Amount by which to extend the bottom fading region. Called only when 22133 * {@link #isPaddingOffsetRequired()} returns true. 22134 * 22135 * @return The bottom padding offset in pixels. 22136 * 22137 * @see #isPaddingOffsetRequired() 22138 * 22139 * @since CURRENT 22140 */ getBottomPaddingOffset()22141 protected int getBottomPaddingOffset() { 22142 return 0; 22143 } 22144 22145 /** 22146 * @hide 22147 * @param offsetRequired 22148 */ getFadeTop(boolean offsetRequired)22149 protected int getFadeTop(boolean offsetRequired) { 22150 int top = mPaddingTop; 22151 if (offsetRequired) top += getTopPaddingOffset(); 22152 return top; 22153 } 22154 22155 /** 22156 * @hide 22157 * @param offsetRequired 22158 */ getFadeHeight(boolean offsetRequired)22159 protected int getFadeHeight(boolean offsetRequired) { 22160 int padding = mPaddingTop; 22161 if (offsetRequired) padding += getTopPaddingOffset(); 22162 return mBottom - mTop - mPaddingBottom - padding; 22163 } 22164 22165 /** 22166 * <p>Indicates whether this view is attached to a hardware accelerated 22167 * window or not.</p> 22168 * 22169 * <p>Even if this method returns true, it does not mean that every call 22170 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 22171 * accelerated {@link android.graphics.Canvas}. For instance, if this view 22172 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 22173 * window is hardware accelerated, 22174 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 22175 * return false, and this method will return true.</p> 22176 * 22177 * @return True if the view is attached to a window and the window is 22178 * hardware accelerated; false in any other case. 22179 */ 22180 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()22181 public boolean isHardwareAccelerated() { 22182 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 22183 } 22184 22185 /** 22186 * Sets a rectangular area on this view to which the view will be clipped 22187 * when it is drawn. Setting the value to null will remove the clip bounds 22188 * and the view will draw normally, using its full bounds. 22189 * 22190 * @param clipBounds The rectangular area, in the local coordinates of 22191 * this view, to which future drawing operations will be clipped. 22192 */ setClipBounds(Rect clipBounds)22193 public void setClipBounds(Rect clipBounds) { 22194 if (clipBounds == mClipBounds 22195 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 22196 return; 22197 } 22198 if (clipBounds != null) { 22199 if (mClipBounds == null) { 22200 mClipBounds = new Rect(clipBounds); 22201 } else { 22202 mClipBounds.set(clipBounds); 22203 } 22204 } else { 22205 mClipBounds = null; 22206 } 22207 mRenderNode.setClipRect(mClipBounds); 22208 invalidateViewProperty(false, false); 22209 } 22210 22211 /** 22212 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 22213 * 22214 * @return A copy of the current clip bounds if clip bounds are set, 22215 * otherwise null. 22216 */ getClipBounds()22217 public Rect getClipBounds() { 22218 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 22219 } 22220 22221 22222 /** 22223 * Populates an output rectangle with the clip bounds of the view, 22224 * returning {@code true} if successful or {@code false} if the view's 22225 * clip bounds are {@code null}. 22226 * 22227 * @param outRect rectangle in which to place the clip bounds of the view 22228 * @return {@code true} if successful or {@code false} if the view's 22229 * clip bounds are {@code null} 22230 */ getClipBounds(Rect outRect)22231 public boolean getClipBounds(Rect outRect) { 22232 if (mClipBounds != null) { 22233 outRect.set(mClipBounds); 22234 return true; 22235 } 22236 return false; 22237 } 22238 22239 /** 22240 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 22241 * case of an active Animation being run on the view. 22242 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)22243 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 22244 Animation a, boolean scalingRequired) { 22245 Transformation invalidationTransform; 22246 final int flags = parent.mGroupFlags; 22247 final boolean initialized = a.isInitialized(); 22248 if (!initialized) { 22249 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 22250 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 22251 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 22252 onAnimationStart(); 22253 } 22254 22255 final Transformation t = parent.getChildTransformation(); 22256 boolean more = a.getTransformation(drawingTime, t, 1f); 22257 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 22258 if (parent.mInvalidationTransformation == null) { 22259 parent.mInvalidationTransformation = new Transformation(); 22260 } 22261 invalidationTransform = parent.mInvalidationTransformation; 22262 a.getTransformation(drawingTime, invalidationTransform, 1f); 22263 } else { 22264 invalidationTransform = t; 22265 } 22266 22267 if (more) { 22268 if (!a.willChangeBounds()) { 22269 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 22270 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 22271 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 22272 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 22273 // The child need to draw an animation, potentially offscreen, so 22274 // make sure we do not cancel invalidate requests 22275 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 22276 parent.invalidate(mLeft, mTop, mRight, mBottom); 22277 } 22278 } else { 22279 if (parent.mInvalidateRegion == null) { 22280 parent.mInvalidateRegion = new RectF(); 22281 } 22282 final RectF region = parent.mInvalidateRegion; 22283 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 22284 invalidationTransform); 22285 22286 // The child need to draw an animation, potentially offscreen, so 22287 // make sure we do not cancel invalidate requests 22288 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 22289 22290 final int left = mLeft + (int) region.left; 22291 final int top = mTop + (int) region.top; 22292 parent.invalidate(left, top, left + (int) (region.width() + .5f), 22293 top + (int) (region.height() + .5f)); 22294 } 22295 } 22296 return more; 22297 } 22298 22299 /** 22300 * This method is called by getDisplayList() when a display list is recorded for a View. 22301 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 22302 */ setDisplayListProperties(RenderNode renderNode)22303 void setDisplayListProperties(RenderNode renderNode) { 22304 if (renderNode != null) { 22305 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 22306 renderNode.setClipToBounds(mParent instanceof ViewGroup 22307 && ((ViewGroup) mParent).getClipChildren()); 22308 22309 float alpha = 1; 22310 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 22311 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22312 ViewGroup parentVG = (ViewGroup) mParent; 22313 final Transformation t = parentVG.getChildTransformation(); 22314 if (parentVG.getChildStaticTransformation(this, t)) { 22315 final int transformType = t.getTransformationType(); 22316 if (transformType != Transformation.TYPE_IDENTITY) { 22317 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 22318 alpha = t.getAlpha(); 22319 } 22320 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 22321 renderNode.setStaticMatrix(t.getMatrix()); 22322 } 22323 } 22324 } 22325 } 22326 if (mTransformationInfo != null) { 22327 alpha *= getFinalAlpha(); 22328 if (alpha < 1) { 22329 final int multipliedAlpha = (int) (255 * alpha); 22330 if (onSetAlpha(multipliedAlpha)) { 22331 alpha = 1; 22332 } 22333 } 22334 renderNode.setAlpha(alpha); 22335 } else if (alpha < 1) { 22336 renderNode.setAlpha(alpha); 22337 } 22338 } 22339 } 22340 22341 /** 22342 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 22343 * 22344 * This is where the View specializes rendering behavior based on layer type, 22345 * and hardware acceleration. 22346 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)22347 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 22348 22349 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 22350 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 22351 * 22352 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 22353 * HW accelerated, it can't handle drawing RenderNodes. 22354 */ 22355 boolean drawingWithRenderNode = mAttachInfo != null 22356 && mAttachInfo.mHardwareAccelerated 22357 && hardwareAcceleratedCanvas; 22358 22359 boolean more = false; 22360 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 22361 final int parentFlags = parent.mGroupFlags; 22362 22363 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 22364 parent.getChildTransformation().clear(); 22365 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22366 } 22367 22368 Transformation transformToApply = null; 22369 boolean concatMatrix = false; 22370 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 22371 final Animation a = getAnimation(); 22372 if (a != null) { 22373 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 22374 concatMatrix = a.willChangeTransformationMatrix(); 22375 if (concatMatrix) { 22376 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22377 } 22378 transformToApply = parent.getChildTransformation(); 22379 } else { 22380 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 22381 // No longer animating: clear out old animation matrix 22382 mRenderNode.setAnimationMatrix(null); 22383 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22384 } 22385 if (!drawingWithRenderNode 22386 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22387 final Transformation t = parent.getChildTransformation(); 22388 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 22389 if (hasTransform) { 22390 final int transformType = t.getTransformationType(); 22391 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 22392 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 22393 } 22394 } 22395 } 22396 22397 concatMatrix |= !childHasIdentityMatrix; 22398 22399 // Sets the flag as early as possible to allow draw() implementations 22400 // to call invalidate() successfully when doing animations 22401 mPrivateFlags |= PFLAG_DRAWN; 22402 22403 if (!concatMatrix && 22404 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 22405 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 22406 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 22407 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 22408 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 22409 return more; 22410 } 22411 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 22412 22413 if (hardwareAcceleratedCanvas) { 22414 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 22415 // retain the flag's value temporarily in the mRecreateDisplayList flag 22416 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 22417 mPrivateFlags &= ~PFLAG_INVALIDATED; 22418 } 22419 22420 RenderNode renderNode = null; 22421 Bitmap cache = null; 22422 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 22423 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 22424 if (layerType != LAYER_TYPE_NONE) { 22425 // If not drawing with RenderNode, treat HW layers as SW 22426 layerType = LAYER_TYPE_SOFTWARE; 22427 buildDrawingCache(true); 22428 } 22429 cache = getDrawingCache(true); 22430 } 22431 22432 if (drawingWithRenderNode) { 22433 // Delay getting the display list until animation-driven alpha values are 22434 // set up and possibly passed on to the view 22435 renderNode = updateDisplayListIfDirty(); 22436 if (!renderNode.hasDisplayList()) { 22437 // Uncommon, but possible. If a view is removed from the hierarchy during the call 22438 // to getDisplayList(), the display list will be marked invalid and we should not 22439 // try to use it again. 22440 renderNode = null; 22441 drawingWithRenderNode = false; 22442 } 22443 } 22444 22445 int sx = 0; 22446 int sy = 0; 22447 if (!drawingWithRenderNode) { 22448 computeScroll(); 22449 sx = mScrollX; 22450 sy = mScrollY; 22451 } 22452 22453 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 22454 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 22455 22456 int restoreTo = -1; 22457 if (!drawingWithRenderNode || transformToApply != null) { 22458 restoreTo = canvas.save(); 22459 } 22460 if (offsetForScroll) { 22461 canvas.translate(mLeft - sx, mTop - sy); 22462 } else { 22463 if (!drawingWithRenderNode) { 22464 canvas.translate(mLeft, mTop); 22465 } 22466 if (scalingRequired) { 22467 if (drawingWithRenderNode) { 22468 // TODO: Might not need this if we put everything inside the DL 22469 restoreTo = canvas.save(); 22470 } 22471 // mAttachInfo cannot be null, otherwise scalingRequired == false 22472 final float scale = 1.0f / mAttachInfo.mApplicationScale; 22473 canvas.scale(scale, scale); 22474 } 22475 } 22476 22477 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 22478 if (transformToApply != null 22479 || alpha < 1 22480 || !hasIdentityMatrix() 22481 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 22482 if (transformToApply != null || !childHasIdentityMatrix) { 22483 int transX = 0; 22484 int transY = 0; 22485 22486 if (offsetForScroll) { 22487 transX = -sx; 22488 transY = -sy; 22489 } 22490 22491 if (transformToApply != null) { 22492 if (concatMatrix) { 22493 if (drawingWithRenderNode) { 22494 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 22495 } else { 22496 // Undo the scroll translation, apply the transformation matrix, 22497 // then redo the scroll translate to get the correct result. 22498 canvas.translate(-transX, -transY); 22499 canvas.concat(transformToApply.getMatrix()); 22500 canvas.translate(transX, transY); 22501 } 22502 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22503 } 22504 22505 float transformAlpha = transformToApply.getAlpha(); 22506 if (transformAlpha < 1) { 22507 alpha *= transformAlpha; 22508 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22509 } 22510 } 22511 22512 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 22513 canvas.translate(-transX, -transY); 22514 canvas.concat(getMatrix()); 22515 canvas.translate(transX, transY); 22516 } 22517 } 22518 22519 // Deal with alpha if it is or used to be <1 22520 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 22521 if (alpha < 1) { 22522 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 22523 } else { 22524 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 22525 } 22526 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22527 if (!drawingWithDrawingCache) { 22528 final int multipliedAlpha = (int) (255 * alpha); 22529 if (!onSetAlpha(multipliedAlpha)) { 22530 if (drawingWithRenderNode) { 22531 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 22532 } else if (layerType == LAYER_TYPE_NONE) { 22533 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 22534 multipliedAlpha); 22535 } 22536 } else { 22537 // Alpha is handled by the child directly, clobber the layer's alpha 22538 mPrivateFlags |= PFLAG_ALPHA_SET; 22539 } 22540 } 22541 } 22542 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 22543 onSetAlpha(255); 22544 mPrivateFlags &= ~PFLAG_ALPHA_SET; 22545 } 22546 22547 if (!drawingWithRenderNode) { 22548 // apply clips directly, since RenderNode won't do it for this draw 22549 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 22550 if (offsetForScroll) { 22551 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 22552 } else { 22553 if (!scalingRequired || cache == null) { 22554 canvas.clipRect(0, 0, getWidth(), getHeight()); 22555 } else { 22556 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 22557 } 22558 } 22559 } 22560 22561 if (mClipBounds != null) { 22562 // clip bounds ignore scroll 22563 canvas.clipRect(mClipBounds); 22564 } 22565 } 22566 22567 if (!drawingWithDrawingCache) { 22568 if (drawingWithRenderNode) { 22569 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22570 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22571 } else { 22572 // Fast path for layouts with no backgrounds 22573 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22574 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22575 dispatchDraw(canvas); 22576 } else { 22577 draw(canvas); 22578 } 22579 } 22580 } else if (cache != null) { 22581 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22582 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 22583 // no layer paint, use temporary paint to draw bitmap 22584 Paint cachePaint = parent.mCachePaint; 22585 if (cachePaint == null) { 22586 cachePaint = new Paint(); 22587 cachePaint.setDither(false); 22588 parent.mCachePaint = cachePaint; 22589 } 22590 cachePaint.setAlpha((int) (alpha * 255)); 22591 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 22592 } else { 22593 // use layer paint to draw the bitmap, merging the two alphas, but also restore 22594 int layerPaintAlpha = mLayerPaint.getAlpha(); 22595 if (alpha < 1) { 22596 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 22597 } 22598 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 22599 if (alpha < 1) { 22600 mLayerPaint.setAlpha(layerPaintAlpha); 22601 } 22602 } 22603 } 22604 22605 if (restoreTo >= 0) { 22606 canvas.restoreToCount(restoreTo); 22607 } 22608 22609 if (a != null && !more) { 22610 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 22611 onSetAlpha(255); 22612 } 22613 parent.finishAnimatingView(this, a); 22614 } 22615 22616 if (more && hardwareAcceleratedCanvas) { 22617 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 22618 // alpha animations should cause the child to recreate its display list 22619 invalidate(true); 22620 } 22621 } 22622 22623 mRecreateDisplayList = false; 22624 22625 return more; 22626 } 22627 getDebugPaint()22628 static Paint getDebugPaint() { 22629 if (sDebugPaint == null) { 22630 sDebugPaint = new Paint(); 22631 sDebugPaint.setAntiAlias(false); 22632 } 22633 return sDebugPaint; 22634 } 22635 dipsToPixels(int dips)22636 final int dipsToPixels(int dips) { 22637 float scale = getContext().getResources().getDisplayMetrics().density; 22638 return (int) (dips * scale + 0.5f); 22639 } 22640 debugDrawFocus(Canvas canvas)22641 final private void debugDrawFocus(Canvas canvas) { 22642 if (isFocused()) { 22643 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 22644 final int l = mScrollX; 22645 final int r = l + mRight - mLeft; 22646 final int t = mScrollY; 22647 final int b = t + mBottom - mTop; 22648 22649 final Paint paint = getDebugPaint(); 22650 paint.setColor(DEBUG_CORNERS_COLOR); 22651 22652 // Draw squares in corners. 22653 paint.setStyle(Paint.Style.FILL); 22654 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 22655 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 22656 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 22657 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 22658 22659 // Draw big X across the view. 22660 paint.setStyle(Paint.Style.STROKE); 22661 canvas.drawLine(l, t, r, b, paint); 22662 canvas.drawLine(l, b, r, t, paint); 22663 } 22664 } 22665 22666 /** 22667 * Manually render this view (and all of its children) to the given Canvas. 22668 * The view must have already done a full layout before this function is 22669 * called. When implementing a view, implement 22670 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 22671 * If you do need to override this method, call the superclass version. 22672 * 22673 * @param canvas The Canvas to which the View is rendered. 22674 */ 22675 @CallSuper draw(Canvas canvas)22676 public void draw(Canvas canvas) { 22677 final int privateFlags = mPrivateFlags; 22678 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 22679 22680 /* 22681 * Draw traversal performs several drawing steps which must be executed 22682 * in the appropriate order: 22683 * 22684 * 1. Draw the background 22685 * 2. If necessary, save the canvas' layers to prepare for fading 22686 * 3. Draw view's content 22687 * 4. Draw children 22688 * 5. If necessary, draw the fading edges and restore layers 22689 * 6. Draw decorations (scrollbars for instance) 22690 * 7. If necessary, draw the default focus highlight 22691 */ 22692 22693 // Step 1, draw the background, if needed 22694 int saveCount; 22695 22696 drawBackground(canvas); 22697 22698 // skip step 2 & 5 if possible (common case) 22699 final int viewFlags = mViewFlags; 22700 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 22701 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 22702 if (!verticalEdges && !horizontalEdges) { 22703 // Step 3, draw the content 22704 onDraw(canvas); 22705 22706 // Step 4, draw the children 22707 dispatchDraw(canvas); 22708 22709 drawAutofilledHighlight(canvas); 22710 22711 // Overlay is part of the content and draws beneath Foreground 22712 if (mOverlay != null && !mOverlay.isEmpty()) { 22713 mOverlay.getOverlayView().dispatchDraw(canvas); 22714 } 22715 22716 // Step 6, draw decorations (foreground, scrollbars) 22717 onDrawForeground(canvas); 22718 22719 // Step 7, draw the default focus highlight 22720 drawDefaultFocusHighlight(canvas); 22721 22722 if (isShowingLayoutBounds()) { 22723 debugDrawFocus(canvas); 22724 } 22725 22726 // we're done... 22727 return; 22728 } 22729 22730 /* 22731 * Here we do the full fledged routine... 22732 * (this is an uncommon case where speed matters less, 22733 * this is why we repeat some of the tests that have been 22734 * done above) 22735 */ 22736 22737 boolean drawTop = false; 22738 boolean drawBottom = false; 22739 boolean drawLeft = false; 22740 boolean drawRight = false; 22741 22742 float topFadeStrength = 0.0f; 22743 float bottomFadeStrength = 0.0f; 22744 float leftFadeStrength = 0.0f; 22745 float rightFadeStrength = 0.0f; 22746 22747 // Step 2, save the canvas' layers 22748 int paddingLeft = mPaddingLeft; 22749 22750 final boolean offsetRequired = isPaddingOffsetRequired(); 22751 if (offsetRequired) { 22752 paddingLeft += getLeftPaddingOffset(); 22753 } 22754 22755 int left = mScrollX + paddingLeft; 22756 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 22757 int top = mScrollY + getFadeTop(offsetRequired); 22758 int bottom = top + getFadeHeight(offsetRequired); 22759 22760 if (offsetRequired) { 22761 right += getRightPaddingOffset(); 22762 bottom += getBottomPaddingOffset(); 22763 } 22764 22765 final ScrollabilityCache scrollabilityCache = mScrollCache; 22766 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 22767 int length = (int) fadeHeight; 22768 22769 // clip the fade length if top and bottom fades overlap 22770 // overlapping fades produce odd-looking artifacts 22771 if (verticalEdges && (top + length > bottom - length)) { 22772 length = (bottom - top) / 2; 22773 } 22774 22775 // also clip horizontal fades if necessary 22776 if (horizontalEdges && (left + length > right - length)) { 22777 length = (right - left) / 2; 22778 } 22779 22780 if (verticalEdges) { 22781 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 22782 drawTop = topFadeStrength * fadeHeight > 1.0f; 22783 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 22784 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 22785 } 22786 22787 if (horizontalEdges) { 22788 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 22789 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 22790 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 22791 drawRight = rightFadeStrength * fadeHeight > 1.0f; 22792 } 22793 22794 saveCount = canvas.getSaveCount(); 22795 int topSaveCount = -1; 22796 int bottomSaveCount = -1; 22797 int leftSaveCount = -1; 22798 int rightSaveCount = -1; 22799 22800 int solidColor = getSolidColor(); 22801 if (solidColor == 0) { 22802 if (drawTop) { 22803 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 22804 } 22805 22806 if (drawBottom) { 22807 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 22808 } 22809 22810 if (drawLeft) { 22811 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 22812 } 22813 22814 if (drawRight) { 22815 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 22816 } 22817 } else { 22818 scrollabilityCache.setFadeColor(solidColor); 22819 } 22820 22821 // Step 3, draw the content 22822 onDraw(canvas); 22823 22824 // Step 4, draw the children 22825 dispatchDraw(canvas); 22826 22827 // Step 5, draw the fade effect and restore layers 22828 final Paint p = scrollabilityCache.paint; 22829 final Matrix matrix = scrollabilityCache.matrix; 22830 final Shader fade = scrollabilityCache.shader; 22831 22832 // must be restored in the reverse order that they were saved 22833 if (drawRight) { 22834 matrix.setScale(1, fadeHeight * rightFadeStrength); 22835 matrix.postRotate(90); 22836 matrix.postTranslate(right, top); 22837 fade.setLocalMatrix(matrix); 22838 p.setShader(fade); 22839 if (solidColor == 0) { 22840 canvas.restoreUnclippedLayer(rightSaveCount, p); 22841 22842 } else { 22843 canvas.drawRect(right - length, top, right, bottom, p); 22844 } 22845 } 22846 22847 if (drawLeft) { 22848 matrix.setScale(1, fadeHeight * leftFadeStrength); 22849 matrix.postRotate(-90); 22850 matrix.postTranslate(left, top); 22851 fade.setLocalMatrix(matrix); 22852 p.setShader(fade); 22853 if (solidColor == 0) { 22854 canvas.restoreUnclippedLayer(leftSaveCount, p); 22855 } else { 22856 canvas.drawRect(left, top, left + length, bottom, p); 22857 } 22858 } 22859 22860 if (drawBottom) { 22861 matrix.setScale(1, fadeHeight * bottomFadeStrength); 22862 matrix.postRotate(180); 22863 matrix.postTranslate(left, bottom); 22864 fade.setLocalMatrix(matrix); 22865 p.setShader(fade); 22866 if (solidColor == 0) { 22867 canvas.restoreUnclippedLayer(bottomSaveCount, p); 22868 } else { 22869 canvas.drawRect(left, bottom - length, right, bottom, p); 22870 } 22871 } 22872 22873 if (drawTop) { 22874 matrix.setScale(1, fadeHeight * topFadeStrength); 22875 matrix.postTranslate(left, top); 22876 fade.setLocalMatrix(matrix); 22877 p.setShader(fade); 22878 if (solidColor == 0) { 22879 canvas.restoreUnclippedLayer(topSaveCount, p); 22880 } else { 22881 canvas.drawRect(left, top, right, top + length, p); 22882 } 22883 } 22884 22885 canvas.restoreToCount(saveCount); 22886 22887 drawAutofilledHighlight(canvas); 22888 22889 // Overlay is part of the content and draws beneath Foreground 22890 if (mOverlay != null && !mOverlay.isEmpty()) { 22891 mOverlay.getOverlayView().dispatchDraw(canvas); 22892 } 22893 22894 // Step 6, draw decorations (foreground, scrollbars) 22895 onDrawForeground(canvas); 22896 22897 // Step 7, draw the default focus highlight 22898 drawDefaultFocusHighlight(canvas); 22899 22900 if (isShowingLayoutBounds()) { 22901 debugDrawFocus(canvas); 22902 } 22903 } 22904 22905 /** 22906 * Draws the background onto the specified canvas. 22907 * 22908 * @param canvas Canvas on which to draw the background 22909 */ 22910 @UnsupportedAppUsage drawBackground(Canvas canvas)22911 private void drawBackground(Canvas canvas) { 22912 final Drawable background = mBackground; 22913 if (background == null) { 22914 return; 22915 } 22916 22917 setBackgroundBounds(); 22918 22919 // Attempt to use a display list if requested. 22920 if (canvas.isHardwareAccelerated() && mAttachInfo != null 22921 && mAttachInfo.mThreadedRenderer != null) { 22922 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 22923 22924 final RenderNode renderNode = mBackgroundRenderNode; 22925 if (renderNode != null && renderNode.hasDisplayList()) { 22926 setBackgroundRenderNodeProperties(renderNode); 22927 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22928 return; 22929 } 22930 } 22931 22932 final int scrollX = mScrollX; 22933 final int scrollY = mScrollY; 22934 if ((scrollX | scrollY) == 0) { 22935 background.draw(canvas); 22936 } else { 22937 canvas.translate(scrollX, scrollY); 22938 background.draw(canvas); 22939 canvas.translate(-scrollX, -scrollY); 22940 } 22941 } 22942 22943 /** 22944 * Sets the correct background bounds and rebuilds the outline, if needed. 22945 * <p/> 22946 * This is called by LayoutLib. 22947 */ setBackgroundBounds()22948 void setBackgroundBounds() { 22949 if (mBackgroundSizeChanged && mBackground != null) { 22950 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 22951 mBackgroundSizeChanged = false; 22952 rebuildOutline(); 22953 } 22954 } 22955 setBackgroundRenderNodeProperties(RenderNode renderNode)22956 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 22957 renderNode.setTranslationX(mScrollX); 22958 renderNode.setTranslationY(mScrollY); 22959 } 22960 22961 /** 22962 * Creates a new display list or updates the existing display list for the 22963 * specified Drawable. 22964 * 22965 * @param drawable Drawable for which to create a display list 22966 * @param renderNode Existing RenderNode, or {@code null} 22967 * @return A valid display list for the specified drawable 22968 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)22969 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 22970 if (renderNode == null) { 22971 renderNode = RenderNode.create(drawable.getClass().getName(), 22972 new ViewAnimationHostBridge(this)); 22973 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 22974 } 22975 22976 final Rect bounds = drawable.getBounds(); 22977 final int width = bounds.width(); 22978 final int height = bounds.height(); 22979 22980 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 22981 // instead of being "stateful" like other RenderNode properties 22982 renderNode.clearStretch(); 22983 22984 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 22985 22986 // Reverse left/top translation done by drawable canvas, which will 22987 // instead be applied by rendernode's LTRB bounds below. This way, the 22988 // drawable's bounds match with its rendernode bounds and its content 22989 // will lie within those bounds in the rendernode tree. 22990 canvas.translate(-bounds.left, -bounds.top); 22991 22992 try { 22993 drawable.draw(canvas); 22994 } finally { 22995 renderNode.endRecording(); 22996 } 22997 22998 // Set up drawable properties that are view-independent. 22999 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 23000 renderNode.setProjectBackwards(drawable.isProjected()); 23001 renderNode.setProjectionReceiver(true); 23002 renderNode.setClipToBounds(false); 23003 return renderNode; 23004 } 23005 23006 /** 23007 * Returns the overlay for this view, creating it if it does not yet exist. 23008 * Adding drawables to the overlay will cause them to be displayed whenever 23009 * the view itself is redrawn. Objects in the overlay should be actively 23010 * managed: remove them when they should not be displayed anymore. The 23011 * overlay will always have the same size as its host view. 23012 * 23013 * <p>Note: Overlays do not currently work correctly with {@link 23014 * SurfaceView} or {@link TextureView}; contents in overlays for these 23015 * types of views may not display correctly.</p> 23016 * 23017 * @return The ViewOverlay object for this view. 23018 * @see ViewOverlay 23019 */ getOverlay()23020 public ViewOverlay getOverlay() { 23021 if (mOverlay == null) { 23022 mOverlay = new ViewOverlay(mContext, this); 23023 } 23024 return mOverlay; 23025 } 23026 23027 /** 23028 * Override this if your view is known to always be drawn on top of a solid color background, 23029 * and needs to draw fading edges. Returning a non-zero color enables the view system to 23030 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 23031 * should be set to 0xFF. 23032 * 23033 * @see #setVerticalFadingEdgeEnabled(boolean) 23034 * @see #setHorizontalFadingEdgeEnabled(boolean) 23035 * 23036 * @return The known solid color background for this view, or 0 if the color may vary 23037 */ 23038 @ViewDebug.ExportedProperty(category = "drawing") 23039 @InspectableProperty 23040 @ColorInt getSolidColor()23041 public int getSolidColor() { 23042 return 0; 23043 } 23044 23045 /** 23046 * Build a human readable string representation of the specified view flags. 23047 * 23048 * @param flags the view flags to convert to a string 23049 * @return a String representing the supplied flags 23050 */ printFlags(int flags)23051 private static String printFlags(int flags) { 23052 String output = ""; 23053 int numFlags = 0; 23054 if ((flags & FOCUSABLE) == FOCUSABLE) { 23055 output += "TAKES_FOCUS"; 23056 numFlags++; 23057 } 23058 23059 switch (flags & VISIBILITY_MASK) { 23060 case INVISIBLE: 23061 if (numFlags > 0) { 23062 output += " "; 23063 } 23064 output += "INVISIBLE"; 23065 // USELESS HERE numFlags++; 23066 break; 23067 case GONE: 23068 if (numFlags > 0) { 23069 output += " "; 23070 } 23071 output += "GONE"; 23072 // USELESS HERE numFlags++; 23073 break; 23074 default: 23075 break; 23076 } 23077 return output; 23078 } 23079 23080 /** 23081 * Build a human readable string representation of the specified private 23082 * view flags. 23083 * 23084 * @param privateFlags the private view flags to convert to a string 23085 * @return a String representing the supplied flags 23086 */ printPrivateFlags(int privateFlags)23087 private static String printPrivateFlags(int privateFlags) { 23088 String output = ""; 23089 int numFlags = 0; 23090 23091 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 23092 output += "WANTS_FOCUS"; 23093 numFlags++; 23094 } 23095 23096 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 23097 if (numFlags > 0) { 23098 output += " "; 23099 } 23100 output += "FOCUSED"; 23101 numFlags++; 23102 } 23103 23104 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 23105 if (numFlags > 0) { 23106 output += " "; 23107 } 23108 output += "SELECTED"; 23109 numFlags++; 23110 } 23111 23112 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 23113 if (numFlags > 0) { 23114 output += " "; 23115 } 23116 output += "IS_ROOT_NAMESPACE"; 23117 numFlags++; 23118 } 23119 23120 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 23121 if (numFlags > 0) { 23122 output += " "; 23123 } 23124 output += "HAS_BOUNDS"; 23125 numFlags++; 23126 } 23127 23128 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 23129 if (numFlags > 0) { 23130 output += " "; 23131 } 23132 output += "DRAWN"; 23133 // USELESS HERE numFlags++; 23134 } 23135 return output; 23136 } 23137 23138 /** 23139 * <p>Indicates whether or not this view's layout will be requested during 23140 * the next hierarchy layout pass.</p> 23141 * 23142 * @return true if the layout will be forced during next layout pass 23143 */ isLayoutRequested()23144 public boolean isLayoutRequested() { 23145 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 23146 } 23147 23148 /** 23149 * Return true if o is a ViewGroup that is laying out using optical bounds. 23150 * @hide 23151 */ isLayoutModeOptical(Object o)23152 public static boolean isLayoutModeOptical(Object o) { 23153 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 23154 } 23155 setOpticalFrame(int left, int top, int right, int bottom)23156 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 23157 Insets parentInsets = mParent instanceof View ? 23158 ((View) mParent).getOpticalInsets() : Insets.NONE; 23159 Insets childInsets = getOpticalInsets(); 23160 return setFrame( 23161 left + parentInsets.left - childInsets.left, 23162 top + parentInsets.top - childInsets.top, 23163 right + parentInsets.left + childInsets.right, 23164 bottom + parentInsets.top + childInsets.bottom); 23165 } 23166 23167 /** 23168 * Assign a size and position to a view and all of its 23169 * descendants 23170 * 23171 * <p>This is the second phase of the layout mechanism. 23172 * (The first is measuring). In this phase, each parent calls 23173 * layout on all of its children to position them. 23174 * This is typically done using the child measurements 23175 * that were stored in the measure pass().</p> 23176 * 23177 * <p>Derived classes should not override this method. 23178 * Derived classes with children should override 23179 * onLayout. In that method, they should 23180 * call layout on each of their children.</p> 23181 * 23182 * @param l Left position, relative to parent 23183 * @param t Top position, relative to parent 23184 * @param r Right position, relative to parent 23185 * @param b Bottom position, relative to parent 23186 */ 23187 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)23188 public void layout(int l, int t, int r, int b) { 23189 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 23190 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 23191 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 23192 } 23193 23194 int oldL = mLeft; 23195 int oldT = mTop; 23196 int oldB = mBottom; 23197 int oldR = mRight; 23198 23199 boolean changed = isLayoutModeOptical(mParent) ? 23200 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 23201 23202 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 23203 onLayout(changed, l, t, r, b); 23204 23205 if (shouldDrawRoundScrollbar()) { 23206 if(mRoundScrollbarRenderer == null) { 23207 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 23208 } 23209 } else { 23210 mRoundScrollbarRenderer = null; 23211 } 23212 23213 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 23214 23215 ListenerInfo li = mListenerInfo; 23216 if (li != null && li.mOnLayoutChangeListeners != null) { 23217 ArrayList<OnLayoutChangeListener> listenersCopy = 23218 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 23219 int numListeners = listenersCopy.size(); 23220 for (int i = 0; i < numListeners; ++i) { 23221 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 23222 } 23223 } 23224 } 23225 23226 final boolean wasLayoutValid = isLayoutValid(); 23227 23228 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 23229 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 23230 23231 if (!wasLayoutValid && isFocused()) { 23232 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 23233 if (canTakeFocus()) { 23234 // We have a robust focus, so parents should no longer be wanting focus. 23235 clearParentsWantFocus(); 23236 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 23237 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 23238 // layout. In this case, there's no guarantee that parent layouts will be evaluated 23239 // and thus the safest action is to clear focus here. 23240 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23241 clearParentsWantFocus(); 23242 } else if (!hasParentWantsFocus()) { 23243 // original requestFocus was likely on this view directly, so just clear focus 23244 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23245 } 23246 // otherwise, we let parents handle re-assigning focus during their layout passes. 23247 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 23248 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 23249 View focused = findFocus(); 23250 if (focused != null) { 23251 // Try to restore focus as close as possible to our starting focus. 23252 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 23253 // Give up and clear focus once we've reached the top-most parent which wants 23254 // focus. 23255 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23256 } 23257 } 23258 } 23259 23260 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 23261 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 23262 notifyEnterOrExitForAutoFillIfNeeded(true); 23263 } 23264 23265 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 23266 } 23267 hasParentWantsFocus()23268 private boolean hasParentWantsFocus() { 23269 ViewParent parent = mParent; 23270 while (parent instanceof ViewGroup) { 23271 ViewGroup pv = (ViewGroup) parent; 23272 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 23273 return true; 23274 } 23275 parent = pv.mParent; 23276 } 23277 return false; 23278 } 23279 23280 /** 23281 * Called from layout when this view should 23282 * assign a size and position to each of its children. 23283 * 23284 * Derived classes with children should override 23285 * this method and call layout on each of 23286 * their children. 23287 * @param changed This is a new size or position for this view 23288 * @param left Left position, relative to parent 23289 * @param top Top position, relative to parent 23290 * @param right Right position, relative to parent 23291 * @param bottom Bottom position, relative to parent 23292 */ onLayout(boolean changed, int left, int top, int right, int bottom)23293 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 23294 } 23295 23296 /** 23297 * Assign a size and position to this view. 23298 * 23299 * This is called from layout. 23300 * 23301 * @param left Left position, relative to parent 23302 * @param top Top position, relative to parent 23303 * @param right Right position, relative to parent 23304 * @param bottom Bottom position, relative to parent 23305 * @return true if the new size and position are different than the 23306 * previous ones 23307 * {@hide} 23308 */ 23309 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)23310 protected boolean setFrame(int left, int top, int right, int bottom) { 23311 boolean changed = false; 23312 23313 if (DBG) { 23314 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 23315 + right + "," + bottom + ")"); 23316 } 23317 23318 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 23319 changed = true; 23320 23321 // Remember our drawn bit 23322 int drawn = mPrivateFlags & PFLAG_DRAWN; 23323 23324 int oldWidth = mRight - mLeft; 23325 int oldHeight = mBottom - mTop; 23326 int newWidth = right - left; 23327 int newHeight = bottom - top; 23328 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 23329 23330 // Invalidate our old position 23331 invalidate(sizeChanged); 23332 23333 mLeft = left; 23334 mTop = top; 23335 mRight = right; 23336 mBottom = bottom; 23337 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 23338 23339 mPrivateFlags |= PFLAG_HAS_BOUNDS; 23340 23341 23342 if (sizeChanged) { 23343 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 23344 } 23345 23346 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 23347 // If we are visible, force the DRAWN bit to on so that 23348 // this invalidate will go through (at least to our parent). 23349 // This is because someone may have invalidated this view 23350 // before this call to setFrame came in, thereby clearing 23351 // the DRAWN bit. 23352 mPrivateFlags |= PFLAG_DRAWN; 23353 invalidate(sizeChanged); 23354 // parent display list may need to be recreated based on a change in the bounds 23355 // of any child 23356 invalidateParentCaches(); 23357 } 23358 23359 // Reset drawn bit to original value (invalidate turns it off) 23360 mPrivateFlags |= drawn; 23361 23362 mBackgroundSizeChanged = true; 23363 mDefaultFocusHighlightSizeChanged = true; 23364 if (mForegroundInfo != null) { 23365 mForegroundInfo.mBoundsChanged = true; 23366 } 23367 23368 notifySubtreeAccessibilityStateChangedIfNeeded(); 23369 } 23370 return changed; 23371 } 23372 23373 /** 23374 * Assign a size and position to this view. 23375 * 23376 * This method is meant to be used in animations only as it applies this position and size 23377 * for the view only temporary and it can be changed back at any time by the layout. 23378 * 23379 * @param left Left position, relative to parent 23380 * @param top Top position, relative to parent 23381 * @param right Right position, relative to parent 23382 * @param bottom Bottom position, relative to parent 23383 * 23384 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 23385 */ setLeftTopRightBottom(int left, int top, int right, int bottom)23386 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 23387 setFrame(left, top, right, bottom); 23388 } 23389 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)23390 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 23391 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 23392 if (mOverlay != null) { 23393 mOverlay.getOverlayView().setRight(newWidth); 23394 mOverlay.getOverlayView().setBottom(newHeight); 23395 } 23396 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 23397 // backtracking" of requestFocus during layout, so don't touch focus here. 23398 if (!sCanFocusZeroSized && isLayoutValid() 23399 // Don't touch focus if animating 23400 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 23401 if (newWidth <= 0 || newHeight <= 0) { 23402 if (hasFocus()) { 23403 clearFocus(); 23404 if (mParent instanceof ViewGroup) { 23405 ((ViewGroup) mParent).clearFocusedInCluster(); 23406 } 23407 } 23408 clearAccessibilityFocus(); 23409 } else if (oldWidth <= 0 || oldHeight <= 0) { 23410 if (mParent != null && canTakeFocus()) { 23411 mParent.focusableViewAvailable(this); 23412 } 23413 } 23414 } 23415 rebuildOutline(); 23416 } 23417 23418 /** 23419 * Finalize inflating a view from XML. This is called as the last phase 23420 * of inflation, after all child views have been added. 23421 * 23422 * <p>Even if the subclass overrides onFinishInflate, they should always be 23423 * sure to call the super method, so that we get called. 23424 */ 23425 @CallSuper onFinishInflate()23426 protected void onFinishInflate() { 23427 } 23428 23429 /** 23430 * Returns the resources associated with this view. 23431 * 23432 * @return Resources object. 23433 */ getResources()23434 public Resources getResources() { 23435 return mResources; 23436 } 23437 23438 /** 23439 * Invalidates the specified Drawable. 23440 * 23441 * @param drawable the drawable to invalidate 23442 */ 23443 @Override invalidateDrawable(@onNull Drawable drawable)23444 public void invalidateDrawable(@NonNull Drawable drawable) { 23445 if (verifyDrawable(drawable)) { 23446 final Rect dirty = drawable.getDirtyBounds(); 23447 final int scrollX = mScrollX; 23448 final int scrollY = mScrollY; 23449 23450 invalidate(dirty.left + scrollX, dirty.top + scrollY, 23451 dirty.right + scrollX, dirty.bottom + scrollY); 23452 rebuildOutline(); 23453 } 23454 } 23455 23456 /** 23457 * Schedules an action on a drawable to occur at a specified time. 23458 * 23459 * @param who the recipient of the action 23460 * @param what the action to run on the drawable 23461 * @param when the time at which the action must occur. Uses the 23462 * {@link SystemClock#uptimeMillis} timebase. 23463 */ 23464 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)23465 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 23466 if (verifyDrawable(who) && what != null) { 23467 final long delay = when - SystemClock.uptimeMillis(); 23468 if (mAttachInfo != null) { 23469 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 23470 Choreographer.CALLBACK_ANIMATION, what, who, 23471 Choreographer.subtractFrameDelay(delay)); 23472 } else { 23473 // Postpone the runnable until we know 23474 // on which thread it needs to run. 23475 getRunQueue().postDelayed(what, delay); 23476 } 23477 } 23478 } 23479 23480 /** 23481 * Cancels a scheduled action on a drawable. 23482 * 23483 * @param who the recipient of the action 23484 * @param what the action to cancel 23485 */ 23486 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)23487 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 23488 if (verifyDrawable(who) && what != null) { 23489 if (mAttachInfo != null) { 23490 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 23491 Choreographer.CALLBACK_ANIMATION, what, who); 23492 } 23493 getRunQueue().removeCallbacks(what); 23494 } 23495 } 23496 23497 /** 23498 * Unschedule any events associated with the given Drawable. This can be 23499 * used when selecting a new Drawable into a view, so that the previous 23500 * one is completely unscheduled. 23501 * 23502 * @param who The Drawable to unschedule. 23503 * 23504 * @see #drawableStateChanged 23505 */ unscheduleDrawable(Drawable who)23506 public void unscheduleDrawable(Drawable who) { 23507 if (mAttachInfo != null && who != null) { 23508 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 23509 Choreographer.CALLBACK_ANIMATION, null, who); 23510 } 23511 } 23512 23513 /** 23514 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 23515 * that the View directionality can and will be resolved before its Drawables. 23516 * 23517 * Will call {@link View#onResolveDrawables} when resolution is done. 23518 * 23519 * @hide 23520 */ resolveDrawables()23521 protected void resolveDrawables() { 23522 // Drawables resolution may need to happen before resolving the layout direction (which is 23523 // done only during the measure() call). 23524 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 23525 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 23526 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 23527 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 23528 // direction to be resolved as its resolved value will be the same as its raw value. 23529 if (!isLayoutDirectionResolved() && 23530 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 23531 return; 23532 } 23533 23534 final int layoutDirection = isLayoutDirectionResolved() ? 23535 getLayoutDirection() : getRawLayoutDirection(); 23536 23537 if (mBackground != null) { 23538 mBackground.setLayoutDirection(layoutDirection); 23539 } 23540 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23541 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 23542 } 23543 if (mDefaultFocusHighlight != null) { 23544 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 23545 } 23546 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 23547 onResolveDrawables(layoutDirection); 23548 } 23549 areDrawablesResolved()23550 boolean areDrawablesResolved() { 23551 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 23552 } 23553 23554 /** 23555 * Called when layout direction has been resolved. 23556 * 23557 * The default implementation does nothing. 23558 * 23559 * @param layoutDirection The resolved layout direction. 23560 * 23561 * @see #LAYOUT_DIRECTION_LTR 23562 * @see #LAYOUT_DIRECTION_RTL 23563 * 23564 * @hide 23565 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)23566 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 23567 } 23568 23569 /** 23570 * @hide 23571 */ 23572 @TestApi resetResolvedDrawables()23573 protected void resetResolvedDrawables() { 23574 resetResolvedDrawablesInternal(); 23575 } 23576 resetResolvedDrawablesInternal()23577 void resetResolvedDrawablesInternal() { 23578 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 23579 } 23580 23581 /** 23582 * If your view subclass is displaying its own Drawable objects, it should 23583 * override this function and return true for any Drawable it is 23584 * displaying. This allows animations for those drawables to be 23585 * scheduled. 23586 * 23587 * <p>Be sure to call through to the super class when overriding this 23588 * function. 23589 * 23590 * @param who The Drawable to verify. Return true if it is one you are 23591 * displaying, else return the result of calling through to the 23592 * super class. 23593 * 23594 * @return boolean If true then the Drawable is being displayed in the 23595 * view; else false and it is not allowed to animate. 23596 * 23597 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 23598 * @see #drawableStateChanged() 23599 */ 23600 @CallSuper verifyDrawable(@onNull Drawable who)23601 protected boolean verifyDrawable(@NonNull Drawable who) { 23602 // Avoid verifying the scroll bar drawable so that we don't end up in 23603 // an invalidation loop. This effectively prevents the scroll bar 23604 // drawable from triggering invalidations and scheduling runnables. 23605 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 23606 || (mDefaultFocusHighlight == who); 23607 } 23608 23609 /** 23610 * This function is called whenever the state of the view changes in such 23611 * a way that it impacts the state of drawables being shown. 23612 * <p> 23613 * If the View has a StateListAnimator, it will also be called to run necessary state 23614 * change animations. 23615 * <p> 23616 * Be sure to call through to the superclass when overriding this function. 23617 * 23618 * @see Drawable#setState(int[]) 23619 */ 23620 @CallSuper drawableStateChanged()23621 protected void drawableStateChanged() { 23622 final int[] state = getDrawableState(); 23623 boolean changed = false; 23624 23625 final Drawable bg = mBackground; 23626 if (bg != null && bg.isStateful()) { 23627 changed |= bg.setState(state); 23628 } 23629 23630 final Drawable hl = mDefaultFocusHighlight; 23631 if (hl != null && hl.isStateful()) { 23632 changed |= hl.setState(state); 23633 } 23634 23635 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23636 if (fg != null && fg.isStateful()) { 23637 changed |= fg.setState(state); 23638 } 23639 23640 if (mScrollCache != null) { 23641 final Drawable scrollBar = mScrollCache.scrollBar; 23642 if (scrollBar != null && scrollBar.isStateful()) { 23643 changed |= scrollBar.setState(state) 23644 && mScrollCache.state != ScrollabilityCache.OFF; 23645 } 23646 } 23647 23648 if (mStateListAnimator != null) { 23649 mStateListAnimator.setState(state); 23650 } 23651 23652 if (!isAggregatedVisible()) { 23653 // If we're not visible, skip any animated changes 23654 jumpDrawablesToCurrentState(); 23655 } 23656 23657 if (changed) { 23658 invalidate(); 23659 } 23660 } 23661 23662 /** 23663 * This function is called whenever the view hotspot changes and needs to 23664 * be propagated to drawables or child views managed by the view. 23665 * <p> 23666 * Dispatching to child views is handled by 23667 * {@link #dispatchDrawableHotspotChanged(float, float)}. 23668 * <p> 23669 * Be sure to call through to the superclass when overriding this function. 23670 * 23671 * @param x hotspot x coordinate 23672 * @param y hotspot y coordinate 23673 */ 23674 @CallSuper drawableHotspotChanged(float x, float y)23675 public void drawableHotspotChanged(float x, float y) { 23676 if (mBackground != null) { 23677 mBackground.setHotspot(x, y); 23678 } 23679 if (mDefaultFocusHighlight != null) { 23680 mDefaultFocusHighlight.setHotspot(x, y); 23681 } 23682 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23683 mForegroundInfo.mDrawable.setHotspot(x, y); 23684 } 23685 23686 dispatchDrawableHotspotChanged(x, y); 23687 } 23688 23689 /** 23690 * Dispatches drawableHotspotChanged to all of this View's children. 23691 * 23692 * @param x hotspot x coordinate 23693 * @param y hotspot y coordinate 23694 * @see #drawableHotspotChanged(float, float) 23695 */ dispatchDrawableHotspotChanged(float x, float y)23696 public void dispatchDrawableHotspotChanged(float x, float y) { 23697 } 23698 23699 /** 23700 * Call this to force a view to update its drawable state. This will cause 23701 * drawableStateChanged to be called on this view. Views that are interested 23702 * in the new state should call getDrawableState. 23703 * 23704 * @see #drawableStateChanged 23705 * @see #getDrawableState 23706 */ refreshDrawableState()23707 public void refreshDrawableState() { 23708 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 23709 drawableStateChanged(); 23710 23711 ViewParent parent = mParent; 23712 if (parent != null) { 23713 parent.childDrawableStateChanged(this); 23714 } 23715 } 23716 23717 /** 23718 * Create a default focus highlight if it doesn't exist. 23719 * @return a default focus highlight. 23720 */ getDefaultFocusHighlightDrawable()23721 private Drawable getDefaultFocusHighlightDrawable() { 23722 if (mDefaultFocusHighlightCache == null) { 23723 if (mContext != null) { 23724 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 23725 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 23726 mDefaultFocusHighlightCache = ta.getDrawable(0); 23727 ta.recycle(); 23728 } 23729 } 23730 return mDefaultFocusHighlightCache; 23731 } 23732 23733 /** 23734 * Set the current default focus highlight. 23735 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 23736 */ setDefaultFocusHighlight(Drawable highlight)23737 private void setDefaultFocusHighlight(Drawable highlight) { 23738 mDefaultFocusHighlight = highlight; 23739 mDefaultFocusHighlightSizeChanged = true; 23740 if (highlight != null) { 23741 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23742 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23743 } 23744 highlight.setLayoutDirection(getLayoutDirection()); 23745 if (highlight.isStateful()) { 23746 highlight.setState(getDrawableState()); 23747 } 23748 if (isAttachedToWindow()) { 23749 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23750 } 23751 // Set callback last, since the view may still be initializing. 23752 highlight.setCallback(this); 23753 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23754 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 23755 mPrivateFlags |= PFLAG_SKIP_DRAW; 23756 } 23757 invalidate(); 23758 } 23759 23760 /** 23761 * Check whether we need to draw a default focus highlight when this view gets focused, 23762 * which requires: 23763 * <ul> 23764 * <li>In both background and foreground, {@link android.R.attr#state_focused} 23765 * is not defined.</li> 23766 * <li>This view is not in touch mode.</li> 23767 * <li>This view doesn't opt out for a default focus highlight, via 23768 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 23769 * <li>This view is attached to window.</li> 23770 * </ul> 23771 * @return {@code true} if a default focus highlight is needed. 23772 * @hide 23773 */ 23774 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)23775 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 23776 final boolean lackFocusState = (background == null || !background.isStateful() 23777 || !background.hasFocusStateSpecified()) 23778 && (foreground == null || !foreground.isStateful() 23779 || !foreground.hasFocusStateSpecified()); 23780 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 23781 && isAttachedToWindow() && sUseDefaultFocusHighlight; 23782 } 23783 23784 /** 23785 * When this view is focused, switches on/off the default focused highlight. 23786 * <p> 23787 * This always happens when this view is focused, and only at this moment the default focus 23788 * highlight can be visible. 23789 */ switchDefaultFocusHighlight()23790 private void switchDefaultFocusHighlight() { 23791 if (isFocused()) { 23792 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 23793 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 23794 final boolean active = mDefaultFocusHighlight != null; 23795 if (needed && !active) { 23796 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 23797 } else if (!needed && active) { 23798 // The highlight is no longer needed, so tear it down. 23799 setDefaultFocusHighlight(null); 23800 } 23801 } 23802 } 23803 23804 /** 23805 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 23806 * @param canvas the canvas where we're drawing the highlight. 23807 */ drawDefaultFocusHighlight(Canvas canvas)23808 private void drawDefaultFocusHighlight(Canvas canvas) { 23809 if (mDefaultFocusHighlight != null && isFocused()) { 23810 if (mDefaultFocusHighlightSizeChanged) { 23811 mDefaultFocusHighlightSizeChanged = false; 23812 final int l = mScrollX; 23813 final int r = l + mRight - mLeft; 23814 final int t = mScrollY; 23815 final int b = t + mBottom - mTop; 23816 mDefaultFocusHighlight.setBounds(l, t, r, b); 23817 } 23818 mDefaultFocusHighlight.draw(canvas); 23819 } 23820 } 23821 23822 /** 23823 * Return an array of resource IDs of the drawable states representing the 23824 * current state of the view. 23825 * 23826 * @return The current drawable state 23827 * 23828 * @see Drawable#setState(int[]) 23829 * @see #drawableStateChanged() 23830 * @see #onCreateDrawableState(int) 23831 */ getDrawableState()23832 public final int[] getDrawableState() { 23833 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 23834 return mDrawableState; 23835 } else { 23836 mDrawableState = onCreateDrawableState(0); 23837 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 23838 return mDrawableState; 23839 } 23840 } 23841 23842 /** 23843 * Generate the new {@link android.graphics.drawable.Drawable} state for 23844 * this view. This is called by the view 23845 * system when the cached Drawable state is determined to be invalid. To 23846 * retrieve the current state, you should use {@link #getDrawableState}. 23847 * 23848 * @param extraSpace if non-zero, this is the number of extra entries you 23849 * would like in the returned array in which you can place your own 23850 * states. 23851 * 23852 * @return Returns an array holding the current {@link Drawable} state of 23853 * the view. 23854 * 23855 * @see #mergeDrawableStates(int[], int[]) 23856 */ onCreateDrawableState(int extraSpace)23857 protected int[] onCreateDrawableState(int extraSpace) { 23858 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 23859 mParent instanceof View) { 23860 return ((View) mParent).onCreateDrawableState(extraSpace); 23861 } 23862 23863 int[] drawableState; 23864 23865 int privateFlags = mPrivateFlags; 23866 23867 int viewStateIndex = 0; 23868 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 23869 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 23870 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 23871 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 23872 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 23873 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 23874 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { 23875 // This is set if HW acceleration is requested, even if the current 23876 // process doesn't allow it. This is just to allow app preview 23877 // windows to better match their app. 23878 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 23879 } 23880 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 23881 23882 final int privateFlags2 = mPrivateFlags2; 23883 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 23884 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 23885 } 23886 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 23887 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 23888 } 23889 23890 drawableState = StateSet.get(viewStateIndex); 23891 23892 //noinspection ConstantIfStatement 23893 if (false) { 23894 Log.i("View", "drawableStateIndex=" + viewStateIndex); 23895 Log.i("View", toString() 23896 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 23897 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 23898 + " fo=" + hasFocus() 23899 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 23900 + " wf=" + hasWindowFocus() 23901 + ": " + Arrays.toString(drawableState)); 23902 } 23903 23904 if (extraSpace == 0) { 23905 return drawableState; 23906 } 23907 23908 final int[] fullState; 23909 if (drawableState != null) { 23910 fullState = new int[drawableState.length + extraSpace]; 23911 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 23912 } else { 23913 fullState = new int[extraSpace]; 23914 } 23915 23916 return fullState; 23917 } 23918 23919 /** 23920 * Merge your own state values in <var>additionalState</var> into the base 23921 * state values <var>baseState</var> that were returned by 23922 * {@link #onCreateDrawableState(int)}. 23923 * 23924 * @param baseState The base state values returned by 23925 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 23926 * own additional state values. 23927 * 23928 * @param additionalState The additional state values you would like 23929 * added to <var>baseState</var>; this array is not modified. 23930 * 23931 * @return As a convenience, the <var>baseState</var> array you originally 23932 * passed into the function is returned. 23933 * 23934 * @see #onCreateDrawableState(int) 23935 */ mergeDrawableStates(int[] baseState, int[] additionalState)23936 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 23937 final int N = baseState.length; 23938 int i = N - 1; 23939 while (i >= 0 && baseState[i] == 0) { 23940 i--; 23941 } 23942 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 23943 return baseState; 23944 } 23945 23946 /** 23947 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 23948 * on all Drawable objects associated with this view. 23949 * <p> 23950 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 23951 * attached to this view. 23952 */ 23953 @CallSuper jumpDrawablesToCurrentState()23954 public void jumpDrawablesToCurrentState() { 23955 if (mBackground != null) { 23956 mBackground.jumpToCurrentState(); 23957 } 23958 if (mStateListAnimator != null) { 23959 mStateListAnimator.jumpToCurrentState(); 23960 } 23961 if (mDefaultFocusHighlight != null) { 23962 mDefaultFocusHighlight.jumpToCurrentState(); 23963 } 23964 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23965 mForegroundInfo.mDrawable.jumpToCurrentState(); 23966 } 23967 } 23968 23969 /** 23970 * Sets the background color for this view. 23971 * @param color the color of the background 23972 */ 23973 @RemotableViewMethod setBackgroundColor(@olorInt int color)23974 public void setBackgroundColor(@ColorInt int color) { 23975 if (mBackground instanceof ColorDrawable) { 23976 ((ColorDrawable) mBackground.mutate()).setColor(color); 23977 computeOpaqueFlags(); 23978 mBackgroundResource = 0; 23979 } else { 23980 setBackground(new ColorDrawable(color)); 23981 } 23982 } 23983 23984 /** 23985 * Set the background to a given resource. The resource should refer to 23986 * a Drawable object or 0 to remove the background. 23987 * @param resid The identifier of the resource. 23988 * 23989 * @attr ref android.R.styleable#View_background 23990 */ 23991 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)23992 public void setBackgroundResource(@DrawableRes int resid) { 23993 if (resid != 0 && resid == mBackgroundResource) { 23994 return; 23995 } 23996 23997 Drawable d = null; 23998 if (resid != 0) { 23999 d = mContext.getDrawable(resid); 24000 } 24001 setBackground(d); 24002 24003 mBackgroundResource = resid; 24004 } 24005 24006 /** 24007 * Set the background to a given Drawable, or remove the background. If the 24008 * background has padding, this View's padding is set to the background's 24009 * padding. However, when a background is removed, this View's padding isn't 24010 * touched. If setting the padding is desired, please use 24011 * {@link #setPadding(int, int, int, int)}. 24012 * 24013 * @param background The Drawable to use as the background, or null to remove the 24014 * background 24015 */ setBackground(Drawable background)24016 public void setBackground(Drawable background) { 24017 //noinspection deprecation 24018 setBackgroundDrawable(background); 24019 } 24020 24021 /** 24022 * @deprecated use {@link #setBackground(Drawable)} instead 24023 */ 24024 @Deprecated setBackgroundDrawable(Drawable background)24025 public void setBackgroundDrawable(Drawable background) { 24026 computeOpaqueFlags(); 24027 24028 if (background == mBackground) { 24029 return; 24030 } 24031 24032 boolean requestLayout = false; 24033 24034 mBackgroundResource = 0; 24035 24036 /* 24037 * Regardless of whether we're setting a new background or not, we want 24038 * to clear the previous drawable. setVisible first while we still have the callback set. 24039 */ 24040 if (mBackground != null) { 24041 if (isAttachedToWindow()) { 24042 mBackground.setVisible(false, false); 24043 } 24044 mBackground.setCallback(null); 24045 unscheduleDrawable(mBackground); 24046 } 24047 24048 if (background != null) { 24049 Rect padding = sThreadLocal.get(); 24050 if (padding == null) { 24051 padding = new Rect(); 24052 sThreadLocal.set(padding); 24053 } 24054 resetResolvedDrawablesInternal(); 24055 background.setLayoutDirection(getLayoutDirection()); 24056 if (background.getPadding(padding)) { 24057 resetResolvedPaddingInternal(); 24058 switch (background.getLayoutDirection()) { 24059 case LAYOUT_DIRECTION_RTL: 24060 mUserPaddingLeftInitial = padding.right; 24061 mUserPaddingRightInitial = padding.left; 24062 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 24063 break; 24064 case LAYOUT_DIRECTION_LTR: 24065 default: 24066 mUserPaddingLeftInitial = padding.left; 24067 mUserPaddingRightInitial = padding.right; 24068 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 24069 } 24070 mLeftPaddingDefined = false; 24071 mRightPaddingDefined = false; 24072 } 24073 24074 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 24075 // if it has a different minimum size, we should layout again 24076 if (mBackground == null 24077 || mBackground.getMinimumHeight() != background.getMinimumHeight() 24078 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 24079 requestLayout = true; 24080 } 24081 24082 // Set mBackground before we set this as the callback and start making other 24083 // background drawable state change calls. In particular, the setVisible call below 24084 // can result in drawables attempting to start animations or otherwise invalidate, 24085 // which requires the view set as the callback (us) to recognize the drawable as 24086 // belonging to it as per verifyDrawable. 24087 mBackground = background; 24088 if (background.isStateful()) { 24089 background.setState(getDrawableState()); 24090 } 24091 if (isAttachedToWindow()) { 24092 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24093 } 24094 24095 applyBackgroundTint(); 24096 24097 // Set callback last, since the view may still be initializing. 24098 background.setCallback(this); 24099 24100 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24101 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24102 requestLayout = true; 24103 } 24104 } else { 24105 /* Remove the background */ 24106 mBackground = null; 24107 if ((mViewFlags & WILL_NOT_DRAW) != 0 24108 && (mDefaultFocusHighlight == null) 24109 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 24110 mPrivateFlags |= PFLAG_SKIP_DRAW; 24111 } 24112 24113 /* 24114 * When the background is set, we try to apply its padding to this 24115 * View. When the background is removed, we don't touch this View's 24116 * padding. This is noted in the Javadocs. Hence, we don't need to 24117 * requestLayout(), the invalidate() below is sufficient. 24118 */ 24119 24120 // The old background's minimum size could have affected this 24121 // View's layout, so let's requestLayout 24122 requestLayout = true; 24123 } 24124 24125 computeOpaqueFlags(); 24126 24127 if (requestLayout) { 24128 requestLayout(); 24129 } 24130 24131 mBackgroundSizeChanged = true; 24132 invalidate(true); 24133 invalidateOutline(); 24134 } 24135 24136 /** 24137 * Gets the background drawable 24138 * 24139 * @return The drawable used as the background for this view, if any. 24140 * 24141 * @see #setBackground(Drawable) 24142 * 24143 * @attr ref android.R.styleable#View_background 24144 */ 24145 @InspectableProperty getBackground()24146 public Drawable getBackground() { 24147 return mBackground; 24148 } 24149 24150 /** 24151 * Applies a tint to the background drawable. Does not modify the current tint 24152 * mode, which is {@link BlendMode#SRC_IN} by default. 24153 * <p> 24154 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 24155 * mutate the drawable and apply the specified tint and tint mode using 24156 * {@link Drawable#setTintList(ColorStateList)}. 24157 * 24158 * @param tint the tint to apply, may be {@code null} to clear tint 24159 * 24160 * @attr ref android.R.styleable#View_backgroundTint 24161 * @see #getBackgroundTintList() 24162 * @see Drawable#setTintList(ColorStateList) 24163 */ 24164 @RemotableViewMethod setBackgroundTintList(@ullable ColorStateList tint)24165 public void setBackgroundTintList(@Nullable ColorStateList tint) { 24166 if (mBackgroundTint == null) { 24167 mBackgroundTint = new TintInfo(); 24168 } 24169 mBackgroundTint.mTintList = tint; 24170 mBackgroundTint.mHasTintList = true; 24171 24172 applyBackgroundTint(); 24173 } 24174 24175 /** 24176 * Return the tint applied to the background drawable, if specified. 24177 * 24178 * @return the tint applied to the background drawable 24179 * @attr ref android.R.styleable#View_backgroundTint 24180 * @see #setBackgroundTintList(ColorStateList) 24181 */ 24182 @InspectableProperty(name = "backgroundTint") 24183 @Nullable getBackgroundTintList()24184 public ColorStateList getBackgroundTintList() { 24185 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 24186 } 24187 24188 /** 24189 * Specifies the blending mode used to apply the tint specified by 24190 * {@link #setBackgroundTintList(ColorStateList)}} to the background 24191 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 24192 * 24193 * @param tintMode the blending mode used to apply the tint, may be 24194 * {@code null} to clear tint 24195 * @attr ref android.R.styleable#View_backgroundTintMode 24196 * @see #getBackgroundTintMode() 24197 * @see Drawable#setTintMode(PorterDuff.Mode) 24198 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)24199 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 24200 BlendMode mode = null; 24201 if (tintMode != null) { 24202 mode = BlendMode.fromValue(tintMode.nativeInt); 24203 } 24204 24205 setBackgroundTintBlendMode(mode); 24206 } 24207 24208 /** 24209 * Specifies the blending mode used to apply the tint specified by 24210 * {@link #setBackgroundTintList(ColorStateList)}} to the background 24211 * drawable. The default mode is {@link BlendMode#SRC_IN}. 24212 * 24213 * @param blendMode the blending mode used to apply the tint, may be 24214 * {@code null} to clear tint 24215 * @attr ref android.R.styleable#View_backgroundTintMode 24216 * @see #getBackgroundTintMode() 24217 * @see Drawable#setTintBlendMode(BlendMode) 24218 */ 24219 @RemotableViewMethod setBackgroundTintBlendMode(@ullable BlendMode blendMode)24220 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 24221 if (mBackgroundTint == null) { 24222 mBackgroundTint = new TintInfo(); 24223 } 24224 24225 mBackgroundTint.mBlendMode = blendMode; 24226 mBackgroundTint.mHasTintMode = true; 24227 24228 applyBackgroundTint(); 24229 } 24230 24231 /** 24232 * Return the blending mode used to apply the tint to the background 24233 * drawable, if specified. 24234 * 24235 * @return the blending mode used to apply the tint to the background 24236 * drawable 24237 * @attr ref android.R.styleable#View_backgroundTintMode 24238 * @see #setBackgroundTintBlendMode(BlendMode) 24239 * 24240 */ 24241 @Nullable 24242 @InspectableProperty getBackgroundTintMode()24243 public PorterDuff.Mode getBackgroundTintMode() { 24244 PorterDuff.Mode porterDuffMode; 24245 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 24246 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 24247 } else { 24248 porterDuffMode = null; 24249 } 24250 return porterDuffMode; 24251 } 24252 24253 /** 24254 * Return the blending mode used to apply the tint to the background 24255 * drawable, if specified. 24256 * 24257 * @return the blending mode used to apply the tint to the background 24258 * drawable, null if no blend has previously been configured 24259 * @attr ref android.R.styleable#View_backgroundTintMode 24260 * @see #setBackgroundTintBlendMode(BlendMode) 24261 */ getBackgroundTintBlendMode()24262 public @Nullable BlendMode getBackgroundTintBlendMode() { 24263 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 24264 } 24265 applyBackgroundTint()24266 private void applyBackgroundTint() { 24267 if (mBackground != null && mBackgroundTint != null) { 24268 final TintInfo tintInfo = mBackgroundTint; 24269 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 24270 mBackground = mBackground.mutate(); 24271 24272 if (tintInfo.mHasTintList) { 24273 mBackground.setTintList(tintInfo.mTintList); 24274 } 24275 24276 if (tintInfo.mHasTintMode) { 24277 mBackground.setTintBlendMode(tintInfo.mBlendMode); 24278 } 24279 24280 // The drawable (or one of its children) may not have been 24281 // stateful before applying the tint, so let's try again. 24282 if (mBackground.isStateful()) { 24283 mBackground.setState(getDrawableState()); 24284 } 24285 } 24286 } 24287 } 24288 24289 /** 24290 * Returns the drawable used as the foreground of this View. The 24291 * foreground drawable, if non-null, is always drawn on top of the view's content. 24292 * 24293 * @return a Drawable or null if no foreground was set 24294 * 24295 * @see #onDrawForeground(Canvas) 24296 */ 24297 @InspectableProperty getForeground()24298 public Drawable getForeground() { 24299 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24300 } 24301 24302 /** 24303 * Supply a Drawable that is to be rendered on top of all of the content in the view. 24304 * 24305 * @param foreground the Drawable to be drawn on top of the children 24306 * 24307 * @attr ref android.R.styleable#View_foreground 24308 */ setForeground(Drawable foreground)24309 public void setForeground(Drawable foreground) { 24310 if (mForegroundInfo == null) { 24311 if (foreground == null) { 24312 // Nothing to do. 24313 return; 24314 } 24315 mForegroundInfo = new ForegroundInfo(); 24316 } 24317 24318 if (foreground == mForegroundInfo.mDrawable) { 24319 // Nothing to do 24320 return; 24321 } 24322 24323 if (mForegroundInfo.mDrawable != null) { 24324 if (isAttachedToWindow()) { 24325 mForegroundInfo.mDrawable.setVisible(false, false); 24326 } 24327 mForegroundInfo.mDrawable.setCallback(null); 24328 unscheduleDrawable(mForegroundInfo.mDrawable); 24329 } 24330 24331 mForegroundInfo.mDrawable = foreground; 24332 mForegroundInfo.mBoundsChanged = true; 24333 if (foreground != null) { 24334 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24335 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24336 } 24337 foreground.setLayoutDirection(getLayoutDirection()); 24338 if (foreground.isStateful()) { 24339 foreground.setState(getDrawableState()); 24340 } 24341 applyForegroundTint(); 24342 if (isAttachedToWindow()) { 24343 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24344 } 24345 // Set callback last, since the view may still be initializing. 24346 foreground.setCallback(this); 24347 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 24348 && (mDefaultFocusHighlight == null)) { 24349 mPrivateFlags |= PFLAG_SKIP_DRAW; 24350 } 24351 requestLayout(); 24352 invalidate(); 24353 } 24354 24355 /** 24356 * Magic bit used to support features of framework-internal window decor implementation details. 24357 * This used to live exclusively in FrameLayout. 24358 * 24359 * @return true if the foreground should draw inside the padding region or false 24360 * if it should draw inset by the view's padding 24361 * @hide internal use only; only used by FrameLayout and internal screen layouts. 24362 */ isForegroundInsidePadding()24363 public boolean isForegroundInsidePadding() { 24364 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 24365 } 24366 24367 /** 24368 * Describes how the foreground is positioned. 24369 * 24370 * @return foreground gravity. 24371 * 24372 * @see #setForegroundGravity(int) 24373 * 24374 * @attr ref android.R.styleable#View_foregroundGravity 24375 */ 24376 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()24377 public int getForegroundGravity() { 24378 return mForegroundInfo != null ? mForegroundInfo.mGravity 24379 : Gravity.START | Gravity.TOP; 24380 } 24381 24382 /** 24383 * Describes how the foreground is positioned. Defaults to START and TOP. 24384 * 24385 * @param gravity see {@link android.view.Gravity} 24386 * 24387 * @see #getForegroundGravity() 24388 * 24389 * @attr ref android.R.styleable#View_foregroundGravity 24390 */ setForegroundGravity(int gravity)24391 public void setForegroundGravity(int gravity) { 24392 if (mForegroundInfo == null) { 24393 mForegroundInfo = new ForegroundInfo(); 24394 } 24395 24396 if (mForegroundInfo.mGravity != gravity) { 24397 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 24398 gravity |= Gravity.START; 24399 } 24400 24401 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 24402 gravity |= Gravity.TOP; 24403 } 24404 24405 mForegroundInfo.mGravity = gravity; 24406 requestLayout(); 24407 } 24408 } 24409 24410 /** 24411 * Applies a tint to the foreground drawable. Does not modify the current tint 24412 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 24413 * <p> 24414 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 24415 * mutate the drawable and apply the specified tint and tint mode using 24416 * {@link Drawable#setTintList(ColorStateList)}. 24417 * 24418 * @param tint the tint to apply, may be {@code null} to clear tint 24419 * 24420 * @attr ref android.R.styleable#View_foregroundTint 24421 * @see #getForegroundTintList() 24422 * @see Drawable#setTintList(ColorStateList) 24423 */ 24424 @RemotableViewMethod setForegroundTintList(@ullable ColorStateList tint)24425 public void setForegroundTintList(@Nullable ColorStateList tint) { 24426 if (mForegroundInfo == null) { 24427 mForegroundInfo = new ForegroundInfo(); 24428 } 24429 if (mForegroundInfo.mTintInfo == null) { 24430 mForegroundInfo.mTintInfo = new TintInfo(); 24431 } 24432 mForegroundInfo.mTintInfo.mTintList = tint; 24433 mForegroundInfo.mTintInfo.mHasTintList = true; 24434 24435 applyForegroundTint(); 24436 } 24437 24438 /** 24439 * Return the tint applied to the foreground drawable, if specified. 24440 * 24441 * @return the tint applied to the foreground drawable 24442 * @attr ref android.R.styleable#View_foregroundTint 24443 * @see #setForegroundTintList(ColorStateList) 24444 */ 24445 @InspectableProperty(name = "foregroundTint") 24446 @Nullable getForegroundTintList()24447 public ColorStateList getForegroundTintList() { 24448 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24449 ? mForegroundInfo.mTintInfo.mTintList : null; 24450 } 24451 24452 /** 24453 * Specifies the blending mode used to apply the tint specified by 24454 * {@link #setForegroundTintList(ColorStateList)}} to the background 24455 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 24456 * 24457 * @param tintMode the blending mode used to apply the tint, may be 24458 * {@code null} to clear tint 24459 * @attr ref android.R.styleable#View_foregroundTintMode 24460 * @see #getForegroundTintMode() 24461 * @see Drawable#setTintMode(PorterDuff.Mode) 24462 * 24463 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)24464 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 24465 BlendMode mode = null; 24466 if (tintMode != null) { 24467 mode = BlendMode.fromValue(tintMode.nativeInt); 24468 } 24469 setForegroundTintBlendMode(mode); 24470 } 24471 24472 /** 24473 * Specifies the blending mode used to apply the tint specified by 24474 * {@link #setForegroundTintList(ColorStateList)}} to the background 24475 * drawable. The default mode is {@link BlendMode#SRC_IN}. 24476 * 24477 * @param blendMode the blending mode used to apply the tint, may be 24478 * {@code null} to clear tint 24479 * @attr ref android.R.styleable#View_foregroundTintMode 24480 * @see #getForegroundTintMode() 24481 * @see Drawable#setTintBlendMode(BlendMode) 24482 */ 24483 @RemotableViewMethod setForegroundTintBlendMode(@ullable BlendMode blendMode)24484 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 24485 if (mForegroundInfo == null) { 24486 mForegroundInfo = new ForegroundInfo(); 24487 } 24488 if (mForegroundInfo.mTintInfo == null) { 24489 mForegroundInfo.mTintInfo = new TintInfo(); 24490 } 24491 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 24492 mForegroundInfo.mTintInfo.mHasTintMode = true; 24493 24494 applyForegroundTint(); 24495 } 24496 24497 /** 24498 * Return the blending mode used to apply the tint to the foreground 24499 * drawable, if specified. 24500 * 24501 * @return the blending mode used to apply the tint to the foreground 24502 * drawable 24503 * @attr ref android.R.styleable#View_foregroundTintMode 24504 * @see #setForegroundTintMode(PorterDuff.Mode) 24505 */ 24506 @InspectableProperty 24507 @Nullable getForegroundTintMode()24508 public PorterDuff.Mode getForegroundTintMode() { 24509 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24510 ? mForegroundInfo.mTintInfo.mBlendMode : null; 24511 if (blendMode != null) { 24512 return BlendMode.blendModeToPorterDuffMode(blendMode); 24513 } else { 24514 return null; 24515 } 24516 } 24517 24518 /** 24519 * Return the blending mode used to apply the tint to the foreground 24520 * drawable, if specified. 24521 * 24522 * @return the blending mode used to apply the tint to the foreground 24523 * drawable 24524 * @attr ref android.R.styleable#View_foregroundTintMode 24525 * @see #setForegroundTintBlendMode(BlendMode) 24526 * 24527 */ getForegroundTintBlendMode()24528 public @Nullable BlendMode getForegroundTintBlendMode() { 24529 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24530 ? mForegroundInfo.mTintInfo.mBlendMode : null; 24531 } 24532 applyForegroundTint()24533 private void applyForegroundTint() { 24534 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 24535 && mForegroundInfo.mTintInfo != null) { 24536 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 24537 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 24538 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 24539 24540 if (tintInfo.mHasTintList) { 24541 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 24542 } 24543 24544 if (tintInfo.mHasTintMode) { 24545 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 24546 } 24547 24548 // The drawable (or one of its children) may not have been 24549 // stateful before applying the tint, so let's try again. 24550 if (mForegroundInfo.mDrawable.isStateful()) { 24551 mForegroundInfo.mDrawable.setState(getDrawableState()); 24552 } 24553 } 24554 } 24555 } 24556 24557 /** 24558 * Get the drawable to be overlayed when a view is autofilled 24559 * 24560 * @return The drawable 24561 * 24562 * @throws IllegalStateException if the drawable could not be found. 24563 */ getAutofilledDrawable()24564 @Nullable private Drawable getAutofilledDrawable() { 24565 if (mAttachInfo == null) { 24566 return null; 24567 } 24568 // Lazily load the isAutofilled drawable. 24569 if (mAttachInfo.mAutofilledDrawable == null) { 24570 Context rootContext = getRootView().getContext(); 24571 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 24572 int attributeResourceId = a.getResourceId(0, 0); 24573 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 24574 a.recycle(); 24575 } 24576 24577 return mAttachInfo.mAutofilledDrawable; 24578 } 24579 24580 /** 24581 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 24582 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 24583 * 24584 * @param canvas The canvas to draw on 24585 */ drawAutofilledHighlight(@onNull Canvas canvas)24586 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 24587 if (isAutofilled() && !hideAutofillHighlight()) { 24588 Drawable autofilledHighlight = getAutofilledDrawable(); 24589 24590 if (autofilledHighlight != null) { 24591 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 24592 autofilledHighlight.draw(canvas); 24593 } 24594 } 24595 } 24596 24597 /** 24598 * Draw any foreground content for this view. 24599 * 24600 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 24601 * drawable or other view-specific decorations. The foreground is drawn on top of the 24602 * primary view content.</p> 24603 * 24604 * @param canvas canvas to draw into 24605 */ onDrawForeground(Canvas canvas)24606 public void onDrawForeground(Canvas canvas) { 24607 onDrawScrollIndicators(canvas); 24608 onDrawScrollBars(canvas); 24609 24610 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24611 if (foreground != null) { 24612 if (mForegroundInfo.mBoundsChanged) { 24613 mForegroundInfo.mBoundsChanged = false; 24614 final Rect selfBounds = mForegroundInfo.mSelfBounds; 24615 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 24616 24617 if (mForegroundInfo.mInsidePadding) { 24618 selfBounds.set(0, 0, getWidth(), getHeight()); 24619 } else { 24620 selfBounds.set(getPaddingLeft(), getPaddingTop(), 24621 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 24622 } 24623 24624 final int ld = getLayoutDirection(); 24625 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 24626 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 24627 foreground.setBounds(overlayBounds); 24628 } 24629 24630 foreground.draw(canvas); 24631 } 24632 } 24633 24634 /** 24635 * Sets the padding. The view may add on the space required to display 24636 * the scrollbars, depending on the style and visibility of the scrollbars. 24637 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 24638 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 24639 * from the values set in this call. 24640 * 24641 * @attr ref android.R.styleable#View_padding 24642 * @attr ref android.R.styleable#View_paddingBottom 24643 * @attr ref android.R.styleable#View_paddingLeft 24644 * @attr ref android.R.styleable#View_paddingRight 24645 * @attr ref android.R.styleable#View_paddingTop 24646 * @param left the left padding in pixels 24647 * @param top the top padding in pixels 24648 * @param right the right padding in pixels 24649 * @param bottom the bottom padding in pixels 24650 */ setPadding(int left, int top, int right, int bottom)24651 public void setPadding(int left, int top, int right, int bottom) { 24652 resetResolvedPaddingInternal(); 24653 24654 mUserPaddingStart = UNDEFINED_PADDING; 24655 mUserPaddingEnd = UNDEFINED_PADDING; 24656 24657 mUserPaddingLeftInitial = left; 24658 mUserPaddingRightInitial = right; 24659 24660 mLeftPaddingDefined = true; 24661 mRightPaddingDefined = true; 24662 24663 internalSetPadding(left, top, right, bottom); 24664 } 24665 24666 /** 24667 * @hide 24668 */ 24669 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)24670 protected void internalSetPadding(int left, int top, int right, int bottom) { 24671 mUserPaddingLeft = left; 24672 mUserPaddingRight = right; 24673 mUserPaddingBottom = bottom; 24674 24675 final int viewFlags = mViewFlags; 24676 boolean changed = false; 24677 24678 // Common case is there are no scroll bars. 24679 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 24680 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 24681 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 24682 ? 0 : getVerticalScrollbarWidth(); 24683 switch (mVerticalScrollbarPosition) { 24684 case SCROLLBAR_POSITION_DEFAULT: 24685 if (isLayoutRtl()) { 24686 left += offset; 24687 } else { 24688 right += offset; 24689 } 24690 break; 24691 case SCROLLBAR_POSITION_RIGHT: 24692 right += offset; 24693 break; 24694 case SCROLLBAR_POSITION_LEFT: 24695 left += offset; 24696 break; 24697 } 24698 } 24699 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 24700 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 24701 ? 0 : getHorizontalScrollbarHeight(); 24702 } 24703 } 24704 24705 if (mPaddingLeft != left) { 24706 changed = true; 24707 mPaddingLeft = left; 24708 } 24709 if (mPaddingTop != top) { 24710 changed = true; 24711 mPaddingTop = top; 24712 } 24713 if (mPaddingRight != right) { 24714 changed = true; 24715 mPaddingRight = right; 24716 } 24717 if (mPaddingBottom != bottom) { 24718 changed = true; 24719 mPaddingBottom = bottom; 24720 } 24721 24722 if (changed) { 24723 requestLayout(); 24724 invalidateOutline(); 24725 } 24726 } 24727 24728 /** 24729 * Sets the relative padding. The view may add on the space required to display 24730 * the scrollbars, depending on the style and visibility of the scrollbars. 24731 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 24732 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 24733 * from the values set in this call. 24734 * 24735 * @attr ref android.R.styleable#View_padding 24736 * @attr ref android.R.styleable#View_paddingBottom 24737 * @attr ref android.R.styleable#View_paddingStart 24738 * @attr ref android.R.styleable#View_paddingEnd 24739 * @attr ref android.R.styleable#View_paddingTop 24740 * @param start the start padding in pixels 24741 * @param top the top padding in pixels 24742 * @param end the end padding in pixels 24743 * @param bottom the bottom padding in pixels 24744 */ setPaddingRelative(int start, int top, int end, int bottom)24745 public void setPaddingRelative(int start, int top, int end, int bottom) { 24746 resetResolvedPaddingInternal(); 24747 24748 mUserPaddingStart = start; 24749 mUserPaddingEnd = end; 24750 mLeftPaddingDefined = true; 24751 mRightPaddingDefined = true; 24752 24753 switch(getLayoutDirection()) { 24754 case LAYOUT_DIRECTION_RTL: 24755 mUserPaddingLeftInitial = end; 24756 mUserPaddingRightInitial = start; 24757 internalSetPadding(end, top, start, bottom); 24758 break; 24759 case LAYOUT_DIRECTION_LTR: 24760 default: 24761 mUserPaddingLeftInitial = start; 24762 mUserPaddingRightInitial = end; 24763 internalSetPadding(start, top, end, bottom); 24764 } 24765 } 24766 24767 /** 24768 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 24769 * resource ID of the source layout. 24770 * 24771 * @return The layout resource id if this view was inflated from XML, otherwise 24772 * {@link Resources#ID_NULL}. 24773 */ 24774 @LayoutRes getSourceLayoutResId()24775 public int getSourceLayoutResId() { 24776 return mSourceLayoutId; 24777 } 24778 24779 /** 24780 * Returns the top padding of this view. 24781 * 24782 * @return the top padding in pixels 24783 */ 24784 @InspectableProperty getPaddingTop()24785 public int getPaddingTop() { 24786 return mPaddingTop; 24787 } 24788 24789 /** 24790 * Returns the bottom padding of this view. If there are inset and enabled 24791 * scrollbars, this value may include the space required to display the 24792 * scrollbars as well. 24793 * 24794 * @return the bottom padding in pixels 24795 */ 24796 @InspectableProperty getPaddingBottom()24797 public int getPaddingBottom() { 24798 return mPaddingBottom; 24799 } 24800 24801 /** 24802 * Returns the left padding of this view. If there are inset and enabled 24803 * scrollbars, this value may include the space required to display the 24804 * scrollbars as well. 24805 * 24806 * @return the left padding in pixels 24807 */ 24808 @InspectableProperty getPaddingLeft()24809 public int getPaddingLeft() { 24810 if (!isPaddingResolved()) { 24811 resolvePadding(); 24812 } 24813 return mPaddingLeft; 24814 } 24815 24816 /** 24817 * Returns the start padding of this view depending on its resolved layout direction. 24818 * If there are inset and enabled scrollbars, this value may include the space 24819 * required to display the scrollbars as well. 24820 * 24821 * @return the start padding in pixels 24822 */ getPaddingStart()24823 public int getPaddingStart() { 24824 if (!isPaddingResolved()) { 24825 resolvePadding(); 24826 } 24827 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24828 mPaddingRight : mPaddingLeft; 24829 } 24830 24831 /** 24832 * Returns the right padding of this view. If there are inset and enabled 24833 * scrollbars, this value may include the space required to display the 24834 * scrollbars as well. 24835 * 24836 * @return the right padding in pixels 24837 */ 24838 @InspectableProperty getPaddingRight()24839 public int getPaddingRight() { 24840 if (!isPaddingResolved()) { 24841 resolvePadding(); 24842 } 24843 return mPaddingRight; 24844 } 24845 24846 /** 24847 * Returns the end padding of this view depending on its resolved layout direction. 24848 * If there are inset and enabled scrollbars, this value may include the space 24849 * required to display the scrollbars as well. 24850 * 24851 * @return the end padding in pixels 24852 */ getPaddingEnd()24853 public int getPaddingEnd() { 24854 if (!isPaddingResolved()) { 24855 resolvePadding(); 24856 } 24857 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24858 mPaddingLeft : mPaddingRight; 24859 } 24860 24861 /** 24862 * Return if the padding has been set through relative values 24863 * {@link #setPaddingRelative(int, int, int, int)} or through 24864 * @attr ref android.R.styleable#View_paddingStart or 24865 * @attr ref android.R.styleable#View_paddingEnd 24866 * 24867 * @return true if the padding is relative or false if it is not. 24868 */ isPaddingRelative()24869 public boolean isPaddingRelative() { 24870 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 24871 } 24872 computeOpticalInsets()24873 Insets computeOpticalInsets() { 24874 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 24875 } 24876 24877 /** 24878 * @hide 24879 */ 24880 @UnsupportedAppUsage resetPaddingToInitialValues()24881 public void resetPaddingToInitialValues() { 24882 if (isRtlCompatibilityMode()) { 24883 mPaddingLeft = mUserPaddingLeftInitial; 24884 mPaddingRight = mUserPaddingRightInitial; 24885 return; 24886 } 24887 if (isLayoutRtl()) { 24888 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 24889 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 24890 } else { 24891 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 24892 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 24893 } 24894 } 24895 24896 /** 24897 * @hide 24898 */ getOpticalInsets()24899 public Insets getOpticalInsets() { 24900 if (mLayoutInsets == null) { 24901 mLayoutInsets = computeOpticalInsets(); 24902 } 24903 return mLayoutInsets; 24904 } 24905 24906 /** 24907 * Set this view's optical insets. 24908 * 24909 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 24910 * property. Views that compute their own optical insets should call it as part of measurement. 24911 * This method does not request layout. If you are setting optical insets outside of 24912 * measure/layout itself you will want to call requestLayout() yourself. 24913 * </p> 24914 * @hide 24915 */ setOpticalInsets(Insets insets)24916 public void setOpticalInsets(Insets insets) { 24917 mLayoutInsets = insets; 24918 } 24919 24920 /** 24921 * Changes the selection state of this view. A view can be selected or not. 24922 * Note that selection is not the same as focus. Views are typically 24923 * selected in the context of an AdapterView like ListView or GridView; 24924 * the selected view is the view that is highlighted. 24925 * 24926 * @param selected true if the view must be selected, false otherwise 24927 */ setSelected(boolean selected)24928 public void setSelected(boolean selected) { 24929 //noinspection DoubleNegation 24930 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 24931 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 24932 if (!selected) resetPressedState(); 24933 invalidate(true); 24934 refreshDrawableState(); 24935 dispatchSetSelected(selected); 24936 if (selected) { 24937 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 24938 } else { 24939 notifyViewAccessibilityStateChangedIfNeeded( 24940 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 24941 } 24942 } 24943 } 24944 24945 /** 24946 * Dispatch setSelected to all of this View's children. 24947 * 24948 * @see #setSelected(boolean) 24949 * 24950 * @param selected The new selected state 24951 */ dispatchSetSelected(boolean selected)24952 protected void dispatchSetSelected(boolean selected) { 24953 } 24954 24955 /** 24956 * Indicates the selection state of this view. 24957 * 24958 * @return true if the view is selected, false otherwise 24959 */ 24960 @ViewDebug.ExportedProperty 24961 @InspectableProperty(hasAttributeId = false) isSelected()24962 public boolean isSelected() { 24963 return (mPrivateFlags & PFLAG_SELECTED) != 0; 24964 } 24965 24966 /** 24967 * Changes the activated state of this view. A view can be activated or not. 24968 * Note that activation is not the same as selection. Selection is 24969 * a transient property, representing the view (hierarchy) the user is 24970 * currently interacting with. Activation is a longer-term state that the 24971 * user can move views in and out of. For example, in a list view with 24972 * single or multiple selection enabled, the views in the current selection 24973 * set are activated. (Um, yeah, we are deeply sorry about the terminology 24974 * here.) The activated state is propagated down to children of the view it 24975 * is set on. 24976 * 24977 * @param activated true if the view must be activated, false otherwise 24978 */ setActivated(boolean activated)24979 public void setActivated(boolean activated) { 24980 //noinspection DoubleNegation 24981 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 24982 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 24983 invalidate(true); 24984 refreshDrawableState(); 24985 dispatchSetActivated(activated); 24986 } 24987 } 24988 24989 /** 24990 * Dispatch setActivated to all of this View's children. 24991 * 24992 * @see #setActivated(boolean) 24993 * 24994 * @param activated The new activated state 24995 */ dispatchSetActivated(boolean activated)24996 protected void dispatchSetActivated(boolean activated) { 24997 } 24998 24999 /** 25000 * Indicates the activation state of this view. 25001 * 25002 * @return true if the view is activated, false otherwise 25003 */ 25004 @ViewDebug.ExportedProperty 25005 @InspectableProperty(hasAttributeId = false) isActivated()25006 public boolean isActivated() { 25007 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 25008 } 25009 25010 /** 25011 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 25012 * observer can be used to get notifications when global events, like 25013 * layout, happen. 25014 * 25015 * The returned ViewTreeObserver observer is not guaranteed to remain 25016 * valid for the lifetime of this View. If the caller of this method keeps 25017 * a long-lived reference to ViewTreeObserver, it should always check for 25018 * the return value of {@link ViewTreeObserver#isAlive()}. 25019 * 25020 * @return The ViewTreeObserver for this view's hierarchy. 25021 */ getViewTreeObserver()25022 public ViewTreeObserver getViewTreeObserver() { 25023 if (mAttachInfo != null) { 25024 return mAttachInfo.mTreeObserver; 25025 } 25026 if (mFloatingTreeObserver == null) { 25027 mFloatingTreeObserver = new ViewTreeObserver(mContext); 25028 } 25029 return mFloatingTreeObserver; 25030 } 25031 25032 /** 25033 * <p>Finds the topmost view in the current view hierarchy.</p> 25034 * 25035 * @return the topmost view containing this view 25036 */ getRootView()25037 public View getRootView() { 25038 if (mAttachInfo != null) { 25039 final View v = mAttachInfo.mRootView; 25040 if (v != null) { 25041 return v; 25042 } 25043 } 25044 25045 View parent = this; 25046 25047 while (parent.mParent instanceof View) { 25048 parent = (View) parent.mParent; 25049 } 25050 25051 return parent; 25052 } 25053 25054 /** 25055 * Transforms a motion event from view-local coordinates to on-screen 25056 * coordinates. 25057 * 25058 * @param ev the view-local motion event 25059 * @return false if the transformation could not be applied 25060 * @hide 25061 */ 25062 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toGlobalMotionEvent(MotionEvent ev)25063 public boolean toGlobalMotionEvent(MotionEvent ev) { 25064 final AttachInfo info = mAttachInfo; 25065 if (info == null) { 25066 return false; 25067 } 25068 25069 final Matrix m = info.mTmpMatrix; 25070 m.set(Matrix.IDENTITY_MATRIX); 25071 transformMatrixToGlobal(m); 25072 ev.transform(m); 25073 return true; 25074 } 25075 25076 /** 25077 * Transforms a motion event from on-screen coordinates to view-local 25078 * coordinates. 25079 * 25080 * @param ev the on-screen motion event 25081 * @return false if the transformation could not be applied 25082 * @hide 25083 */ 25084 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toLocalMotionEvent(MotionEvent ev)25085 public boolean toLocalMotionEvent(MotionEvent ev) { 25086 final AttachInfo info = mAttachInfo; 25087 if (info == null) { 25088 return false; 25089 } 25090 25091 final Matrix m = info.mTmpMatrix; 25092 m.set(Matrix.IDENTITY_MATRIX); 25093 transformMatrixToLocal(m); 25094 ev.transform(m); 25095 return true; 25096 } 25097 25098 /** 25099 * Modifies the input matrix such that it maps view-local coordinates to 25100 * on-screen coordinates. 25101 * 25102 * @param matrix input matrix to modify 25103 */ transformMatrixToGlobal(@onNull Matrix matrix)25104 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 25105 final ViewParent parent = mParent; 25106 if (parent instanceof View) { 25107 final View vp = (View) parent; 25108 vp.transformMatrixToGlobal(matrix); 25109 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 25110 } else if (parent instanceof ViewRootImpl) { 25111 final ViewRootImpl vr = (ViewRootImpl) parent; 25112 vr.transformMatrixToGlobal(matrix); 25113 matrix.preTranslate(0, -vr.mCurScrollY); 25114 } 25115 25116 matrix.preTranslate(mLeft, mTop); 25117 25118 if (!hasIdentityMatrix()) { 25119 matrix.preConcat(getMatrix()); 25120 } 25121 } 25122 25123 /** 25124 * Modifies the input matrix such that it maps on-screen coordinates to 25125 * view-local coordinates. 25126 * 25127 * @param matrix input matrix to modify 25128 */ transformMatrixToLocal(@onNull Matrix matrix)25129 public void transformMatrixToLocal(@NonNull Matrix matrix) { 25130 final ViewParent parent = mParent; 25131 if (parent instanceof View) { 25132 final View vp = (View) parent; 25133 vp.transformMatrixToLocal(matrix); 25134 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 25135 } else if (parent instanceof ViewRootImpl) { 25136 final ViewRootImpl vr = (ViewRootImpl) parent; 25137 vr.transformMatrixToLocal(matrix); 25138 matrix.postTranslate(0, vr.mCurScrollY); 25139 } 25140 25141 matrix.postTranslate(-mLeft, -mTop); 25142 25143 if (!hasIdentityMatrix()) { 25144 matrix.postConcat(getInverseMatrix()); 25145 } 25146 } 25147 25148 /** 25149 * @hide 25150 */ 25151 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 25152 @ViewDebug.IntToString(from = 0, to = "x"), 25153 @ViewDebug.IntToString(from = 1, to = "y") 25154 }) 25155 @UnsupportedAppUsage getLocationOnScreen()25156 public int[] getLocationOnScreen() { 25157 int[] location = new int[2]; 25158 getLocationOnScreen(location); 25159 return location; 25160 } 25161 25162 /** 25163 * <p>Computes the coordinates of this view on the screen. The argument 25164 * must be an array of two integers. After the method returns, the array 25165 * contains the x and y location in that order.</p> 25166 * 25167 * @param outLocation an array of two integers in which to hold the coordinates 25168 */ getLocationOnScreen(@ize2) int[] outLocation)25169 public void getLocationOnScreen(@Size(2) int[] outLocation) { 25170 getLocationInWindow(outLocation); 25171 25172 final AttachInfo info = mAttachInfo; 25173 if (info != null) { 25174 outLocation[0] += info.mWindowLeft; 25175 outLocation[1] += info.mWindowTop; 25176 } 25177 } 25178 25179 /** 25180 * <p>Computes the coordinates of this view in its window. The argument 25181 * must be an array of two integers. After the method returns, the array 25182 * contains the x and y location in that order.</p> 25183 * 25184 * @param outLocation an array of two integers in which to hold the coordinates 25185 */ getLocationInWindow(@ize2) int[] outLocation)25186 public void getLocationInWindow(@Size(2) int[] outLocation) { 25187 if (outLocation == null || outLocation.length < 2) { 25188 throw new IllegalArgumentException("outLocation must be an array of two integers"); 25189 } 25190 25191 outLocation[0] = 0; 25192 outLocation[1] = 0; 25193 25194 transformFromViewToWindowSpace(outLocation); 25195 } 25196 25197 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)25198 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 25199 if (inOutLocation == null || inOutLocation.length < 2) { 25200 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 25201 } 25202 25203 if (mAttachInfo == null) { 25204 // When the view is not attached to a window, this method does not make sense 25205 inOutLocation[0] = inOutLocation[1] = 0; 25206 return; 25207 } 25208 25209 float position[] = mAttachInfo.mTmpTransformLocation; 25210 position[0] = inOutLocation[0]; 25211 position[1] = inOutLocation[1]; 25212 25213 if (!hasIdentityMatrix()) { 25214 getMatrix().mapPoints(position); 25215 } 25216 25217 position[0] += mLeft; 25218 position[1] += mTop; 25219 25220 ViewParent viewParent = mParent; 25221 while (viewParent instanceof View) { 25222 final View view = (View) viewParent; 25223 25224 position[0] -= view.mScrollX; 25225 position[1] -= view.mScrollY; 25226 25227 if (!view.hasIdentityMatrix()) { 25228 view.getMatrix().mapPoints(position); 25229 } 25230 25231 position[0] += view.mLeft; 25232 position[1] += view.mTop; 25233 25234 viewParent = view.mParent; 25235 } 25236 25237 if (viewParent instanceof ViewRootImpl) { 25238 // *cough* 25239 final ViewRootImpl vr = (ViewRootImpl) viewParent; 25240 position[1] -= vr.mCurScrollY; 25241 } 25242 25243 inOutLocation[0] = Math.round(position[0]); 25244 inOutLocation[1] = Math.round(position[1]); 25245 } 25246 25247 /** 25248 * @param id the id of the view to be found 25249 * @return the view of the specified id, null if cannot be found 25250 * @hide 25251 */ findViewTraversal(@dRes int id)25252 protected <T extends View> T findViewTraversal(@IdRes int id) { 25253 if (id == mID) { 25254 return (T) this; 25255 } 25256 return null; 25257 } 25258 25259 /** 25260 * @param tag the tag of the view to be found 25261 * @return the view of specified tag, null if cannot be found 25262 * @hide 25263 */ findViewWithTagTraversal(Object tag)25264 protected <T extends View> T findViewWithTagTraversal(Object tag) { 25265 if (tag != null && tag.equals(mTag)) { 25266 return (T) this; 25267 } 25268 return null; 25269 } 25270 25271 /** 25272 * @param predicate The predicate to evaluate. 25273 * @param childToSkip If not null, ignores this child during the recursive traversal. 25274 * @return The first view that matches the predicate or null. 25275 * @hide 25276 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)25277 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 25278 View childToSkip) { 25279 if (predicate.test(this)) { 25280 return (T) this; 25281 } 25282 return null; 25283 } 25284 25285 /** 25286 * Finds the first descendant view with the given ID, the view itself if 25287 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 25288 * (< 0) or there is no matching view in the hierarchy. 25289 * <p> 25290 * <strong>Note:</strong> In most cases -- depending on compiler support -- 25291 * the resulting view is automatically cast to the target class type. If 25292 * the target class type is unconstrained, an explicit cast may be 25293 * necessary. 25294 * 25295 * @param id the ID to search for 25296 * @return a view with given ID if found, or {@code null} otherwise 25297 * @see View#requireViewById(int) 25298 */ 25299 @Nullable findViewById(@dRes int id)25300 public final <T extends View> T findViewById(@IdRes int id) { 25301 if (id == NO_ID) { 25302 return null; 25303 } 25304 return findViewTraversal(id); 25305 } 25306 25307 /** 25308 * Finds the first descendant view with the given ID, the view itself if the ID matches 25309 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 25310 * matching view in the hierarchy. 25311 * <p> 25312 * <strong>Note:</strong> In most cases -- depending on compiler support -- 25313 * the resulting view is automatically cast to the target class type. If 25314 * the target class type is unconstrained, an explicit cast may be 25315 * necessary. 25316 * 25317 * @param id the ID to search for 25318 * @return a view with given ID 25319 * @see View#findViewById(int) 25320 */ 25321 @NonNull requireViewById(@dRes int id)25322 public final <T extends View> T requireViewById(@IdRes int id) { 25323 T view = findViewById(id); 25324 if (view == null) { 25325 throw new IllegalArgumentException("ID does not reference a View inside this View"); 25326 } 25327 return view; 25328 } 25329 25330 /** 25331 * Performs the traversal to find a view by its unique and stable accessibility id. 25332 * 25333 * <strong>Note:</strong>This method does not stop at the root namespace 25334 * boundary since the user can touch the screen at an arbitrary location 25335 * potentially crossing the root namespace boundary which will send an 25336 * accessibility event to accessibility services and they should be able 25337 * to obtain the event source. Also accessibility ids are guaranteed to be 25338 * unique in the window. 25339 * 25340 * @param accessibilityId The accessibility id. 25341 * @return The found view. 25342 * @hide 25343 */ findViewByAccessibilityIdTraversal(int accessibilityId)25344 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 25345 if (getAccessibilityViewId() == accessibilityId) { 25346 return (T) this; 25347 } 25348 return null; 25349 } 25350 25351 /** 25352 * Performs the traversal to find a view by its autofill id. 25353 * 25354 * <strong>Note:</strong>This method does not stop at the root namespace 25355 * boundary. 25356 * 25357 * @param autofillId The autofill id. 25358 * @return The found view. 25359 * @hide 25360 */ findViewByAutofillIdTraversal(int autofillId)25361 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 25362 if (getAutofillViewId() == autofillId) { 25363 return (T) this; 25364 } 25365 return null; 25366 } 25367 25368 /** 25369 * Look for a child view with the given tag. If this view has the given 25370 * tag, return this view. 25371 * 25372 * @param tag The tag to search for, using "tag.equals(getTag())". 25373 * @return The View that has the given tag in the hierarchy or null 25374 */ findViewWithTag(Object tag)25375 public final <T extends View> T findViewWithTag(Object tag) { 25376 if (tag == null) { 25377 return null; 25378 } 25379 return findViewWithTagTraversal(tag); 25380 } 25381 25382 /** 25383 * Look for a child view that matches the specified predicate. 25384 * If this view matches the predicate, return this view. 25385 * 25386 * @param predicate The predicate to evaluate. 25387 * @return The first view that matches the predicate or null. 25388 * @hide 25389 */ findViewByPredicate(Predicate<View> predicate)25390 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 25391 return findViewByPredicateTraversal(predicate, null); 25392 } 25393 25394 /** 25395 * Look for a child view that matches the specified predicate, 25396 * starting with the specified view and its descendents and then 25397 * recusively searching the ancestors and siblings of that view 25398 * until this view is reached. 25399 * 25400 * This method is useful in cases where the predicate does not match 25401 * a single unique view (perhaps multiple views use the same id) 25402 * and we are trying to find the view that is "closest" in scope to the 25403 * starting view. 25404 * 25405 * @param start The view to start from. 25406 * @param predicate The predicate to evaluate. 25407 * @return The first view that matches the predicate or null. 25408 * @hide 25409 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)25410 public final <T extends View> T findViewByPredicateInsideOut( 25411 View start, Predicate<View> predicate) { 25412 View childToSkip = null; 25413 for (;;) { 25414 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 25415 if (view != null || start == this) { 25416 return view; 25417 } 25418 25419 ViewParent parent = start.getParent(); 25420 if (parent == null || !(parent instanceof View)) { 25421 return null; 25422 } 25423 25424 childToSkip = start; 25425 start = (View) parent; 25426 } 25427 } 25428 25429 /** 25430 * Sets the identifier for this view. The identifier does not have to be 25431 * unique in this view's hierarchy. The identifier should be a positive 25432 * number. 25433 * 25434 * @see #NO_ID 25435 * @see #getId() 25436 * @see #findViewById(int) 25437 * 25438 * @param id a number used to identify the view 25439 * 25440 * @attr ref android.R.styleable#View_id 25441 */ setId(@dRes int id)25442 public void setId(@IdRes int id) { 25443 mID = id; 25444 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 25445 mID = generateViewId(); 25446 } 25447 } 25448 25449 /** 25450 * {@hide} 25451 * 25452 * @param isRoot true if the view belongs to the root namespace, false 25453 * otherwise 25454 */ 25455 @UnsupportedAppUsage 25456 @TestApi setIsRootNamespace(boolean isRoot)25457 public void setIsRootNamespace(boolean isRoot) { 25458 if (isRoot) { 25459 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 25460 } else { 25461 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 25462 } 25463 } 25464 25465 /** 25466 * {@hide} 25467 * 25468 * @return true if the view belongs to the root namespace, false otherwise 25469 */ 25470 @UnsupportedAppUsage isRootNamespace()25471 public boolean isRootNamespace() { 25472 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 25473 } 25474 25475 /** 25476 * Returns this view's identifier. 25477 * 25478 * @return a positive integer used to identify the view or {@link #NO_ID} 25479 * if the view has no ID 25480 * 25481 * @see #setId(int) 25482 * @see #findViewById(int) 25483 * @attr ref android.R.styleable#View_id 25484 */ 25485 @IdRes 25486 @ViewDebug.CapturedViewProperty 25487 @InspectableProperty getId()25488 public int getId() { 25489 return mID; 25490 } 25491 25492 /** 25493 * Get the identifier used for this view by the drawing system. 25494 * 25495 * @see RenderNode#getUniqueId() 25496 * @return A long that uniquely identifies this view's drawing component 25497 */ getUniqueDrawingId()25498 public long getUniqueDrawingId() { 25499 return mRenderNode.getUniqueId(); 25500 } 25501 25502 /** 25503 * Returns this view's tag. 25504 * 25505 * @return the Object stored in this view as a tag, or {@code null} if not 25506 * set 25507 * 25508 * @see #setTag(Object) 25509 * @see #getTag(int) 25510 */ 25511 @ViewDebug.ExportedProperty 25512 @InspectableProperty getTag()25513 public Object getTag() { 25514 return mTag; 25515 } 25516 25517 /** 25518 * Sets the tag associated with this view. A tag can be used to mark 25519 * a view in its hierarchy and does not have to be unique within the 25520 * hierarchy. Tags can also be used to store data within a view without 25521 * resorting to another data structure. 25522 * 25523 * @param tag an Object to tag the view with 25524 * 25525 * @see #getTag() 25526 * @see #setTag(int, Object) 25527 */ setTag(final Object tag)25528 public void setTag(final Object tag) { 25529 mTag = tag; 25530 } 25531 25532 /** 25533 * Returns the tag associated with this view and the specified key. 25534 * 25535 * @param key The key identifying the tag 25536 * 25537 * @return the Object stored in this view as a tag, or {@code null} if not 25538 * set 25539 * 25540 * @see #setTag(int, Object) 25541 * @see #getTag() 25542 */ getTag(int key)25543 public Object getTag(int key) { 25544 if (mKeyedTags != null) return mKeyedTags.get(key); 25545 return null; 25546 } 25547 25548 /** 25549 * Sets a tag associated with this view and a key. A tag can be used 25550 * to mark a view in its hierarchy and does not have to be unique within 25551 * the hierarchy. Tags can also be used to store data within a view 25552 * without resorting to another data structure. 25553 * 25554 * The specified key should be an id declared in the resources of the 25555 * application to ensure it is unique (see the <a 25556 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 25557 * Keys identified as belonging to 25558 * the Android framework or not associated with any package will cause 25559 * an {@link IllegalArgumentException} to be thrown. 25560 * 25561 * @param key The key identifying the tag 25562 * @param tag An Object to tag the view with 25563 * 25564 * @throws IllegalArgumentException If they specified key is not valid 25565 * 25566 * @see #setTag(Object) 25567 * @see #getTag(int) 25568 */ setTag(int key, final Object tag)25569 public void setTag(int key, final Object tag) { 25570 // If the package id is 0x00 or 0x01, it's either an undefined package 25571 // or a framework id 25572 if ((key >>> 24) < 2) { 25573 throw new IllegalArgumentException("The key must be an application-specific " 25574 + "resource id."); 25575 } 25576 25577 setKeyedTag(key, tag); 25578 } 25579 25580 /** 25581 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 25582 * framework id. 25583 * 25584 * @hide 25585 */ 25586 @UnsupportedAppUsage setTagInternal(int key, Object tag)25587 public void setTagInternal(int key, Object tag) { 25588 if ((key >>> 24) != 0x1) { 25589 throw new IllegalArgumentException("The key must be a framework-specific " 25590 + "resource id."); 25591 } 25592 25593 setKeyedTag(key, tag); 25594 } 25595 setKeyedTag(int key, Object tag)25596 private void setKeyedTag(int key, Object tag) { 25597 if (mKeyedTags == null) { 25598 mKeyedTags = new SparseArray<Object>(2); 25599 } 25600 25601 mKeyedTags.put(key, tag); 25602 } 25603 25604 /** 25605 * Prints information about this view in the log output, with the tag 25606 * {@link #VIEW_LOG_TAG}. 25607 * 25608 * @hide 25609 */ 25610 @UnsupportedAppUsage debug()25611 public void debug() { 25612 debug(0); 25613 } 25614 25615 /** 25616 * Prints information about this view in the log output, with the tag 25617 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 25618 * indentation defined by the <code>depth</code>. 25619 * 25620 * @param depth the indentation level 25621 * 25622 * @hide 25623 */ 25624 @UnsupportedAppUsage debug(int depth)25625 protected void debug(int depth) { 25626 String output = debugIndent(depth - 1); 25627 25628 output += "+ " + this; 25629 int id = getId(); 25630 if (id != -1) { 25631 output += " (id=" + id + ")"; 25632 } 25633 Object tag = getTag(); 25634 if (tag != null) { 25635 output += " (tag=" + tag + ")"; 25636 } 25637 Log.d(VIEW_LOG_TAG, output); 25638 25639 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 25640 output = debugIndent(depth) + " FOCUSED"; 25641 Log.d(VIEW_LOG_TAG, output); 25642 } 25643 25644 output = debugIndent(depth); 25645 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 25646 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 25647 + "} "; 25648 Log.d(VIEW_LOG_TAG, output); 25649 25650 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 25651 || mPaddingBottom != 0) { 25652 output = debugIndent(depth); 25653 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 25654 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 25655 Log.d(VIEW_LOG_TAG, output); 25656 } 25657 25658 output = debugIndent(depth); 25659 output += "mMeasureWidth=" + mMeasuredWidth + 25660 " mMeasureHeight=" + mMeasuredHeight; 25661 Log.d(VIEW_LOG_TAG, output); 25662 25663 output = debugIndent(depth); 25664 if (mLayoutParams == null) { 25665 output += "BAD! no layout params"; 25666 } else { 25667 output = mLayoutParams.debug(output); 25668 } 25669 Log.d(VIEW_LOG_TAG, output); 25670 25671 output = debugIndent(depth); 25672 output += "flags={"; 25673 output += View.printFlags(mViewFlags); 25674 output += "}"; 25675 Log.d(VIEW_LOG_TAG, output); 25676 25677 output = debugIndent(depth); 25678 output += "privateFlags={"; 25679 output += View.printPrivateFlags(mPrivateFlags); 25680 output += "}"; 25681 Log.d(VIEW_LOG_TAG, output); 25682 } 25683 25684 /** 25685 * Creates a string of whitespaces used for indentation. 25686 * 25687 * @param depth the indentation level 25688 * @return a String containing (depth * 2 + 3) * 2 white spaces 25689 * 25690 * @hide 25691 */ debugIndent(int depth)25692 protected static String debugIndent(int depth) { 25693 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 25694 for (int i = 0; i < (depth * 2) + 3; i++) { 25695 spaces.append(' ').append(' '); 25696 } 25697 return spaces.toString(); 25698 } 25699 25700 /** 25701 * <p>Return the offset of the widget's text baseline from the widget's top 25702 * boundary. If this widget does not support baseline alignment, this 25703 * method returns -1. </p> 25704 * 25705 * @return the offset of the baseline within the widget's bounds or -1 25706 * if baseline alignment is not supported 25707 */ 25708 @ViewDebug.ExportedProperty(category = "layout") 25709 @InspectableProperty getBaseline()25710 public int getBaseline() { 25711 return -1; 25712 } 25713 25714 /** 25715 * Returns whether the view hierarchy is currently undergoing a layout pass. This 25716 * information is useful to avoid situations such as calling {@link #requestLayout()} during 25717 * a layout pass. 25718 * 25719 * @return whether the view hierarchy is currently undergoing a layout pass 25720 */ isInLayout()25721 public boolean isInLayout() { 25722 ViewRootImpl viewRoot = getViewRootImpl(); 25723 return (viewRoot != null && viewRoot.isInLayout()); 25724 } 25725 25726 /** 25727 * Call this when something has changed which has invalidated the 25728 * layout of this view. This will schedule a layout pass of the view 25729 * tree. This should not be called while the view hierarchy is currently in a layout 25730 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 25731 * end of the current layout pass (and then layout will run again) or after the current 25732 * frame is drawn and the next layout occurs. 25733 * 25734 * <p>Subclasses which override this method should call the superclass method to 25735 * handle possible request-during-layout errors correctly.</p> 25736 */ 25737 @CallSuper requestLayout()25738 public void requestLayout() { 25739 if (mMeasureCache != null) mMeasureCache.clear(); 25740 25741 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 25742 // Only trigger request-during-layout logic if this is the view requesting it, 25743 // not the views in its parent hierarchy 25744 ViewRootImpl viewRoot = getViewRootImpl(); 25745 if (viewRoot != null && viewRoot.isInLayout()) { 25746 if (!viewRoot.requestLayoutDuringLayout(this)) { 25747 return; 25748 } 25749 } 25750 mAttachInfo.mViewRequestingLayout = this; 25751 } 25752 25753 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25754 mPrivateFlags |= PFLAG_INVALIDATED; 25755 25756 if (mParent != null && !mParent.isLayoutRequested()) { 25757 mParent.requestLayout(); 25758 } 25759 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 25760 mAttachInfo.mViewRequestingLayout = null; 25761 } 25762 } 25763 25764 /** 25765 * Forces this view to be laid out during the next layout pass. 25766 * This method does not call requestLayout() or forceLayout() 25767 * on the parent. 25768 */ forceLayout()25769 public void forceLayout() { 25770 if (mMeasureCache != null) mMeasureCache.clear(); 25771 25772 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25773 mPrivateFlags |= PFLAG_INVALIDATED; 25774 } 25775 25776 /** 25777 * <p> 25778 * This is called to find out how big a view should be. The parent 25779 * supplies constraint information in the width and height parameters. 25780 * </p> 25781 * 25782 * <p> 25783 * The actual measurement work of a view is performed in 25784 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 25785 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 25786 * </p> 25787 * 25788 * 25789 * @param widthMeasureSpec Horizontal space requirements as imposed by the 25790 * parent 25791 * @param heightMeasureSpec Vertical space requirements as imposed by the 25792 * parent 25793 * 25794 * @see #onMeasure(int, int) 25795 */ measure(int widthMeasureSpec, int heightMeasureSpec)25796 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 25797 boolean optical = isLayoutModeOptical(this); 25798 if (optical != isLayoutModeOptical(mParent)) { 25799 Insets insets = getOpticalInsets(); 25800 int oWidth = insets.left + insets.right; 25801 int oHeight = insets.top + insets.bottom; 25802 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 25803 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 25804 } 25805 25806 // Suppress sign extension for the low bytes 25807 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 25808 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 25809 25810 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 25811 25812 // Optimize layout by avoiding an extra EXACTLY pass when the view is 25813 // already measured as the correct size. In API 23 and below, this 25814 // extra pass is required to make LinearLayout re-distribute weight. 25815 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 25816 || heightMeasureSpec != mOldHeightMeasureSpec; 25817 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 25818 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 25819 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 25820 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 25821 final boolean needsLayout = specChanged 25822 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 25823 25824 if (forceLayout || needsLayout) { 25825 // first clears the measured dimension flag 25826 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 25827 25828 resolveRtlPropertiesIfNeeded(); 25829 25830 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 25831 if (cacheIndex < 0 || sIgnoreMeasureCache) { 25832 // measure ourselves, this should set the measured dimension flag back 25833 onMeasure(widthMeasureSpec, heightMeasureSpec); 25834 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25835 } else { 25836 long value = mMeasureCache.valueAt(cacheIndex); 25837 // Casting a long to int drops the high 32 bits, no mask needed 25838 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 25839 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25840 } 25841 25842 // flag not set, setMeasuredDimension() was not invoked, we raise 25843 // an exception to warn the developer 25844 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 25845 throw new IllegalStateException("View with id " + getId() + ": " 25846 + getClass().getName() + "#onMeasure() did not set the" 25847 + " measured dimension by calling" 25848 + " setMeasuredDimension()"); 25849 } 25850 25851 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 25852 } 25853 25854 mOldWidthMeasureSpec = widthMeasureSpec; 25855 mOldHeightMeasureSpec = heightMeasureSpec; 25856 25857 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 25858 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 25859 } 25860 25861 /** 25862 * <p> 25863 * Measure the view and its content to determine the measured width and the 25864 * measured height. This method is invoked by {@link #measure(int, int)} and 25865 * should be overridden by subclasses to provide accurate and efficient 25866 * measurement of their contents. 25867 * </p> 25868 * 25869 * <p> 25870 * <strong>CONTRACT:</strong> When overriding this method, you 25871 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 25872 * measured width and height of this view. Failure to do so will trigger an 25873 * <code>IllegalStateException</code>, thrown by 25874 * {@link #measure(int, int)}. Calling the superclass' 25875 * {@link #onMeasure(int, int)} is a valid use. 25876 * </p> 25877 * 25878 * <p> 25879 * The base class implementation of measure defaults to the background size, 25880 * unless a larger size is allowed by the MeasureSpec. Subclasses should 25881 * override {@link #onMeasure(int, int)} to provide better measurements of 25882 * their content. 25883 * </p> 25884 * 25885 * <p> 25886 * If this method is overridden, it is the subclass's responsibility to make 25887 * sure the measured height and width are at least the view's minimum height 25888 * and width ({@link #getSuggestedMinimumHeight()} and 25889 * {@link #getSuggestedMinimumWidth()}). 25890 * </p> 25891 * 25892 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 25893 * The requirements are encoded with 25894 * {@link android.view.View.MeasureSpec}. 25895 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 25896 * The requirements are encoded with 25897 * {@link android.view.View.MeasureSpec}. 25898 * 25899 * @see #getMeasuredWidth() 25900 * @see #getMeasuredHeight() 25901 * @see #setMeasuredDimension(int, int) 25902 * @see #getSuggestedMinimumHeight() 25903 * @see #getSuggestedMinimumWidth() 25904 * @see android.view.View.MeasureSpec#getMode(int) 25905 * @see android.view.View.MeasureSpec#getSize(int) 25906 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)25907 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 25908 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 25909 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 25910 } 25911 25912 /** 25913 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 25914 * measured width and measured height. Failing to do so will trigger an 25915 * exception at measurement time.</p> 25916 * 25917 * @param measuredWidth The measured width of this view. May be a complex 25918 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25919 * {@link #MEASURED_STATE_TOO_SMALL}. 25920 * @param measuredHeight The measured height of this view. May be a complex 25921 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25922 * {@link #MEASURED_STATE_TOO_SMALL}. 25923 */ setMeasuredDimension(int measuredWidth, int measuredHeight)25924 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 25925 boolean optical = isLayoutModeOptical(this); 25926 if (optical != isLayoutModeOptical(mParent)) { 25927 Insets insets = getOpticalInsets(); 25928 int opticalWidth = insets.left + insets.right; 25929 int opticalHeight = insets.top + insets.bottom; 25930 25931 measuredWidth += optical ? opticalWidth : -opticalWidth; 25932 measuredHeight += optical ? opticalHeight : -opticalHeight; 25933 } 25934 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 25935 } 25936 25937 /** 25938 * Sets the measured dimension without extra processing for things like optical bounds. 25939 * Useful for reapplying consistent values that have already been cooked with adjustments 25940 * for optical bounds, etc. such as those from the measurement cache. 25941 * 25942 * @param measuredWidth The measured width of this view. May be a complex 25943 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25944 * {@link #MEASURED_STATE_TOO_SMALL}. 25945 * @param measuredHeight The measured height of this view. May be a complex 25946 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25947 * {@link #MEASURED_STATE_TOO_SMALL}. 25948 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)25949 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 25950 mMeasuredWidth = measuredWidth; 25951 mMeasuredHeight = measuredHeight; 25952 25953 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 25954 } 25955 25956 /** 25957 * Merge two states as returned by {@link #getMeasuredState()}. 25958 * @param curState The current state as returned from a view or the result 25959 * of combining multiple views. 25960 * @param newState The new view state to combine. 25961 * @return Returns a new integer reflecting the combination of the two 25962 * states. 25963 */ combineMeasuredStates(int curState, int newState)25964 public static int combineMeasuredStates(int curState, int newState) { 25965 return curState | newState; 25966 } 25967 25968 /** 25969 * Version of {@link #resolveSizeAndState(int, int, int)} 25970 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 25971 */ resolveSize(int size, int measureSpec)25972 public static int resolveSize(int size, int measureSpec) { 25973 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 25974 } 25975 25976 /** 25977 * Utility to reconcile a desired size and state, with constraints imposed 25978 * by a MeasureSpec. Will take the desired size, unless a different size 25979 * is imposed by the constraints. The returned value is a compound integer, 25980 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 25981 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 25982 * resulting size is smaller than the size the view wants to be. 25983 * 25984 * @param size How big the view wants to be. 25985 * @param measureSpec Constraints imposed by the parent. 25986 * @param childMeasuredState Size information bit mask for the view's 25987 * children. 25988 * @return Size information bit mask as defined by 25989 * {@link #MEASURED_SIZE_MASK} and 25990 * {@link #MEASURED_STATE_TOO_SMALL}. 25991 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)25992 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 25993 final int specMode = MeasureSpec.getMode(measureSpec); 25994 final int specSize = MeasureSpec.getSize(measureSpec); 25995 final int result; 25996 switch (specMode) { 25997 case MeasureSpec.AT_MOST: 25998 if (specSize < size) { 25999 result = specSize | MEASURED_STATE_TOO_SMALL; 26000 } else { 26001 result = size; 26002 } 26003 break; 26004 case MeasureSpec.EXACTLY: 26005 result = specSize; 26006 break; 26007 case MeasureSpec.UNSPECIFIED: 26008 default: 26009 result = size; 26010 } 26011 return result | (childMeasuredState & MEASURED_STATE_MASK); 26012 } 26013 26014 /** 26015 * Utility to return a default size. Uses the supplied size if the 26016 * MeasureSpec imposed no constraints. Will get larger if allowed 26017 * by the MeasureSpec. 26018 * 26019 * @param size Default size for this view 26020 * @param measureSpec Constraints imposed by the parent 26021 * @return The size this view should be. 26022 */ getDefaultSize(int size, int measureSpec)26023 public static int getDefaultSize(int size, int measureSpec) { 26024 int result = size; 26025 int specMode = MeasureSpec.getMode(measureSpec); 26026 int specSize = MeasureSpec.getSize(measureSpec); 26027 26028 switch (specMode) { 26029 case MeasureSpec.UNSPECIFIED: 26030 result = size; 26031 break; 26032 case MeasureSpec.AT_MOST: 26033 case MeasureSpec.EXACTLY: 26034 result = specSize; 26035 break; 26036 } 26037 return result; 26038 } 26039 26040 /** 26041 * Returns the suggested minimum height that the view should use. This 26042 * returns the maximum of the view's minimum height 26043 * and the background's minimum height 26044 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 26045 * <p> 26046 * When being used in {@link #onMeasure(int, int)}, the caller should still 26047 * ensure the returned height is within the requirements of the parent. 26048 * 26049 * @return The suggested minimum height of the view. 26050 */ getSuggestedMinimumHeight()26051 protected int getSuggestedMinimumHeight() { 26052 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 26053 26054 } 26055 26056 /** 26057 * Returns the suggested minimum width that the view should use. This 26058 * returns the maximum of the view's minimum width 26059 * and the background's minimum width 26060 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 26061 * <p> 26062 * When being used in {@link #onMeasure(int, int)}, the caller should still 26063 * ensure the returned width is within the requirements of the parent. 26064 * 26065 * @return The suggested minimum width of the view. 26066 */ getSuggestedMinimumWidth()26067 protected int getSuggestedMinimumWidth() { 26068 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 26069 } 26070 26071 /** 26072 * Returns the minimum height of the view. 26073 * 26074 * @return the minimum height the view will try to be, in pixels 26075 * 26076 * @see #setMinimumHeight(int) 26077 * 26078 * @attr ref android.R.styleable#View_minHeight 26079 */ 26080 @InspectableProperty(name = "minHeight") getMinimumHeight()26081 public int getMinimumHeight() { 26082 return mMinHeight; 26083 } 26084 26085 /** 26086 * Sets the minimum height of the view. It is not guaranteed the view will 26087 * be able to achieve this minimum height (for example, if its parent layout 26088 * constrains it with less available height). 26089 * 26090 * @param minHeight The minimum height the view will try to be, in pixels 26091 * 26092 * @see #getMinimumHeight() 26093 * 26094 * @attr ref android.R.styleable#View_minHeight 26095 */ 26096 @RemotableViewMethod setMinimumHeight(int minHeight)26097 public void setMinimumHeight(int minHeight) { 26098 mMinHeight = minHeight; 26099 requestLayout(); 26100 } 26101 26102 /** 26103 * Returns the minimum width of the view. 26104 * 26105 * @return the minimum width the view will try to be, in pixels 26106 * 26107 * @see #setMinimumWidth(int) 26108 * 26109 * @attr ref android.R.styleable#View_minWidth 26110 */ 26111 @InspectableProperty(name = "minWidth") getMinimumWidth()26112 public int getMinimumWidth() { 26113 return mMinWidth; 26114 } 26115 26116 /** 26117 * Sets the minimum width of the view. It is not guaranteed the view will 26118 * be able to achieve this minimum width (for example, if its parent layout 26119 * constrains it with less available width). 26120 * 26121 * @param minWidth The minimum width the view will try to be, in pixels 26122 * 26123 * @see #getMinimumWidth() 26124 * 26125 * @attr ref android.R.styleable#View_minWidth 26126 */ 26127 @RemotableViewMethod setMinimumWidth(int minWidth)26128 public void setMinimumWidth(int minWidth) { 26129 mMinWidth = minWidth; 26130 requestLayout(); 26131 26132 } 26133 26134 /** 26135 * Get the animation currently associated with this view. 26136 * 26137 * @return The animation that is currently playing or 26138 * scheduled to play for this view. 26139 */ getAnimation()26140 public Animation getAnimation() { 26141 return mCurrentAnimation; 26142 } 26143 26144 /** 26145 * Start the specified animation now. 26146 * 26147 * @param animation the animation to start now 26148 */ startAnimation(Animation animation)26149 public void startAnimation(Animation animation) { 26150 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 26151 setAnimation(animation); 26152 invalidateParentCaches(); 26153 invalidate(true); 26154 } 26155 26156 /** 26157 * Cancels any animations for this view. 26158 */ clearAnimation()26159 public void clearAnimation() { 26160 if (mCurrentAnimation != null) { 26161 mCurrentAnimation.detach(); 26162 } 26163 mCurrentAnimation = null; 26164 invalidateParentIfNeeded(); 26165 } 26166 26167 /** 26168 * Sets the next animation to play for this view. 26169 * If you want the animation to play immediately, use 26170 * {@link #startAnimation(android.view.animation.Animation)} instead. 26171 * This method provides allows fine-grained 26172 * control over the start time and invalidation, but you 26173 * must make sure that 1) the animation has a start time set, and 26174 * 2) the view's parent (which controls animations on its children) 26175 * will be invalidated when the animation is supposed to 26176 * start. 26177 * 26178 * @param animation The next animation, or null. 26179 */ setAnimation(Animation animation)26180 public void setAnimation(Animation animation) { 26181 mCurrentAnimation = animation; 26182 26183 if (animation != null) { 26184 // If the screen is off assume the animation start time is now instead of 26185 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 26186 // would cause the animation to start when the screen turns back on 26187 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 26188 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 26189 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 26190 } 26191 animation.reset(); 26192 } 26193 } 26194 26195 /** 26196 * Invoked by a parent ViewGroup to notify the start of the animation 26197 * currently associated with this view. If you override this method, 26198 * always call super.onAnimationStart(); 26199 * 26200 * @see #setAnimation(android.view.animation.Animation) 26201 * @see #getAnimation() 26202 */ 26203 @CallSuper onAnimationStart()26204 protected void onAnimationStart() { 26205 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 26206 } 26207 26208 /** 26209 * Invoked by a parent ViewGroup to notify the end of the animation 26210 * currently associated with this view. If you override this method, 26211 * always call super.onAnimationEnd(); 26212 * 26213 * @see #setAnimation(android.view.animation.Animation) 26214 * @see #getAnimation() 26215 */ 26216 @CallSuper onAnimationEnd()26217 protected void onAnimationEnd() { 26218 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 26219 } 26220 26221 /** 26222 * Invoked if there is a Transform that involves alpha. Subclass that can 26223 * draw themselves with the specified alpha should return true, and then 26224 * respect that alpha when their onDraw() is called. If this returns false 26225 * then the view may be redirected to draw into an offscreen buffer to 26226 * fulfill the request, which will look fine, but may be slower than if the 26227 * subclass handles it internally. The default implementation returns false. 26228 * 26229 * @param alpha The alpha (0..255) to apply to the view's drawing 26230 * @return true if the view can draw with the specified alpha. 26231 */ onSetAlpha(int alpha)26232 protected boolean onSetAlpha(int alpha) { 26233 return false; 26234 } 26235 26236 /** 26237 * This is used by the ViewRoot to perform an optimization when 26238 * the view hierarchy contains one or several SurfaceView. 26239 * SurfaceView is always considered transparent, but its children are not, 26240 * therefore all View objects remove themselves from the global transparent 26241 * region (passed as a parameter to this function). 26242 * 26243 * @param region The transparent region for this ViewAncestor (window). 26244 * 26245 * @return Returns true if the effective visibility of the view at this 26246 * point is opaque, regardless of the transparent region; returns false 26247 * if it is possible for underlying windows to be seen behind the view. 26248 * 26249 */ gatherTransparentRegion(@ullable Region region)26250 public boolean gatherTransparentRegion(@Nullable Region region) { 26251 final AttachInfo attachInfo = mAttachInfo; 26252 if (region != null && attachInfo != null) { 26253 final int pflags = mPrivateFlags; 26254 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 26255 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 26256 // remove it from the transparent region. 26257 final int[] location = attachInfo.mTransparentLocation; 26258 getLocationInWindow(location); 26259 // When a view has Z value, then it will be better to leave some area below the view 26260 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 26261 // the bottom part needs more offset than the left, top and right parts due to the 26262 // spot light effects. 26263 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 26264 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 26265 location[0] + mRight - mLeft + shadowOffset, 26266 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 26267 } else { 26268 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 26269 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 26270 // the background drawable's non-transparent parts from this transparent region. 26271 applyDrawableToTransparentRegion(mBackground, region); 26272 } 26273 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 26274 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 26275 // Similarly, we remove the foreground drawable's non-transparent parts. 26276 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 26277 } 26278 if (mDefaultFocusHighlight != null 26279 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 26280 // Similarly, we remove the default focus highlight's non-transparent parts. 26281 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 26282 } 26283 } 26284 } 26285 return true; 26286 } 26287 26288 /** 26289 * Play a sound effect for this view. 26290 * 26291 * <p>The framework will play sound effects for some built in actions, such as 26292 * clicking, but you may wish to play these effects in your widget, 26293 * for instance, for internal navigation. 26294 * 26295 * <p>The sound effect will only be played if sound effects are enabled by the user, and 26296 * {@link #isSoundEffectsEnabled()} is true. 26297 * 26298 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}. 26299 */ playSoundEffect(@oundEffectConstants.SoundEffect int soundConstant)26300 public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { 26301 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 26302 return; 26303 } 26304 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 26305 } 26306 26307 /** 26308 * BZZZTT!!1! 26309 * 26310 * <p>Provide haptic feedback to the user for this view. 26311 * 26312 * <p>The framework will provide haptic feedback for some built in actions, 26313 * such as long presses, but you may wish to provide feedback for your 26314 * own widget. 26315 * 26316 * <p>The feedback will only be performed if 26317 * {@link #isHapticFeedbackEnabled()} is true. 26318 * 26319 * @param feedbackConstant One of the constants defined in 26320 * {@link HapticFeedbackConstants} 26321 */ performHapticFeedback(int feedbackConstant)26322 public boolean performHapticFeedback(int feedbackConstant) { 26323 return performHapticFeedback(feedbackConstant, 0); 26324 } 26325 26326 /** 26327 * BZZZTT!!1! 26328 * 26329 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 26330 * 26331 * @param feedbackConstant One of the constants defined in 26332 * {@link HapticFeedbackConstants} 26333 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 26334 */ performHapticFeedback(int feedbackConstant, int flags)26335 public boolean performHapticFeedback(int feedbackConstant, int flags) { 26336 if (mAttachInfo == null) { 26337 return false; 26338 } 26339 //noinspection SimplifiableIfStatement 26340 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 26341 && !isHapticFeedbackEnabled()) { 26342 return false; 26343 } 26344 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 26345 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 26346 } 26347 26348 /** 26349 * Request that the visibility of the status bar or other screen/window 26350 * decorations be changed. 26351 * 26352 * <p>This method is used to put the over device UI into temporary modes 26353 * where the user's attention is focused more on the application content, 26354 * by dimming or hiding surrounding system affordances. This is typically 26355 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 26356 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 26357 * to be placed behind the action bar (and with these flags other system 26358 * affordances) so that smooth transitions between hiding and showing them 26359 * can be done. 26360 * 26361 * <p>Two representative examples of the use of system UI visibility is 26362 * implementing a content browsing application (like a magazine reader) 26363 * and a video playing application. 26364 * 26365 * <p>The first code shows a typical implementation of a View in a content 26366 * browsing application. In this implementation, the application goes 26367 * into a content-oriented mode by hiding the status bar and action bar, 26368 * and putting the navigation elements into lights out mode. The user can 26369 * then interact with content while in this mode. Such an application should 26370 * provide an easy way for the user to toggle out of the mode (such as to 26371 * check information in the status bar or access notifications). In the 26372 * implementation here, this is done simply by tapping on the content. 26373 * 26374 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 26375 * content} 26376 * 26377 * <p>This second code sample shows a typical implementation of a View 26378 * in a video playing application. In this situation, while the video is 26379 * playing the application would like to go into a complete full-screen mode, 26380 * to use as much of the display as possible for the video. When in this state 26381 * the user can not interact with the application; the system intercepts 26382 * touching on the screen to pop the UI out of full screen mode. See 26383 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 26384 * 26385 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 26386 * content} 26387 * 26388 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26389 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 26390 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 26391 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 26392 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 26393 * 26394 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26395 * instead. 26396 */ 26397 @Deprecated setSystemUiVisibility(int visibility)26398 public void setSystemUiVisibility(int visibility) { 26399 if (visibility != mSystemUiVisibility) { 26400 mSystemUiVisibility = visibility; 26401 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 26402 mParent.recomputeViewAttributes(this); 26403 } 26404 } 26405 } 26406 26407 /** 26408 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 26409 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26410 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 26411 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 26412 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 26413 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 26414 * 26415 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26416 * instead. 26417 */ 26418 @Deprecated getSystemUiVisibility()26419 public int getSystemUiVisibility() { 26420 return mSystemUiVisibility; 26421 } 26422 26423 /** 26424 * Returns the current system UI visibility that is currently set for 26425 * the entire window. This is the combination of the 26426 * {@link #setSystemUiVisibility(int)} values supplied by all of the 26427 * views in the window. 26428 * 26429 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26430 * instead. 26431 */ 26432 @Deprecated getWindowSystemUiVisibility()26433 public int getWindowSystemUiVisibility() { 26434 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 26435 } 26436 26437 /** 26438 * Override to find out when the window's requested system UI visibility 26439 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 26440 * This is different from the callbacks received through 26441 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 26442 * in that this is only telling you about the local request of the window, 26443 * not the actual values applied by the system. 26444 * 26445 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26446 * instead. 26447 */ 26448 @Deprecated onWindowSystemUiVisibilityChanged(int visible)26449 public void onWindowSystemUiVisibilityChanged(int visible) { 26450 } 26451 26452 /** 26453 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 26454 * the view hierarchy. 26455 * 26456 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26457 * instead. 26458 */ 26459 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)26460 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 26461 onWindowSystemUiVisibilityChanged(visible); 26462 } 26463 26464 /** 26465 * Set a listener to receive callbacks when the visibility of the system bar changes. 26466 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 26467 * 26468 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 26469 * by setting a {@link OnApplyWindowInsetsListener} on this view. 26470 */ 26471 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)26472 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 26473 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 26474 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 26475 mParent.recomputeViewAttributes(this); 26476 } 26477 } 26478 26479 /** 26480 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 26481 * the view hierarchy. 26482 * 26483 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 26484 * by setting a {@link OnApplyWindowInsetsListener} on this view. 26485 */ 26486 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)26487 public void dispatchSystemUiVisibilityChanged(int visibility) { 26488 ListenerInfo li = mListenerInfo; 26489 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 26490 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 26491 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 26492 } 26493 } 26494 updateLocalSystemUiVisibility(int localValue, int localChanges)26495 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 26496 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 26497 if (val != mSystemUiVisibility) { 26498 setSystemUiVisibility(val); 26499 return true; 26500 } 26501 return false; 26502 } 26503 26504 /** @hide */ 26505 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setDisabledSystemUiVisibility(int flags)26506 public void setDisabledSystemUiVisibility(int flags) { 26507 if (mAttachInfo != null) { 26508 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 26509 mAttachInfo.mDisabledSystemUiVisibility = flags; 26510 if (mParent != null) { 26511 mParent.recomputeViewAttributes(this); 26512 } 26513 } 26514 } 26515 } 26516 26517 /** 26518 * This needs to be a better API before it is exposed. For now, only the root view will get 26519 * notified. 26520 * @hide 26521 */ onSystemBarAppearanceChanged(@indowInsetsController.Appearance int appearance)26522 public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { 26523 } 26524 26525 /** 26526 * Creates an image that the system displays during the drag and drop 26527 * operation. This is called a "drag shadow". The default implementation 26528 * for a DragShadowBuilder based on a View returns an image that has exactly the same 26529 * appearance as the given View. The default also positions the center of the drag shadow 26530 * directly under the touch point. If no View is provided (the constructor with no parameters 26531 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 26532 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 26533 * default is an invisible drag shadow. 26534 * <p> 26535 * You are not required to use the View you provide to the constructor as the basis of the 26536 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 26537 * anything you want as the drag shadow. 26538 * </p> 26539 * <p> 26540 * You pass a DragShadowBuilder object to the system when you start the drag. The system 26541 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 26542 * size and position of the drag shadow. It uses this data to construct a 26543 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 26544 * so that your application can draw the shadow image in the Canvas. 26545 * </p> 26546 * 26547 * <div class="special reference"> 26548 * <h3>Developer Guides</h3> 26549 * <p>For a guide to implementing drag and drop features, read the 26550 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 26551 * </div> 26552 */ 26553 public static class DragShadowBuilder { 26554 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 26555 private final WeakReference<View> mView; 26556 26557 /** 26558 * Constructs a shadow image builder based on a View. By default, the resulting drag 26559 * shadow will have the same appearance and dimensions as the View, with the touch point 26560 * over the center of the View. 26561 * @param view A View. Any View in scope can be used. 26562 */ DragShadowBuilder(View view)26563 public DragShadowBuilder(View view) { 26564 mView = new WeakReference<View>(view); 26565 } 26566 26567 /** 26568 * Construct a shadow builder object with no associated View. This 26569 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 26570 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 26571 * to supply the drag shadow's dimensions and appearance without 26572 * reference to any View object. 26573 */ DragShadowBuilder()26574 public DragShadowBuilder() { 26575 mView = new WeakReference<View>(null); 26576 } 26577 26578 /** 26579 * Returns the View object that had been passed to the 26580 * {@link #DragShadowBuilder(View)} 26581 * constructor. If that View parameter was {@code null} or if the 26582 * {@link #DragShadowBuilder()} 26583 * constructor was used to instantiate the builder object, this method will return 26584 * null. 26585 * 26586 * @return The View object associate with this builder object. 26587 */ 26588 @SuppressWarnings({"JavadocReference"}) getView()26589 final public View getView() { 26590 return mView.get(); 26591 } 26592 26593 /** 26594 * Provides the metrics for the shadow image. These include the dimensions of 26595 * the shadow image, and the point within that shadow that should 26596 * be centered under the touch location while dragging. 26597 * <p> 26598 * The default implementation sets the dimensions of the shadow to be the 26599 * same as the dimensions of the View itself and centers the shadow under 26600 * the touch point. 26601 * </p> 26602 * 26603 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 26604 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 26605 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 26606 * image. Since Android P, the width and height must be positive values. 26607 * 26608 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 26609 * shadow image that should be underneath the touch point during the drag and drop 26610 * operation. Your application must set {@link android.graphics.Point#x} to the 26611 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 26612 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)26613 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 26614 final View view = mView.get(); 26615 if (view != null) { 26616 outShadowSize.set(view.getWidth(), view.getHeight()); 26617 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 26618 } else { 26619 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 26620 } 26621 } 26622 26623 /** 26624 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 26625 * based on the dimensions it received from the 26626 * {@link #onProvideShadowMetrics(Point, Point)} callback. 26627 * 26628 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 26629 */ onDrawShadow(Canvas canvas)26630 public void onDrawShadow(Canvas canvas) { 26631 final View view = mView.get(); 26632 if (view != null) { 26633 view.draw(canvas); 26634 } else { 26635 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 26636 } 26637 } 26638 } 26639 26640 /** 26641 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 26642 * startDragAndDrop()} for newer platform versions. 26643 */ 26644 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)26645 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 26646 Object myLocalState, int flags) { 26647 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 26648 } 26649 26650 /** 26651 * Starts a drag and drop operation. When your application calls this method, it passes a 26652 * {@link android.view.View.DragShadowBuilder} object to the system. The 26653 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 26654 * to get metrics for the drag shadow, and then calls the object's 26655 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 26656 * <p> 26657 * Once the system has the drag shadow, it begins the drag and drop operation by sending 26658 * drag events to all the View objects in your application that are currently visible. It does 26659 * this either by calling the View object's drag listener (an implementation of 26660 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 26661 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 26662 * Both are passed a {@link android.view.DragEvent} object that has a 26663 * {@link android.view.DragEvent#getAction()} value of 26664 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 26665 * </p> 26666 * <p> 26667 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 26668 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 26669 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 26670 * to the View the user selected for dragging. 26671 * </p> 26672 * @param data A {@link android.content.ClipData} object pointing to the data to be 26673 * transferred by the drag and drop operation. 26674 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26675 * drag shadow. 26676 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 26677 * drop operation. When dispatching drag events to views in the same activity this object 26678 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 26679 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 26680 * will return null). 26681 * <p> 26682 * myLocalState is a lightweight mechanism for the sending information from the dragged View 26683 * to the target Views. For example, it can contain flags that differentiate between a 26684 * a copy operation and a move operation. 26685 * </p> 26686 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 26687 * flags, or any combination of the following: 26688 * <ul> 26689 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 26690 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 26691 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 26692 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 26693 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 26694 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 26695 * <li>{@link #DRAG_FLAG_ACCESSIBILITY_ACTION}</li> 26696 * </ul> 26697 * @return {@code true} if the method completes successfully, or 26698 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 26699 * do a drag because of another ongoing operation or some other reasons. 26700 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)26701 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 26702 Object myLocalState, int flags) { 26703 if (ViewDebug.DEBUG_DRAG) { 26704 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 26705 } 26706 if (mAttachInfo == null) { 26707 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 26708 return false; 26709 } 26710 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 26711 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 26712 return false; 26713 } 26714 26715 if (data != null) { 26716 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 26717 } 26718 26719 Rect bounds = new Rect(); 26720 getBoundsOnScreen(bounds, true); 26721 26722 Point lastTouchPoint = new Point(); 26723 mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); 26724 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 26725 26726 // Skip surface logic since shadows and animation are not required during the a11y drag 26727 final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); 26728 if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { 26729 try { 26730 IBinder token = mAttachInfo.mSession.performDrag( 26731 mAttachInfo.mWindow, flags, null, 26732 mAttachInfo.mViewRootImpl.getLastTouchSource(), 26733 0f, 0f, 0f, 0f, data); 26734 if (ViewDebug.DEBUG_DRAG) { 26735 Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); 26736 } 26737 if (token != null) { 26738 root.setLocalDragState(myLocalState); 26739 mAttachInfo.mDragToken = token; 26740 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 26741 setAccessibilityDragStarted(true); 26742 } 26743 return token != null; 26744 } catch (Exception e) { 26745 Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); 26746 return false; 26747 } 26748 } 26749 26750 Point shadowSize = new Point(); 26751 Point shadowTouchPoint = new Point(); 26752 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 26753 26754 if ((shadowSize.x < 0) || (shadowSize.y < 0) 26755 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 26756 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 26757 } 26758 26759 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 26760 // does not accept zero size surface. 26761 if (shadowSize.x == 0 || shadowSize.y == 0) { 26762 if (!sAcceptZeroSizeDragShadow) { 26763 throw new IllegalStateException("Drag shadow dimensions must be positive"); 26764 } 26765 shadowSize.x = 1; 26766 shadowSize.y = 1; 26767 } 26768 26769 if (ViewDebug.DEBUG_DRAG) { 26770 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 26771 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 26772 } 26773 26774 final SurfaceSession session = new SurfaceSession(); 26775 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 26776 .setName("drag surface") 26777 .setParent(root.getSurfaceControl()) 26778 .setBufferSize(shadowSize.x, shadowSize.y) 26779 .setFormat(PixelFormat.TRANSLUCENT) 26780 .setCallsite("View.startDragAndDrop") 26781 .build(); 26782 final Surface surface = new Surface(); 26783 surface.copyFrom(surfaceControl); 26784 IBinder token = null; 26785 try { 26786 final Canvas canvas = isHardwareAccelerated() 26787 ? surface.lockHardwareCanvas() 26788 : surface.lockCanvas(null); 26789 try { 26790 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26791 shadowBuilder.onDrawShadow(canvas); 26792 } finally { 26793 surface.unlockCanvasAndPost(canvas); 26794 } 26795 26796 token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, 26797 root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y, 26798 shadowTouchPoint.x, shadowTouchPoint.y, data); 26799 if (ViewDebug.DEBUG_DRAG) { 26800 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 26801 } 26802 if (token != null) { 26803 if (mAttachInfo.mDragSurface != null) { 26804 mAttachInfo.mDragSurface.release(); 26805 } 26806 mAttachInfo.mDragSurface = surface; 26807 mAttachInfo.mDragToken = token; 26808 // Cache the local state object for delivery with DragEvents 26809 root.setLocalDragState(myLocalState); 26810 if (a11yEnabled) { 26811 // Set for AccessibilityEvents 26812 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 26813 } 26814 } 26815 return token != null; 26816 } catch (Exception e) { 26817 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 26818 return false; 26819 } finally { 26820 if (token == null) { 26821 surface.destroy(); 26822 } 26823 session.kill(); 26824 } 26825 } 26826 setAccessibilityDragStarted(boolean started)26827 void setAccessibilityDragStarted(boolean started) { 26828 int pflags4 = mPrivateFlags4; 26829 if (started) { 26830 pflags4 |= PFLAG4_DRAG_A11Y_STARTED; 26831 } else { 26832 pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; 26833 } 26834 26835 if (pflags4 != mPrivateFlags4) { 26836 mPrivateFlags4 = pflags4; 26837 sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); 26838 } 26839 } 26840 startedSystemDragForAccessibility()26841 private boolean startedSystemDragForAccessibility() { 26842 return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; 26843 } 26844 26845 /** 26846 * Cancels an ongoing drag and drop operation. 26847 * <p> 26848 * A {@link android.view.DragEvent} object with 26849 * {@link android.view.DragEvent#getAction()} value of 26850 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 26851 * {@link android.view.DragEvent#getResult()} value of {@code false} 26852 * will be sent to every 26853 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 26854 * even if they are not currently visible. 26855 * </p> 26856 * <p> 26857 * This method can be called on any View in the same window as the View on which 26858 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 26859 * was called. 26860 * </p> 26861 */ cancelDragAndDrop()26862 public final void cancelDragAndDrop() { 26863 if (ViewDebug.DEBUG_DRAG) { 26864 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 26865 } 26866 if (mAttachInfo == null) { 26867 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 26868 return; 26869 } 26870 if (mAttachInfo.mDragToken != null) { 26871 try { 26872 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 26873 } catch (Exception e) { 26874 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 26875 } 26876 mAttachInfo.mDragToken = null; 26877 } else { 26878 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 26879 } 26880 } 26881 26882 /** 26883 * Updates the drag shadow for the ongoing drag and drop operation. 26884 * 26885 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26886 * new drag shadow. 26887 */ updateDragShadow(DragShadowBuilder shadowBuilder)26888 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 26889 if (ViewDebug.DEBUG_DRAG) { 26890 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 26891 } 26892 if (mAttachInfo == null) { 26893 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 26894 return; 26895 } 26896 if (mAttachInfo.mDragToken != null) { 26897 try { 26898 Canvas canvas = isHardwareAccelerated() 26899 ? mAttachInfo.mDragSurface.lockHardwareCanvas() 26900 : mAttachInfo.mDragSurface.lockCanvas(null); 26901 try { 26902 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26903 shadowBuilder.onDrawShadow(canvas); 26904 } finally { 26905 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 26906 } 26907 } catch (Exception e) { 26908 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 26909 } 26910 } else { 26911 Log.e(VIEW_LOG_TAG, "No active drag"); 26912 } 26913 } 26914 26915 /** 26916 * Starts a move from {startX, startY}, the amount of the movement will be the offset 26917 * between {startX, startY} and the new cursor positon. 26918 * @param startX horizontal coordinate where the move started. 26919 * @param startY vertical coordinate where the move started. 26920 * @return whether moving was started successfully. 26921 * @hide 26922 */ startMovingTask(float startX, float startY)26923 public final boolean startMovingTask(float startX, float startY) { 26924 if (ViewDebug.DEBUG_POSITIONING) { 26925 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 26926 } 26927 try { 26928 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 26929 } catch (RemoteException e) { 26930 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 26931 } 26932 return false; 26933 } 26934 26935 /** 26936 * Finish a window move task. 26937 * @hide 26938 */ finishMovingTask()26939 public void finishMovingTask() { 26940 if (ViewDebug.DEBUG_POSITIONING) { 26941 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 26942 } 26943 try { 26944 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 26945 } catch (RemoteException e) { 26946 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 26947 } 26948 } 26949 26950 /** 26951 * Handles drag events sent by the system following a call to 26952 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 26953 * startDragAndDrop()}. 26954 *<p> 26955 * When the system calls this method, it passes a 26956 * {@link android.view.DragEvent} object. A call to 26957 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 26958 * in DragEvent. The method uses these to determine what is happening in the drag and drop 26959 * operation. 26960 * </p> 26961 * <p> 26962 * The default implementation returns false, except if an {@link OnReceiveContentListener} 26963 * is {@link #setOnReceiveContentListener set} for this view. If an 26964 * {@link OnReceiveContentListener} is set, the default implementation... 26965 * <ul> 26966 * <li>returns true for an 26967 * {@link android.view.DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event 26968 * <li>calls {@link #performReceiveContent} for an 26969 * {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event 26970 * <li>returns true for an {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event, if 26971 * the listener consumed some or all of the content 26972 * </ul> 26973 * </p> 26974 * 26975 * @param event The {@link android.view.DragEvent} sent by the system. 26976 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 26977 * in DragEvent, indicating the type of drag event represented by this object. 26978 * @return {@code true} if the method was successful, otherwise {@code false}. 26979 * <p> 26980 * The method should return {@code true} in response to an action type of 26981 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 26982 * operation. 26983 * </p> 26984 * <p> 26985 * The method should also return {@code true} in response to an action type of 26986 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 26987 * {@code false} if it didn't. 26988 * </p> 26989 * <p> 26990 * For all other events, the return value is ignored. 26991 * </p> 26992 */ onDragEvent(DragEvent event)26993 public boolean onDragEvent(DragEvent event) { 26994 if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { 26995 return false; 26996 } 26997 // Accept drag events by default if there's an OnReceiveContentListener set. 26998 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { 26999 return true; 27000 } 27001 if (event.getAction() == DragEvent.ACTION_DROP) { 27002 final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); 27003 if (permissions != null) { 27004 permissions.takeTransient(); 27005 } 27006 final ContentInfo payload = 27007 new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) 27008 .setDragAndDropPermissions(permissions) 27009 .build(); 27010 ContentInfo remainingPayload = performReceiveContent(payload); 27011 // Return true unless none of the payload was consumed. 27012 return remainingPayload != payload; 27013 } 27014 return false; 27015 } 27016 27017 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)27018 boolean dispatchDragEnterExitInPreN(DragEvent event) { 27019 return callDragEventHandler(event); 27020 } 27021 27022 /** 27023 * Detects if this View is enabled and has a drag event listener. 27024 * If both are true, then it calls the drag event listener with the 27025 * {@link android.view.DragEvent} it received. If the drag event listener returns 27026 * {@code true}, then dispatchDragEvent() returns {@code true}. 27027 * <p> 27028 * For all other cases, the method calls the 27029 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 27030 * method and returns its result. 27031 * </p> 27032 * <p> 27033 * This ensures that a drag event is always consumed, even if the View does not have a drag 27034 * event listener. However, if the View has a listener and the listener returns true, then 27035 * onDragEvent() is not called. 27036 * </p> 27037 */ dispatchDragEvent(DragEvent event)27038 public boolean dispatchDragEvent(DragEvent event) { 27039 event.mEventHandlerWasCalled = true; 27040 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 27041 event.mAction == DragEvent.ACTION_DROP) { 27042 // About to deliver an event with coordinates to this view. Notify that now this view 27043 // has drag focus. This will send exit/enter events as needed. 27044 getViewRootImpl().setDragFocus(this, event); 27045 } 27046 return callDragEventHandler(event); 27047 } 27048 callDragEventHandler(DragEvent event)27049 final boolean callDragEventHandler(DragEvent event) { 27050 final boolean result; 27051 27052 ListenerInfo li = mListenerInfo; 27053 //noinspection SimplifiableIfStatement 27054 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 27055 && li.mOnDragListener.onDrag(this, event)) { 27056 result = true; 27057 } else { 27058 result = onDragEvent(event); 27059 } 27060 27061 switch (event.mAction) { 27062 case DragEvent.ACTION_DRAG_STARTED: { 27063 if (result && li != null && li.mOnDragListener != null) { 27064 sendWindowContentChangedAccessibilityEvent( 27065 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 27066 } 27067 } break; 27068 case DragEvent.ACTION_DRAG_ENTERED: { 27069 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 27070 refreshDrawableState(); 27071 } break; 27072 case DragEvent.ACTION_DRAG_EXITED: { 27073 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 27074 refreshDrawableState(); 27075 } break; 27076 case DragEvent.ACTION_DROP: { 27077 if (result && li != null && (li.mOnDragListener != null 27078 || li.mOnReceiveContentListener != null)) { 27079 sendWindowContentChangedAccessibilityEvent( 27080 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); 27081 } 27082 } break; 27083 case DragEvent.ACTION_DRAG_ENDED: { 27084 sendWindowContentChangedAccessibilityEvent( 27085 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 27086 mPrivateFlags2 &= ~View.DRAG_MASK; 27087 refreshDrawableState(); 27088 } break; 27089 } 27090 27091 return result; 27092 } 27093 canAcceptDrag()27094 boolean canAcceptDrag() { 27095 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 27096 } 27097 sendWindowContentChangedAccessibilityEvent(int changeType)27098 void sendWindowContentChangedAccessibilityEvent(int changeType) { 27099 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 27100 AccessibilityEvent event = AccessibilityEvent.obtain(); 27101 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 27102 event.setContentChangeTypes(changeType); 27103 sendAccessibilityEventUnchecked(event); 27104 } 27105 } 27106 27107 /** 27108 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 27109 * it is ever exposed at all. 27110 * @hide 27111 */ 27112 @UnsupportedAppUsage onCloseSystemDialogs(String reason)27113 public void onCloseSystemDialogs(String reason) { 27114 } 27115 27116 /** 27117 * Given a Drawable whose bounds have been set to draw into this view, 27118 * update a Region being computed for 27119 * {@link #gatherTransparentRegion(android.graphics.Region)} so 27120 * that any non-transparent parts of the Drawable are removed from the 27121 * given transparent region. 27122 * 27123 * @param dr The Drawable whose transparency is to be applied to the region. 27124 * @param region A Region holding the current transparency information, 27125 * where any parts of the region that are set are considered to be 27126 * transparent. On return, this region will be modified to have the 27127 * transparency information reduced by the corresponding parts of the 27128 * Drawable that are not transparent. 27129 * {@hide} 27130 */ 27131 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyDrawableToTransparentRegion(Drawable dr, Region region)27132 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 27133 if (DBG) { 27134 Log.i("View", "Getting transparent region for: " + this); 27135 } 27136 final Region r = dr.getTransparentRegion(); 27137 final Rect db = dr.getBounds(); 27138 final AttachInfo attachInfo = mAttachInfo; 27139 if (r != null && attachInfo != null) { 27140 final int w = getRight()-getLeft(); 27141 final int h = getBottom()-getTop(); 27142 if (db.left > 0) { 27143 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 27144 r.op(0, 0, db.left, h, Region.Op.UNION); 27145 } 27146 if (db.right < w) { 27147 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 27148 r.op(db.right, 0, w, h, Region.Op.UNION); 27149 } 27150 if (db.top > 0) { 27151 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 27152 r.op(0, 0, w, db.top, Region.Op.UNION); 27153 } 27154 if (db.bottom < h) { 27155 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 27156 r.op(0, db.bottom, w, h, Region.Op.UNION); 27157 } 27158 final int[] location = attachInfo.mTransparentLocation; 27159 getLocationInWindow(location); 27160 r.translate(location[0], location[1]); 27161 region.op(r, Region.Op.INTERSECT); 27162 } else { 27163 region.op(db, Region.Op.DIFFERENCE); 27164 } 27165 } 27166 checkForLongClick(long delay, float x, float y, int classification)27167 private void checkForLongClick(long delay, float x, float y, int classification) { 27168 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 27169 mHasPerformedLongPress = false; 27170 27171 if (mPendingCheckForLongPress == null) { 27172 mPendingCheckForLongPress = new CheckForLongPress(); 27173 } 27174 mPendingCheckForLongPress.setAnchor(x, y); 27175 mPendingCheckForLongPress.rememberWindowAttachCount(); 27176 mPendingCheckForLongPress.rememberPressedState(); 27177 mPendingCheckForLongPress.setClassification(classification); 27178 postDelayed(mPendingCheckForLongPress, delay); 27179 } 27180 } 27181 27182 /** 27183 * Inflate a view from an XML resource. This convenience method wraps the {@link 27184 * LayoutInflater} class, which provides a full range of options for view inflation. 27185 * 27186 * @param context The Context object for your activity or application. 27187 * @param resource The resource ID to inflate 27188 * @param root A view group that will be the parent. Used to properly inflate the 27189 * layout_* parameters. 27190 * @see LayoutInflater 27191 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)27192 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 27193 LayoutInflater factory = LayoutInflater.from(context); 27194 return factory.inflate(resource, root); 27195 } 27196 27197 /** 27198 * Scroll the view with standard behavior for scrolling beyond the normal 27199 * content boundaries. Views that call this method should override 27200 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 27201 * results of an over-scroll operation. 27202 * 27203 * Views can use this method to handle any touch or fling-based scrolling. 27204 * 27205 * @param deltaX Change in X in pixels 27206 * @param deltaY Change in Y in pixels 27207 * @param scrollX Current X scroll value in pixels before applying deltaX 27208 * @param scrollY Current Y scroll value in pixels before applying deltaY 27209 * @param scrollRangeX Maximum content scroll range along the X axis 27210 * @param scrollRangeY Maximum content scroll range along the Y axis 27211 * @param maxOverScrollX Number of pixels to overscroll by in either direction 27212 * along the X axis. 27213 * @param maxOverScrollY Number of pixels to overscroll by in either direction 27214 * along the Y axis. 27215 * @param isTouchEvent true if this scroll operation is the result of a touch event. 27216 * @return true if scrolling was clamped to an over-scroll boundary along either 27217 * axis, false otherwise. 27218 */ 27219 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)27220 protected boolean overScrollBy(int deltaX, int deltaY, 27221 int scrollX, int scrollY, 27222 int scrollRangeX, int scrollRangeY, 27223 int maxOverScrollX, int maxOverScrollY, 27224 boolean isTouchEvent) { 27225 final int overScrollMode = mOverScrollMode; 27226 final boolean canScrollHorizontal = 27227 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 27228 final boolean canScrollVertical = 27229 computeVerticalScrollRange() > computeVerticalScrollExtent(); 27230 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 27231 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 27232 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 27233 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 27234 27235 int newScrollX = scrollX + deltaX; 27236 if (!overScrollHorizontal) { 27237 maxOverScrollX = 0; 27238 } 27239 27240 int newScrollY = scrollY + deltaY; 27241 if (!overScrollVertical) { 27242 maxOverScrollY = 0; 27243 } 27244 27245 // Clamp values if at the limits and record 27246 final int left = -maxOverScrollX; 27247 final int right = maxOverScrollX + scrollRangeX; 27248 final int top = -maxOverScrollY; 27249 final int bottom = maxOverScrollY + scrollRangeY; 27250 27251 boolean clampedX = false; 27252 if (newScrollX > right) { 27253 newScrollX = right; 27254 clampedX = true; 27255 } else if (newScrollX < left) { 27256 newScrollX = left; 27257 clampedX = true; 27258 } 27259 27260 boolean clampedY = false; 27261 if (newScrollY > bottom) { 27262 newScrollY = bottom; 27263 clampedY = true; 27264 } else if (newScrollY < top) { 27265 newScrollY = top; 27266 clampedY = true; 27267 } 27268 27269 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 27270 27271 return clampedX || clampedY; 27272 } 27273 27274 /** 27275 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 27276 * respond to the results of an over-scroll operation. 27277 * 27278 * @param scrollX New X scroll value in pixels 27279 * @param scrollY New Y scroll value in pixels 27280 * @param clampedX True if scrollX was clamped to an over-scroll boundary 27281 * @param clampedY True if scrollY was clamped to an over-scroll boundary 27282 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)27283 protected void onOverScrolled(int scrollX, int scrollY, 27284 boolean clampedX, boolean clampedY) { 27285 // Intentionally empty. 27286 } 27287 27288 /** 27289 * Returns the over-scroll mode for this view. The result will be 27290 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 27291 * (allow over-scrolling only if the view content is larger than the container), 27292 * or {@link #OVER_SCROLL_NEVER}. 27293 * 27294 * @return This view's over-scroll mode. 27295 */ 27296 @InspectableProperty(enumMapping = { 27297 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 27298 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 27299 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 27300 }) getOverScrollMode()27301 public int getOverScrollMode() { 27302 return mOverScrollMode; 27303 } 27304 27305 /** 27306 * Set the over-scroll mode for this view. Valid over-scroll modes are 27307 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 27308 * (allow over-scrolling only if the view content is larger than the container), 27309 * or {@link #OVER_SCROLL_NEVER}. 27310 * 27311 * Setting the over-scroll mode of a view will have an effect only if the 27312 * view is capable of scrolling. 27313 * 27314 * @param overScrollMode The new over-scroll mode for this view. 27315 */ setOverScrollMode(int overScrollMode)27316 public void setOverScrollMode(int overScrollMode) { 27317 if (overScrollMode != OVER_SCROLL_ALWAYS && 27318 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 27319 overScrollMode != OVER_SCROLL_NEVER) { 27320 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 27321 } 27322 mOverScrollMode = overScrollMode; 27323 } 27324 27325 /** 27326 * Enable or disable nested scrolling for this view. 27327 * 27328 * <p>If this property is set to true the view will be permitted to initiate nested 27329 * scrolling operations with a compatible parent view in the current hierarchy. If this 27330 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 27331 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 27332 * the nested scroll.</p> 27333 * 27334 * @param enabled true to enable nested scrolling, false to disable 27335 * 27336 * @see #isNestedScrollingEnabled() 27337 */ setNestedScrollingEnabled(boolean enabled)27338 public void setNestedScrollingEnabled(boolean enabled) { 27339 if (enabled) { 27340 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 27341 } else { 27342 stopNestedScroll(); 27343 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 27344 } 27345 } 27346 27347 /** 27348 * Returns true if nested scrolling is enabled for this view. 27349 * 27350 * <p>If nested scrolling is enabled and this View class implementation supports it, 27351 * this view will act as a nested scrolling child view when applicable, forwarding data 27352 * about the scroll operation in progress to a compatible and cooperating nested scrolling 27353 * parent.</p> 27354 * 27355 * @return true if nested scrolling is enabled 27356 * 27357 * @see #setNestedScrollingEnabled(boolean) 27358 */ 27359 @InspectableProperty isNestedScrollingEnabled()27360 public boolean isNestedScrollingEnabled() { 27361 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 27362 PFLAG3_NESTED_SCROLLING_ENABLED; 27363 } 27364 27365 /** 27366 * Begin a nestable scroll operation along the given axes. 27367 * 27368 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 27369 * 27370 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 27371 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 27372 * In the case of touch scrolling the nested scroll will be terminated automatically in 27373 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 27374 * In the event of programmatic scrolling the caller must explicitly call 27375 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 27376 * 27377 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 27378 * If it returns false the caller may ignore the rest of this contract until the next scroll. 27379 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 27380 * 27381 * <p>At each incremental step of the scroll the caller should invoke 27382 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 27383 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 27384 * parent at least partially consumed the scroll and the caller should adjust the amount it 27385 * scrolls by.</p> 27386 * 27387 * <p>After applying the remainder of the scroll delta the caller should invoke 27388 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 27389 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 27390 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 27391 * </p> 27392 * 27393 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 27394 * {@link #SCROLL_AXIS_VERTICAL}. 27395 * @return true if a cooperative parent was found and nested scrolling has been enabled for 27396 * the current gesture. 27397 * 27398 * @see #stopNestedScroll() 27399 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 27400 * @see #dispatchNestedScroll(int, int, int, int, int[]) 27401 */ startNestedScroll(int axes)27402 public boolean startNestedScroll(int axes) { 27403 if (hasNestedScrollingParent()) { 27404 // Already in progress 27405 return true; 27406 } 27407 if (isNestedScrollingEnabled()) { 27408 ViewParent p = getParent(); 27409 View child = this; 27410 while (p != null) { 27411 try { 27412 if (p.onStartNestedScroll(child, this, axes)) { 27413 mNestedScrollingParent = p; 27414 p.onNestedScrollAccepted(child, this, axes); 27415 return true; 27416 } 27417 } catch (AbstractMethodError e) { 27418 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 27419 "method onStartNestedScroll", e); 27420 // Allow the search upward to continue 27421 } 27422 if (p instanceof View) { 27423 child = (View) p; 27424 } 27425 p = p.getParent(); 27426 } 27427 } 27428 return false; 27429 } 27430 27431 /** 27432 * Stop a nested scroll in progress. 27433 * 27434 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 27435 * 27436 * @see #startNestedScroll(int) 27437 */ stopNestedScroll()27438 public void stopNestedScroll() { 27439 if (mNestedScrollingParent != null) { 27440 mNestedScrollingParent.onStopNestedScroll(this); 27441 mNestedScrollingParent = null; 27442 } 27443 } 27444 27445 /** 27446 * Returns true if this view has a nested scrolling parent. 27447 * 27448 * <p>The presence of a nested scrolling parent indicates that this view has initiated 27449 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 27450 * 27451 * @return whether this view has a nested scrolling parent 27452 */ hasNestedScrollingParent()27453 public boolean hasNestedScrollingParent() { 27454 return mNestedScrollingParent != null; 27455 } 27456 27457 /** 27458 * Dispatch one step of a nested scroll in progress. 27459 * 27460 * <p>Implementations of views that support nested scrolling should call this to report 27461 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 27462 * is not currently in progress or nested scrolling is not 27463 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 27464 * 27465 * <p>Compatible View implementations should also call 27466 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 27467 * consuming a component of the scroll event themselves.</p> 27468 * 27469 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 27470 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 27471 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 27472 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 27473 * @param offsetInWindow Optional. If not null, on return this will contain the offset 27474 * in local view coordinates of this view from before this operation 27475 * to after it completes. View implementations may use this to adjust 27476 * expected input coordinate tracking. 27477 * @return true if the event was dispatched, false if it could not be dispatched. 27478 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 27479 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)27480 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 27481 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 27482 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27483 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 27484 int startX = 0; 27485 int startY = 0; 27486 if (offsetInWindow != null) { 27487 getLocationInWindow(offsetInWindow); 27488 startX = offsetInWindow[0]; 27489 startY = offsetInWindow[1]; 27490 } 27491 27492 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 27493 dxUnconsumed, dyUnconsumed); 27494 27495 if (offsetInWindow != null) { 27496 getLocationInWindow(offsetInWindow); 27497 offsetInWindow[0] -= startX; 27498 offsetInWindow[1] -= startY; 27499 } 27500 return true; 27501 } else if (offsetInWindow != null) { 27502 // No motion, no dispatch. Keep offsetInWindow up to date. 27503 offsetInWindow[0] = 0; 27504 offsetInWindow[1] = 0; 27505 } 27506 } 27507 return false; 27508 } 27509 27510 /** 27511 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 27512 * 27513 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 27514 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 27515 * scrolling operation to consume some or all of the scroll operation before the child view 27516 * consumes it.</p> 27517 * 27518 * @param dx Horizontal scroll distance in pixels 27519 * @param dy Vertical scroll distance in pixels 27520 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 27521 * and consumed[1] the consumed dy. 27522 * @param offsetInWindow Optional. If not null, on return this will contain the offset 27523 * in local view coordinates of this view from before this operation 27524 * to after it completes. View implementations may use this to adjust 27525 * expected input coordinate tracking. 27526 * @return true if the parent consumed some or all of the scroll delta 27527 * @see #dispatchNestedScroll(int, int, int, int, int[]) 27528 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)27529 public boolean dispatchNestedPreScroll(int dx, int dy, 27530 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 27531 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27532 if (dx != 0 || dy != 0) { 27533 int startX = 0; 27534 int startY = 0; 27535 if (offsetInWindow != null) { 27536 getLocationInWindow(offsetInWindow); 27537 startX = offsetInWindow[0]; 27538 startY = offsetInWindow[1]; 27539 } 27540 27541 if (consumed == null) { 27542 if (mTempNestedScrollConsumed == null) { 27543 mTempNestedScrollConsumed = new int[2]; 27544 } 27545 consumed = mTempNestedScrollConsumed; 27546 } 27547 consumed[0] = 0; 27548 consumed[1] = 0; 27549 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 27550 27551 if (offsetInWindow != null) { 27552 getLocationInWindow(offsetInWindow); 27553 offsetInWindow[0] -= startX; 27554 offsetInWindow[1] -= startY; 27555 } 27556 return consumed[0] != 0 || consumed[1] != 0; 27557 } else if (offsetInWindow != null) { 27558 offsetInWindow[0] = 0; 27559 offsetInWindow[1] = 0; 27560 } 27561 } 27562 return false; 27563 } 27564 27565 /** 27566 * Dispatch a fling to a nested scrolling parent. 27567 * 27568 * <p>This method should be used to indicate that a nested scrolling child has detected 27569 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 27570 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 27571 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 27572 * along a scrollable axis.</p> 27573 * 27574 * <p>If a nested scrolling child view would normally fling but it is at the edge of 27575 * its own content, it can use this method to delegate the fling to its nested scrolling 27576 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 27577 * 27578 * @param velocityX Horizontal fling velocity in pixels per second 27579 * @param velocityY Vertical fling velocity in pixels per second 27580 * @param consumed true if the child consumed the fling, false otherwise 27581 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 27582 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)27583 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 27584 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27585 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 27586 } 27587 return false; 27588 } 27589 27590 /** 27591 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 27592 * 27593 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 27594 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 27595 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 27596 * before the child view consumes it. If this method returns <code>true</code>, a nested 27597 * parent view consumed the fling and this view should not scroll as a result.</p> 27598 * 27599 * <p>For a better user experience, only one view in a nested scrolling chain should consume 27600 * the fling at a time. If a parent view consumed the fling this method will return false. 27601 * Custom view implementations should account for this in two ways:</p> 27602 * 27603 * <ul> 27604 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 27605 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 27606 * position regardless.</li> 27607 * <li>If a nested parent does consume the fling, this view should not scroll at all, 27608 * even to settle back to a valid idle position.</li> 27609 * </ul> 27610 * 27611 * <p>Views should also not offer fling velocities to nested parent views along an axis 27612 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 27613 * should not offer a horizontal fling velocity to its parents since scrolling along that 27614 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 27615 * 27616 * @param velocityX Horizontal fling velocity in pixels per second 27617 * @param velocityY Vertical fling velocity in pixels per second 27618 * @return true if a nested scrolling parent consumed the fling 27619 */ dispatchNestedPreFling(float velocityX, float velocityY)27620 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 27621 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27622 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 27623 } 27624 return false; 27625 } 27626 27627 /** 27628 * Gets a scale factor that determines the distance the view should scroll 27629 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 27630 * @return The vertical scroll scale factor. 27631 * @hide 27632 */ 27633 @UnsupportedAppUsage getVerticalScrollFactor()27634 protected float getVerticalScrollFactor() { 27635 if (mVerticalScrollFactor == 0) { 27636 TypedValue outValue = new TypedValue(); 27637 if (!mContext.getTheme().resolveAttribute( 27638 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 27639 throw new IllegalStateException( 27640 "Expected theme to define listPreferredItemHeight."); 27641 } 27642 mVerticalScrollFactor = outValue.getDimension( 27643 mContext.getResources().getDisplayMetrics()); 27644 } 27645 return mVerticalScrollFactor; 27646 } 27647 27648 /** 27649 * Gets a scale factor that determines the distance the view should scroll 27650 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 27651 * @return The horizontal scroll scale factor. 27652 * @hide 27653 */ 27654 @UnsupportedAppUsage getHorizontalScrollFactor()27655 protected float getHorizontalScrollFactor() { 27656 // TODO: Should use something else. 27657 return getVerticalScrollFactor(); 27658 } 27659 27660 /** 27661 * Return the value specifying the text direction or policy that was set with 27662 * {@link #setTextDirection(int)}. 27663 * 27664 * @return the defined text direction. It can be one of: 27665 * 27666 * {@link #TEXT_DIRECTION_INHERIT}, 27667 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27668 * {@link #TEXT_DIRECTION_ANY_RTL}, 27669 * {@link #TEXT_DIRECTION_LTR}, 27670 * {@link #TEXT_DIRECTION_RTL}, 27671 * {@link #TEXT_DIRECTION_LOCALE}, 27672 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27673 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 27674 * 27675 * @attr ref android.R.styleable#View_textDirection 27676 * 27677 * @hide 27678 */ 27679 @ViewDebug.ExportedProperty(category = "text", mapping = { 27680 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 27681 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 27682 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 27683 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 27684 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 27685 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 27686 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 27687 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 27688 }) 27689 @InspectableProperty(hasAttributeId = false, enumMapping = { 27690 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 27691 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 27692 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 27693 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 27694 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 27695 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 27696 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 27697 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 27698 }) 27699 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextDirection()27700 public int getRawTextDirection() { 27701 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 27702 } 27703 27704 /** 27705 * Set the text direction. 27706 * 27707 * @param textDirection the direction to set. Should be one of: 27708 * 27709 * {@link #TEXT_DIRECTION_INHERIT}, 27710 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27711 * {@link #TEXT_DIRECTION_ANY_RTL}, 27712 * {@link #TEXT_DIRECTION_LTR}, 27713 * {@link #TEXT_DIRECTION_RTL}, 27714 * {@link #TEXT_DIRECTION_LOCALE} 27715 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27716 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 27717 * 27718 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 27719 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 27720 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 27721 * 27722 * @attr ref android.R.styleable#View_textDirection 27723 */ setTextDirection(int textDirection)27724 public void setTextDirection(int textDirection) { 27725 if (getRawTextDirection() != textDirection) { 27726 // Reset the current text direction and the resolved one 27727 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 27728 resetResolvedTextDirection(); 27729 // Set the new text direction 27730 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 27731 // Do resolution 27732 resolveTextDirection(); 27733 // Notify change 27734 onRtlPropertiesChanged(getLayoutDirection()); 27735 // Refresh 27736 requestLayout(); 27737 invalidate(true); 27738 } 27739 } 27740 27741 /** 27742 * Return the resolved text direction. 27743 * 27744 * @return the resolved text direction. Returns one of: 27745 * 27746 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27747 * {@link #TEXT_DIRECTION_ANY_RTL}, 27748 * {@link #TEXT_DIRECTION_LTR}, 27749 * {@link #TEXT_DIRECTION_RTL}, 27750 * {@link #TEXT_DIRECTION_LOCALE}, 27751 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27752 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 27753 * 27754 * @attr ref android.R.styleable#View_textDirection 27755 */ 27756 @ViewDebug.ExportedProperty(category = "text", mapping = { 27757 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 27758 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 27759 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 27760 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 27761 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 27762 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 27763 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 27764 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 27765 }) 27766 @InspectableProperty(hasAttributeId = false, enumMapping = { 27767 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 27768 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 27769 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 27770 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 27771 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 27772 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 27773 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 27774 }) getTextDirection()27775 public int getTextDirection() { 27776 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 27777 } 27778 27779 /** 27780 * Resolve the text direction. 27781 * 27782 * @return true if resolution has been done, false otherwise. 27783 * 27784 * @hide 27785 */ resolveTextDirection()27786 public boolean resolveTextDirection() { 27787 // Reset any previous text direction resolution 27788 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27789 27790 if (hasRtlSupport()) { 27791 // Set resolved text direction flag depending on text direction flag 27792 final int textDirection = getRawTextDirection(); 27793 switch(textDirection) { 27794 case TEXT_DIRECTION_INHERIT: 27795 if (!canResolveTextDirection()) { 27796 // We cannot do the resolution if there is no parent, so use the default one 27797 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27798 // Resolution will need to happen again later 27799 return false; 27800 } 27801 27802 // Parent has not yet resolved, so we still return the default 27803 try { 27804 if (!mParent.isTextDirectionResolved()) { 27805 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27806 // Resolution will need to happen again later 27807 return false; 27808 } 27809 } catch (AbstractMethodError e) { 27810 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27811 " does not fully implement ViewParent", e); 27812 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 27813 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27814 return true; 27815 } 27816 27817 // Set current resolved direction to the same value as the parent's one 27818 int parentResolvedDirection; 27819 try { 27820 parentResolvedDirection = mParent.getTextDirection(); 27821 } catch (AbstractMethodError e) { 27822 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27823 " does not fully implement ViewParent", e); 27824 parentResolvedDirection = TEXT_DIRECTION_LTR; 27825 } 27826 switch (parentResolvedDirection) { 27827 case TEXT_DIRECTION_FIRST_STRONG: 27828 case TEXT_DIRECTION_ANY_RTL: 27829 case TEXT_DIRECTION_LTR: 27830 case TEXT_DIRECTION_RTL: 27831 case TEXT_DIRECTION_LOCALE: 27832 case TEXT_DIRECTION_FIRST_STRONG_LTR: 27833 case TEXT_DIRECTION_FIRST_STRONG_RTL: 27834 mPrivateFlags2 |= 27835 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 27836 break; 27837 default: 27838 // Default resolved direction is "first strong" heuristic 27839 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27840 } 27841 break; 27842 case TEXT_DIRECTION_FIRST_STRONG: 27843 case TEXT_DIRECTION_ANY_RTL: 27844 case TEXT_DIRECTION_LTR: 27845 case TEXT_DIRECTION_RTL: 27846 case TEXT_DIRECTION_LOCALE: 27847 case TEXT_DIRECTION_FIRST_STRONG_LTR: 27848 case TEXT_DIRECTION_FIRST_STRONG_RTL: 27849 // Resolved direction is the same as text direction 27850 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 27851 break; 27852 default: 27853 // Default resolved direction is "first strong" heuristic 27854 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27855 } 27856 } else { 27857 // Default resolved direction is "first strong" heuristic 27858 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27859 } 27860 27861 // Set to resolved 27862 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 27863 return true; 27864 } 27865 27866 /** 27867 * Check if text direction resolution can be done. 27868 * 27869 * @return true if text direction resolution can be done otherwise return false. 27870 */ canResolveTextDirection()27871 public boolean canResolveTextDirection() { 27872 switch (getRawTextDirection()) { 27873 case TEXT_DIRECTION_INHERIT: 27874 if (mParent != null) { 27875 try { 27876 return mParent.canResolveTextDirection(); 27877 } catch (AbstractMethodError e) { 27878 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27879 " does not fully implement ViewParent", e); 27880 } 27881 } 27882 return false; 27883 27884 default: 27885 return true; 27886 } 27887 } 27888 27889 /** 27890 * Reset resolved text direction. Text direction will be resolved during a call to 27891 * {@link #onMeasure(int, int)}. 27892 * 27893 * @hide 27894 */ 27895 @TestApi resetResolvedTextDirection()27896 public void resetResolvedTextDirection() { 27897 // Reset any previous text direction resolution 27898 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27899 // Set to default value 27900 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27901 } 27902 27903 /** 27904 * @return true if text direction is inherited. 27905 * 27906 * @hide 27907 */ isTextDirectionInherited()27908 public boolean isTextDirectionInherited() { 27909 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 27910 } 27911 27912 /** 27913 * @return true if text direction is resolved. 27914 */ isTextDirectionResolved()27915 public boolean isTextDirectionResolved() { 27916 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 27917 } 27918 27919 /** 27920 * Return the value specifying the text alignment or policy that was set with 27921 * {@link #setTextAlignment(int)}. 27922 * 27923 * @return the defined text alignment. It can be one of: 27924 * 27925 * {@link #TEXT_ALIGNMENT_INHERIT}, 27926 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27927 * {@link #TEXT_ALIGNMENT_CENTER}, 27928 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27929 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27930 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27931 * {@link #TEXT_ALIGNMENT_VIEW_END} 27932 * 27933 * @attr ref android.R.styleable#View_textAlignment 27934 * 27935 * @hide 27936 */ 27937 @ViewDebug.ExportedProperty(category = "text", mapping = { 27938 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27939 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27940 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27941 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27942 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27943 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27944 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27945 }) 27946 @InspectableProperty(hasAttributeId = false, enumMapping = { 27947 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 27948 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27949 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27950 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27951 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27952 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27953 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27954 }) 27955 @TextAlignment 27956 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextAlignment()27957 public int getRawTextAlignment() { 27958 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 27959 } 27960 27961 /** 27962 * Set the text alignment. 27963 * 27964 * @param textAlignment The text alignment to set. Should be one of 27965 * 27966 * {@link #TEXT_ALIGNMENT_INHERIT}, 27967 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27968 * {@link #TEXT_ALIGNMENT_CENTER}, 27969 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27970 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27971 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27972 * {@link #TEXT_ALIGNMENT_VIEW_END} 27973 * 27974 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 27975 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 27976 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 27977 * 27978 * @attr ref android.R.styleable#View_textAlignment 27979 */ setTextAlignment(@extAlignment int textAlignment)27980 public void setTextAlignment(@TextAlignment int textAlignment) { 27981 if (textAlignment != getRawTextAlignment()) { 27982 // Reset the current and resolved text alignment 27983 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 27984 resetResolvedTextAlignment(); 27985 // Set the new text alignment 27986 mPrivateFlags2 |= 27987 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 27988 // Do resolution 27989 resolveTextAlignment(); 27990 // Notify change 27991 onRtlPropertiesChanged(getLayoutDirection()); 27992 // Refresh 27993 requestLayout(); 27994 invalidate(true); 27995 } 27996 } 27997 27998 /** 27999 * Return the resolved text alignment. 28000 * 28001 * @return the resolved text alignment. Returns one of: 28002 * 28003 * {@link #TEXT_ALIGNMENT_GRAVITY}, 28004 * {@link #TEXT_ALIGNMENT_CENTER}, 28005 * {@link #TEXT_ALIGNMENT_TEXT_START}, 28006 * {@link #TEXT_ALIGNMENT_TEXT_END}, 28007 * {@link #TEXT_ALIGNMENT_VIEW_START}, 28008 * {@link #TEXT_ALIGNMENT_VIEW_END} 28009 * 28010 * @attr ref android.R.styleable#View_textAlignment 28011 */ 28012 @ViewDebug.ExportedProperty(category = "text", mapping = { 28013 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 28014 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 28015 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 28016 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 28017 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 28018 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 28019 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 28020 }) 28021 @InspectableProperty(enumMapping = { 28022 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 28023 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 28024 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 28025 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 28026 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 28027 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 28028 }) 28029 @TextAlignment getTextAlignment()28030 public int getTextAlignment() { 28031 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 28032 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 28033 } 28034 28035 /** 28036 * Resolve the text alignment. 28037 * 28038 * @return true if resolution has been done, false otherwise. 28039 * 28040 * @hide 28041 */ resolveTextAlignment()28042 public boolean resolveTextAlignment() { 28043 // Reset any previous text alignment resolution 28044 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 28045 28046 if (hasRtlSupport()) { 28047 // Set resolved text alignment flag depending on text alignment flag 28048 final int textAlignment = getRawTextAlignment(); 28049 switch (textAlignment) { 28050 case TEXT_ALIGNMENT_INHERIT: 28051 // Check if we can resolve the text alignment 28052 if (!canResolveTextAlignment()) { 28053 // We cannot do the resolution if there is no parent so use the default 28054 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28055 // Resolution will need to happen again later 28056 return false; 28057 } 28058 28059 // Parent has not yet resolved, so we still return the default 28060 try { 28061 if (!mParent.isTextAlignmentResolved()) { 28062 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28063 // Resolution will need to happen again later 28064 return false; 28065 } 28066 } catch (AbstractMethodError e) { 28067 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28068 " does not fully implement ViewParent", e); 28069 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 28070 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28071 return true; 28072 } 28073 28074 int parentResolvedTextAlignment; 28075 try { 28076 parentResolvedTextAlignment = mParent.getTextAlignment(); 28077 } catch (AbstractMethodError e) { 28078 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28079 " does not fully implement ViewParent", e); 28080 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 28081 } 28082 switch (parentResolvedTextAlignment) { 28083 case TEXT_ALIGNMENT_GRAVITY: 28084 case TEXT_ALIGNMENT_TEXT_START: 28085 case TEXT_ALIGNMENT_TEXT_END: 28086 case TEXT_ALIGNMENT_CENTER: 28087 case TEXT_ALIGNMENT_VIEW_START: 28088 case TEXT_ALIGNMENT_VIEW_END: 28089 // Resolved text alignment is the same as the parent resolved 28090 // text alignment 28091 mPrivateFlags2 |= 28092 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 28093 break; 28094 default: 28095 // Use default resolved text alignment 28096 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28097 } 28098 break; 28099 case TEXT_ALIGNMENT_GRAVITY: 28100 case TEXT_ALIGNMENT_TEXT_START: 28101 case TEXT_ALIGNMENT_TEXT_END: 28102 case TEXT_ALIGNMENT_CENTER: 28103 case TEXT_ALIGNMENT_VIEW_START: 28104 case TEXT_ALIGNMENT_VIEW_END: 28105 // Resolved text alignment is the same as text alignment 28106 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 28107 break; 28108 default: 28109 // Use default resolved text alignment 28110 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28111 } 28112 } else { 28113 // Use default resolved text alignment 28114 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28115 } 28116 28117 // Set the resolved 28118 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 28119 return true; 28120 } 28121 28122 /** 28123 * Check if text alignment resolution can be done. 28124 * 28125 * @return true if text alignment resolution can be done otherwise return false. 28126 */ canResolveTextAlignment()28127 public boolean canResolveTextAlignment() { 28128 switch (getRawTextAlignment()) { 28129 case TEXT_DIRECTION_INHERIT: 28130 if (mParent != null) { 28131 try { 28132 return mParent.canResolveTextAlignment(); 28133 } catch (AbstractMethodError e) { 28134 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28135 " does not fully implement ViewParent", e); 28136 } 28137 } 28138 return false; 28139 28140 default: 28141 return true; 28142 } 28143 } 28144 28145 /** 28146 * Reset resolved text alignment. Text alignment will be resolved during a call to 28147 * {@link #onMeasure(int, int)}. 28148 * 28149 * @hide 28150 */ 28151 @TestApi resetResolvedTextAlignment()28152 public void resetResolvedTextAlignment() { 28153 // Reset any previous text alignment resolution 28154 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 28155 // Set to default 28156 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28157 } 28158 28159 /** 28160 * @return true if text alignment is inherited. 28161 * 28162 * @hide 28163 */ isTextAlignmentInherited()28164 public boolean isTextAlignmentInherited() { 28165 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 28166 } 28167 28168 /** 28169 * @return true if text alignment is resolved. 28170 */ isTextAlignmentResolved()28171 public boolean isTextAlignmentResolved() { 28172 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 28173 } 28174 28175 /** 28176 * Generate a value suitable for use in {@link #setId(int)}. 28177 * This value will not collide with ID values generated at build time by aapt for R.id. 28178 * 28179 * @return a generated ID value 28180 */ generateViewId()28181 public static int generateViewId() { 28182 for (;;) { 28183 final int result = sNextGeneratedId.get(); 28184 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 28185 int newValue = result + 1; 28186 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 28187 if (sNextGeneratedId.compareAndSet(result, newValue)) { 28188 return result; 28189 } 28190 } 28191 } 28192 isViewIdGenerated(int id)28193 private static boolean isViewIdGenerated(int id) { 28194 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 28195 } 28196 28197 /** 28198 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 28199 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 28200 * a normal View or a ViewGroup with 28201 * {@link android.view.ViewGroup#isTransitionGroup()} true. 28202 * @hide 28203 */ captureTransitioningViews(List<View> transitioningViews)28204 public void captureTransitioningViews(List<View> transitioningViews) { 28205 if (getVisibility() == View.VISIBLE) { 28206 transitioningViews.add(this); 28207 } 28208 } 28209 28210 /** 28211 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 28212 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 28213 * @hide 28214 */ findNamedViews(Map<String, View> namedElements)28215 public void findNamedViews(Map<String, View> namedElements) { 28216 if (getVisibility() == VISIBLE || mGhostView != null) { 28217 String transitionName = getTransitionName(); 28218 if (transitionName != null) { 28219 namedElements.put(transitionName, this); 28220 } 28221 } 28222 } 28223 28224 /** 28225 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 28226 * The default implementation does not care the location or event types, but some subclasses 28227 * may use it (such as WebViews). 28228 * @param event The MotionEvent from a mouse 28229 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 28230 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 28231 * @see PointerIcon 28232 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)28233 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 28234 final float x = event.getX(pointerIndex); 28235 final float y = event.getY(pointerIndex); 28236 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 28237 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 28238 } 28239 return mPointerIcon; 28240 } 28241 28242 /** 28243 * Set the pointer icon for the current view. 28244 * Passing {@code null} will restore the pointer icon to its default value. 28245 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 28246 */ setPointerIcon(PointerIcon pointerIcon)28247 public void setPointerIcon(PointerIcon pointerIcon) { 28248 mPointerIcon = pointerIcon; 28249 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 28250 return; 28251 } 28252 try { 28253 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 28254 } catch (RemoteException e) { 28255 } 28256 } 28257 28258 /** 28259 * Gets the pointer icon for the current view. 28260 */ 28261 @InspectableProperty getPointerIcon()28262 public PointerIcon getPointerIcon() { 28263 return mPointerIcon; 28264 } 28265 28266 /** 28267 * Checks pointer capture status. 28268 * 28269 * @return true if the view has pointer capture. 28270 * @see #requestPointerCapture() 28271 * @see #hasPointerCapture() 28272 */ hasPointerCapture()28273 public boolean hasPointerCapture() { 28274 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28275 if (viewRootImpl == null) { 28276 return false; 28277 } 28278 return viewRootImpl.hasPointerCapture(); 28279 } 28280 28281 /** 28282 * Requests pointer capture mode. 28283 * <p> 28284 * When the window has pointer capture, the mouse pointer icon will disappear and will not 28285 * change its position. Enabling pointer capture will change the behavior of input devices in 28286 * the following ways: 28287 * <ul> 28288 * <li>Events from a mouse will be delivered with the source 28289 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be 28290 * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li> 28291 * 28292 * <li>Events from a touchpad will be delivered with the source 28293 * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers 28294 * on the touchpad will be available through {@link MotionEvent#getX(int)} and 28295 * {@link MotionEvent#getY(int)}, and their relative movements are stored in 28296 * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li> 28297 * 28298 * <li>Events from other types of devices, such as touchscreens, will not be affected.</li> 28299 * </ul> 28300 * <p> 28301 * Events captured through pointer capture will be dispatched to 28302 * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an 28303 * {@link OnCapturedPointerListener} is set, and otherwise to 28304 * {@link #onCapturedPointerEvent(MotionEvent)}. 28305 * <p> 28306 * If the window already has pointer capture, this call does nothing. 28307 * <p> 28308 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 28309 * automatically when the window loses focus. 28310 * 28311 * @see #releasePointerCapture() 28312 * @see #hasPointerCapture() 28313 * @see #onPointerCaptureChange(boolean) 28314 */ requestPointerCapture()28315 public void requestPointerCapture() { 28316 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28317 if (viewRootImpl != null) { 28318 viewRootImpl.requestPointerCapture(true); 28319 } 28320 } 28321 28322 28323 /** 28324 * Releases the pointer capture. 28325 * <p> 28326 * If the window does not have pointer capture, this call will do nothing. 28327 * @see #requestPointerCapture() 28328 * @see #hasPointerCapture() 28329 * @see #onPointerCaptureChange(boolean) 28330 */ releasePointerCapture()28331 public void releasePointerCapture() { 28332 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28333 if (viewRootImpl != null) { 28334 viewRootImpl.requestPointerCapture(false); 28335 } 28336 } 28337 28338 /** 28339 * Called when the window has just acquired or lost pointer capture. 28340 * 28341 * @param hasCapture True if the view now has pointerCapture, false otherwise. 28342 */ 28343 @CallSuper onPointerCaptureChange(boolean hasCapture)28344 public void onPointerCaptureChange(boolean hasCapture) { 28345 } 28346 28347 /** 28348 * @see #onPointerCaptureChange 28349 */ dispatchPointerCaptureChanged(boolean hasCapture)28350 public void dispatchPointerCaptureChanged(boolean hasCapture) { 28351 onPointerCaptureChange(hasCapture); 28352 } 28353 28354 /** 28355 * Implement this method to handle captured pointer events 28356 * 28357 * @param event The captured pointer event. 28358 * @return True if the event was handled, false otherwise. 28359 * @see #requestPointerCapture() 28360 */ onCapturedPointerEvent(MotionEvent event)28361 public boolean onCapturedPointerEvent(MotionEvent event) { 28362 return false; 28363 } 28364 28365 /** 28366 * Interface definition for a callback to be invoked when a captured pointer event 28367 * is being dispatched this view. The callback will be invoked before the event is 28368 * given to the view. 28369 */ 28370 public interface OnCapturedPointerListener { 28371 /** 28372 * Called when a captured pointer event is dispatched to a view. 28373 * @param view The view this event has been dispatched to. 28374 * @param event The captured event. 28375 * @return True if the listener has consumed the event, false otherwise. 28376 */ onCapturedPointer(View view, MotionEvent event)28377 boolean onCapturedPointer(View view, MotionEvent event); 28378 } 28379 28380 /** 28381 * Set a listener to receive callbacks when the pointer capture state of a view changes. 28382 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 28383 */ setOnCapturedPointerListener(OnCapturedPointerListener l)28384 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 28385 getListenerInfo().mOnCapturedPointerListener = l; 28386 } 28387 28388 // Properties 28389 // 28390 /** 28391 * A Property wrapper around the <code>alpha</code> functionality handled by the 28392 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 28393 */ 28394 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 28395 @Override 28396 public void setValue(View object, float value) { 28397 object.setAlpha(value); 28398 } 28399 28400 @Override 28401 public Float get(View object) { 28402 return object.getAlpha(); 28403 } 28404 }; 28405 28406 /** 28407 * A Property wrapper around the <code>translationX</code> functionality handled by the 28408 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 28409 */ 28410 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 28411 @Override 28412 public void setValue(View object, float value) { 28413 object.setTranslationX(value); 28414 } 28415 28416 @Override 28417 public Float get(View object) { 28418 return object.getTranslationX(); 28419 } 28420 }; 28421 28422 /** 28423 * A Property wrapper around the <code>translationY</code> functionality handled by the 28424 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 28425 */ 28426 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 28427 @Override 28428 public void setValue(View object, float value) { 28429 object.setTranslationY(value); 28430 } 28431 28432 @Override 28433 public Float get(View object) { 28434 return object.getTranslationY(); 28435 } 28436 }; 28437 28438 /** 28439 * A Property wrapper around the <code>translationZ</code> functionality handled by the 28440 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 28441 */ 28442 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 28443 @Override 28444 public void setValue(View object, float value) { 28445 object.setTranslationZ(value); 28446 } 28447 28448 @Override 28449 public Float get(View object) { 28450 return object.getTranslationZ(); 28451 } 28452 }; 28453 28454 /** 28455 * A Property wrapper around the <code>x</code> functionality handled by the 28456 * {@link View#setX(float)} and {@link View#getX()} methods. 28457 */ 28458 public static final Property<View, Float> X = new FloatProperty<View>("x") { 28459 @Override 28460 public void setValue(View object, float value) { 28461 object.setX(value); 28462 } 28463 28464 @Override 28465 public Float get(View object) { 28466 return object.getX(); 28467 } 28468 }; 28469 28470 /** 28471 * A Property wrapper around the <code>y</code> functionality handled by the 28472 * {@link View#setY(float)} and {@link View#getY()} methods. 28473 */ 28474 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 28475 @Override 28476 public void setValue(View object, float value) { 28477 object.setY(value); 28478 } 28479 28480 @Override 28481 public Float get(View object) { 28482 return object.getY(); 28483 } 28484 }; 28485 28486 /** 28487 * A Property wrapper around the <code>z</code> functionality handled by the 28488 * {@link View#setZ(float)} and {@link View#getZ()} methods. 28489 */ 28490 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 28491 @Override 28492 public void setValue(View object, float value) { 28493 object.setZ(value); 28494 } 28495 28496 @Override 28497 public Float get(View object) { 28498 return object.getZ(); 28499 } 28500 }; 28501 28502 /** 28503 * A Property wrapper around the <code>rotation</code> functionality handled by the 28504 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 28505 */ 28506 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 28507 @Override 28508 public void setValue(View object, float value) { 28509 object.setRotation(value); 28510 } 28511 28512 @Override 28513 public Float get(View object) { 28514 return object.getRotation(); 28515 } 28516 }; 28517 28518 /** 28519 * A Property wrapper around the <code>rotationX</code> functionality handled by the 28520 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 28521 */ 28522 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 28523 @Override 28524 public void setValue(View object, float value) { 28525 object.setRotationX(value); 28526 } 28527 28528 @Override 28529 public Float get(View object) { 28530 return object.getRotationX(); 28531 } 28532 }; 28533 28534 /** 28535 * A Property wrapper around the <code>rotationY</code> functionality handled by the 28536 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 28537 */ 28538 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 28539 @Override 28540 public void setValue(View object, float value) { 28541 object.setRotationY(value); 28542 } 28543 28544 @Override 28545 public Float get(View object) { 28546 return object.getRotationY(); 28547 } 28548 }; 28549 28550 /** 28551 * A Property wrapper around the <code>scaleX</code> functionality handled by the 28552 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 28553 */ 28554 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 28555 @Override 28556 public void setValue(View object, float value) { 28557 object.setScaleX(value); 28558 } 28559 28560 @Override 28561 public Float get(View object) { 28562 return object.getScaleX(); 28563 } 28564 }; 28565 28566 /** 28567 * A Property wrapper around the <code>scaleY</code> functionality handled by the 28568 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 28569 */ 28570 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 28571 @Override 28572 public void setValue(View object, float value) { 28573 object.setScaleY(value); 28574 } 28575 28576 @Override 28577 public Float get(View object) { 28578 return object.getScaleY(); 28579 } 28580 }; 28581 28582 /** 28583 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 28584 * Each MeasureSpec represents a requirement for either the width or the height. 28585 * A MeasureSpec is comprised of a size and a mode. There are three possible 28586 * modes: 28587 * <dl> 28588 * <dt>UNSPECIFIED</dt> 28589 * <dd> 28590 * The parent has not imposed any constraint on the child. It can be whatever size 28591 * it wants. 28592 * </dd> 28593 * 28594 * <dt>EXACTLY</dt> 28595 * <dd> 28596 * The parent has determined an exact size for the child. The child is going to be 28597 * given those bounds regardless of how big it wants to be. 28598 * </dd> 28599 * 28600 * <dt>AT_MOST</dt> 28601 * <dd> 28602 * The child can be as large as it wants up to the specified size. 28603 * </dd> 28604 * </dl> 28605 * 28606 * MeasureSpecs are implemented as ints to reduce object allocation. This class 28607 * is provided to pack and unpack the <size, mode> tuple into the int. 28608 */ 28609 public static class MeasureSpec { 28610 private static final int MODE_SHIFT = 30; 28611 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 28612 28613 /** @hide */ 28614 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 28615 @Retention(RetentionPolicy.SOURCE) 28616 public @interface MeasureSpecMode {} 28617 28618 /** 28619 * Measure specification mode: The parent has not imposed any constraint 28620 * on the child. It can be whatever size it wants. 28621 */ 28622 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 28623 28624 /** 28625 * Measure specification mode: The parent has determined an exact size 28626 * for the child. The child is going to be given those bounds regardless 28627 * of how big it wants to be. 28628 */ 28629 public static final int EXACTLY = 1 << MODE_SHIFT; 28630 28631 /** 28632 * Measure specification mode: The child can be as large as it wants up 28633 * to the specified size. 28634 */ 28635 public static final int AT_MOST = 2 << MODE_SHIFT; 28636 28637 /** 28638 * Creates a measure specification based on the supplied size and mode. 28639 * 28640 * The mode must always be one of the following: 28641 * <ul> 28642 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 28643 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 28644 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 28645 * </ul> 28646 * 28647 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 28648 * implementation was such that the order of arguments did not matter 28649 * and overflow in either value could impact the resulting MeasureSpec. 28650 * {@link android.widget.RelativeLayout} was affected by this bug. 28651 * Apps targeting API levels greater than 17 will get the fixed, more strict 28652 * behavior.</p> 28653 * 28654 * @param size the size of the measure specification 28655 * @param mode the mode of the measure specification 28656 * @return the measure specification based on size and mode 28657 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)28658 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 28659 @MeasureSpecMode int mode) { 28660 if (sUseBrokenMakeMeasureSpec) { 28661 return size + mode; 28662 } else { 28663 return (size & ~MODE_MASK) | (mode & MODE_MASK); 28664 } 28665 } 28666 28667 /** 28668 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 28669 * will automatically get a size of 0. Older apps expect this. 28670 * 28671 * @hide internal use only for compatibility with system widgets and older apps 28672 */ 28673 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)28674 public static int makeSafeMeasureSpec(int size, int mode) { 28675 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 28676 return 0; 28677 } 28678 return makeMeasureSpec(size, mode); 28679 } 28680 28681 /** 28682 * Extracts the mode from the supplied measure specification. 28683 * 28684 * @param measureSpec the measure specification to extract the mode from 28685 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 28686 * {@link android.view.View.MeasureSpec#AT_MOST} or 28687 * {@link android.view.View.MeasureSpec#EXACTLY} 28688 */ 28689 @MeasureSpecMode getMode(int measureSpec)28690 public static int getMode(int measureSpec) { 28691 //noinspection ResourceType 28692 return (measureSpec & MODE_MASK); 28693 } 28694 28695 /** 28696 * Extracts the size from the supplied measure specification. 28697 * 28698 * @param measureSpec the measure specification to extract the size from 28699 * @return the size in pixels defined in the supplied measure specification 28700 */ getSize(int measureSpec)28701 public static int getSize(int measureSpec) { 28702 return (measureSpec & ~MODE_MASK); 28703 } 28704 adjust(int measureSpec, int delta)28705 static int adjust(int measureSpec, int delta) { 28706 final int mode = getMode(measureSpec); 28707 int size = getSize(measureSpec); 28708 if (mode == UNSPECIFIED) { 28709 // No need to adjust size for UNSPECIFIED mode. 28710 return makeMeasureSpec(size, UNSPECIFIED); 28711 } 28712 size += delta; 28713 if (size < 0) { 28714 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 28715 ") spec: " + toString(measureSpec) + " delta: " + delta); 28716 size = 0; 28717 } 28718 return makeMeasureSpec(size, mode); 28719 } 28720 28721 /** 28722 * Returns a String representation of the specified measure 28723 * specification. 28724 * 28725 * @param measureSpec the measure specification to convert to a String 28726 * @return a String with the following format: "MeasureSpec: MODE SIZE" 28727 */ toString(int measureSpec)28728 public static String toString(int measureSpec) { 28729 int mode = getMode(measureSpec); 28730 int size = getSize(measureSpec); 28731 28732 StringBuilder sb = new StringBuilder("MeasureSpec: "); 28733 28734 if (mode == UNSPECIFIED) 28735 sb.append("UNSPECIFIED "); 28736 else if (mode == EXACTLY) 28737 sb.append("EXACTLY "); 28738 else if (mode == AT_MOST) 28739 sb.append("AT_MOST "); 28740 else 28741 sb.append(mode).append(" "); 28742 28743 sb.append(size); 28744 return sb.toString(); 28745 } 28746 } 28747 28748 private final class CheckForLongPress implements Runnable { 28749 private int mOriginalWindowAttachCount; 28750 private float mX; 28751 private float mY; 28752 private boolean mOriginalPressedState; 28753 /** 28754 * The classification of the long click being checked: one of the 28755 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 28756 */ 28757 private int mClassification; 28758 28759 @UnsupportedAppUsage CheckForLongPress()28760 private CheckForLongPress() { 28761 } 28762 28763 @Override run()28764 public void run() { 28765 if ((mOriginalPressedState == isPressed()) && (mParent != null) 28766 && mOriginalWindowAttachCount == mWindowAttachCount) { 28767 recordGestureClassification(mClassification); 28768 if (performLongClick(mX, mY)) { 28769 mHasPerformedLongPress = true; 28770 } 28771 } 28772 } 28773 setAnchor(float x, float y)28774 public void setAnchor(float x, float y) { 28775 mX = x; 28776 mY = y; 28777 } 28778 rememberWindowAttachCount()28779 public void rememberWindowAttachCount() { 28780 mOriginalWindowAttachCount = mWindowAttachCount; 28781 } 28782 rememberPressedState()28783 public void rememberPressedState() { 28784 mOriginalPressedState = isPressed(); 28785 } 28786 setClassification(int classification)28787 public void setClassification(int classification) { 28788 mClassification = classification; 28789 } 28790 } 28791 28792 private final class CheckForTap implements Runnable { 28793 public float x; 28794 public float y; 28795 28796 @Override run()28797 public void run() { 28798 mPrivateFlags &= ~PFLAG_PREPRESSED; 28799 setPressed(true, x, y); 28800 final long delay = 28801 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 28802 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 28803 } 28804 } 28805 28806 private final class PerformClick implements Runnable { 28807 @Override run()28808 public void run() { 28809 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 28810 performClickInternal(); 28811 } 28812 } 28813 28814 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)28815 private void recordGestureClassification(int classification) { 28816 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 28817 return; 28818 } 28819 // To avoid negatively impacting View performance, the latency and displacement metrics 28820 // are omitted. 28821 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 28822 classification); 28823 } 28824 28825 /** 28826 * This method returns a ViewPropertyAnimator object, which can be used to animate 28827 * specific properties on this View. 28828 * 28829 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 28830 */ animate()28831 public ViewPropertyAnimator animate() { 28832 if (mAnimator == null) { 28833 mAnimator = new ViewPropertyAnimator(this); 28834 } 28835 return mAnimator; 28836 } 28837 28838 /** 28839 * Sets the name of the View to be used to identify Views in Transitions. 28840 * Names should be unique in the View hierarchy. 28841 * 28842 * @param transitionName The name of the View to uniquely identify it for Transitions. 28843 */ setTransitionName(String transitionName)28844 public final void setTransitionName(String transitionName) { 28845 mTransitionName = transitionName; 28846 } 28847 28848 /** 28849 * Returns the name of the View to be used to identify Views in Transitions. 28850 * Names should be unique in the View hierarchy. 28851 * 28852 * <p>This returns null if the View has not been given a name.</p> 28853 * 28854 * @return The name used of the View to be used to identify Views in Transitions or null 28855 * if no name has been given. 28856 */ 28857 @ViewDebug.ExportedProperty 28858 @InspectableProperty getTransitionName()28859 public String getTransitionName() { 28860 return mTransitionName; 28861 } 28862 28863 /** 28864 * @hide 28865 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)28866 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 28867 // Do nothing. 28868 } 28869 28870 /** 28871 * Interface definition for a callback to be invoked when a hardware key event is 28872 * dispatched to this view. The callback will be invoked before the key event is 28873 * given to the view. This is only useful for hardware keyboards; a software input 28874 * method has no obligation to trigger this listener. 28875 */ 28876 public interface OnKeyListener { 28877 /** 28878 * Called when a hardware key is dispatched to a view. This allows listeners to 28879 * get a chance to respond before the target view. 28880 * <p>Key presses in software keyboards will generally NOT trigger this method, 28881 * although some may elect to do so in some situations. Do not assume a 28882 * software input method has to be key-based; even if it is, it may use key presses 28883 * in a different way than you expect, so there is no way to reliably catch soft 28884 * input key presses. 28885 * 28886 * @param v The view the key has been dispatched to. 28887 * @param keyCode The code for the physical key that was pressed 28888 * @param event The KeyEvent object containing full information about 28889 * the event. 28890 * @return True if the listener has consumed the event, false otherwise. 28891 */ onKey(View v, int keyCode, KeyEvent event)28892 boolean onKey(View v, int keyCode, KeyEvent event); 28893 } 28894 28895 /** 28896 * Interface definition for a callback to be invoked when a hardware key event hasn't 28897 * been handled by the view hierarchy. 28898 */ 28899 public interface OnUnhandledKeyEventListener { 28900 /** 28901 * Called when a hardware key is dispatched to a view after being unhandled during normal 28902 * {@link KeyEvent} dispatch. 28903 * 28904 * @param v The view the key has been dispatched to. 28905 * @param event The KeyEvent object containing information about the event. 28906 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 28907 */ onUnhandledKeyEvent(View v, KeyEvent event)28908 boolean onUnhandledKeyEvent(View v, KeyEvent event); 28909 } 28910 28911 /** 28912 * Interface definition for a callback to be invoked when a touch event is 28913 * dispatched to this view. The callback will be invoked before the touch 28914 * event is given to the view. 28915 */ 28916 public interface OnTouchListener { 28917 /** 28918 * Called when a touch event is dispatched to a view. This allows listeners to 28919 * get a chance to respond before the target view. 28920 * 28921 * @param v The view the touch event has been dispatched to. 28922 * @param event The MotionEvent object containing full information about 28923 * the event. 28924 * @return True if the listener has consumed the event, false otherwise. 28925 */ onTouch(View v, MotionEvent event)28926 boolean onTouch(View v, MotionEvent event); 28927 } 28928 28929 /** 28930 * Interface definition for a callback to be invoked when a hover event is 28931 * dispatched to this view. The callback will be invoked before the hover 28932 * event is given to the view. 28933 */ 28934 public interface OnHoverListener { 28935 /** 28936 * Called when a hover event is dispatched to a view. This allows listeners to 28937 * get a chance to respond before the target view. 28938 * 28939 * @param v The view the hover event has been dispatched to. 28940 * @param event The MotionEvent object containing full information about 28941 * the event. 28942 * @return True if the listener has consumed the event, false otherwise. 28943 */ onHover(View v, MotionEvent event)28944 boolean onHover(View v, MotionEvent event); 28945 } 28946 28947 /** 28948 * Interface definition for a callback to be invoked when a generic motion event is 28949 * dispatched to this view. The callback will be invoked before the generic motion 28950 * event is given to the view. 28951 */ 28952 public interface OnGenericMotionListener { 28953 /** 28954 * Called when a generic motion event is dispatched to a view. This allows listeners to 28955 * get a chance to respond before the target view. 28956 * 28957 * @param v The view the generic motion event has been dispatched to. 28958 * @param event The MotionEvent object containing full information about 28959 * the event. 28960 * @return True if the listener has consumed the event, false otherwise. 28961 */ onGenericMotion(View v, MotionEvent event)28962 boolean onGenericMotion(View v, MotionEvent event); 28963 } 28964 28965 /** 28966 * Interface definition for a callback to be invoked when a view has been clicked and held. 28967 */ 28968 public interface OnLongClickListener { 28969 /** 28970 * Called when a view has been clicked and held. 28971 * 28972 * @param v The view that was clicked and held. 28973 * 28974 * @return true if the callback consumed the long click, false otherwise. 28975 */ onLongClick(View v)28976 boolean onLongClick(View v); 28977 } 28978 28979 /** 28980 * Interface definition for a callback to be invoked when a drag is being dispatched 28981 * to this view. The callback will be invoked before the hosting view's own 28982 * onDrag(event) method. If the listener wants to fall back to the hosting view's 28983 * onDrag(event) behavior, it should return 'false' from this callback. 28984 * 28985 * <div class="special reference"> 28986 * <h3>Developer Guides</h3> 28987 * <p>For a guide to implementing drag and drop features, read the 28988 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 28989 * </div> 28990 */ 28991 public interface OnDragListener { 28992 /** 28993 * Called when a drag event is dispatched to a view. This allows listeners 28994 * to get a chance to override base View behavior. 28995 * 28996 * @param v The View that received the drag event. 28997 * @param event The {@link android.view.DragEvent} object for the drag event. 28998 * @return {@code true} if the drag event was handled successfully, or {@code false} 28999 * if the drag event was not handled. Note that {@code false} will trigger the View 29000 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 29001 */ onDrag(View v, DragEvent event)29002 boolean onDrag(View v, DragEvent event); 29003 } 29004 29005 /** 29006 * Interface definition for a callback to be invoked when the focus state of 29007 * a view changed. 29008 */ 29009 public interface OnFocusChangeListener { 29010 /** 29011 * Called when the focus state of a view has changed. 29012 * 29013 * @param v The view whose state has changed. 29014 * @param hasFocus The new focus state of v. 29015 */ onFocusChange(View v, boolean hasFocus)29016 void onFocusChange(View v, boolean hasFocus); 29017 } 29018 29019 /** 29020 * Interface definition for a callback to be invoked when a view is clicked. 29021 */ 29022 public interface OnClickListener { 29023 /** 29024 * Called when a view has been clicked. 29025 * 29026 * @param v The view that was clicked. 29027 */ onClick(View v)29028 void onClick(View v); 29029 } 29030 29031 /** 29032 * Interface definition for a callback to be invoked when a view is context clicked. 29033 */ 29034 public interface OnContextClickListener { 29035 /** 29036 * Called when a view is context clicked. 29037 * 29038 * @param v The view that has been context clicked. 29039 * @return true if the callback consumed the context click, false otherwise. 29040 */ onContextClick(View v)29041 boolean onContextClick(View v); 29042 } 29043 29044 /** 29045 * Interface definition for a callback to be invoked when the context menu 29046 * for this view is being built. 29047 */ 29048 public interface OnCreateContextMenuListener { 29049 /** 29050 * Called when the context menu for this view is being built. It is not 29051 * safe to hold onto the menu after this method returns. 29052 * 29053 * @param menu The context menu that is being built 29054 * @param v The view for which the context menu is being built 29055 * @param menuInfo Extra information about the item for which the 29056 * context menu should be shown. This information will vary 29057 * depending on the class of v. 29058 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)29059 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 29060 } 29061 29062 /** 29063 * Interface definition for a callback to be invoked when the status bar changes 29064 * visibility. This reports <strong>global</strong> changes to the system UI 29065 * state, not what the application is requesting. 29066 * 29067 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 29068 * 29069 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 29070 * by setting a {@link OnApplyWindowInsetsListener} on this view. 29071 */ 29072 @Deprecated 29073 public interface OnSystemUiVisibilityChangeListener { 29074 /** 29075 * Called when the status bar changes visibility because of a call to 29076 * {@link View#setSystemUiVisibility(int)}. 29077 * 29078 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 29079 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 29080 * This tells you the <strong>global</strong> state of these UI visibility 29081 * flags, not what your app is currently applying. 29082 */ onSystemUiVisibilityChange(int visibility)29083 public void onSystemUiVisibilityChange(int visibility); 29084 } 29085 29086 /** 29087 * Interface definition for a callback to be invoked when this view is attached 29088 * or detached from its window. 29089 */ 29090 public interface OnAttachStateChangeListener { 29091 /** 29092 * Called when the view is attached to a window. 29093 * @param v The view that was attached 29094 */ onViewAttachedToWindow(View v)29095 public void onViewAttachedToWindow(View v); 29096 /** 29097 * Called when the view is detached from a window. 29098 * @param v The view that was detached 29099 */ onViewDetachedFromWindow(View v)29100 public void onViewDetachedFromWindow(View v); 29101 } 29102 29103 /** 29104 * Listener for applying window insets on a view in a custom way. 29105 * 29106 * <p>Apps may choose to implement this interface if they want to apply custom policy 29107 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 29108 * is set, its 29109 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 29110 * method will be called instead of the View's own 29111 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 29112 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 29113 * the View's normal behavior as part of its own.</p> 29114 */ 29115 public interface OnApplyWindowInsetsListener { 29116 /** 29117 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 29118 * on a View, this listener method will be called instead of the view's own 29119 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 29120 * 29121 * @param v The view applying window insets 29122 * @param insets The insets to apply 29123 * @return The insets supplied, minus any insets that were consumed 29124 */ onApplyWindowInsets(View v, WindowInsets insets)29125 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 29126 } 29127 29128 private final class UnsetPressedState implements Runnable { 29129 @Override run()29130 public void run() { 29131 setPressed(false); 29132 } 29133 } 29134 29135 /** 29136 * When a view becomes invisible checks if autofill considers the view invisible too. This 29137 * happens after the regular removal operation to make sure the operation is finished by the 29138 * time this is called. 29139 */ 29140 private static class VisibilityChangeForAutofillHandler extends Handler { 29141 private final AutofillManager mAfm; 29142 private final View mView; 29143 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)29144 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 29145 @NonNull View view) { 29146 mAfm = afm; 29147 mView = view; 29148 } 29149 29150 @Override handleMessage(Message msg)29151 public void handleMessage(Message msg) { 29152 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 29153 } 29154 } 29155 29156 /** 29157 * Base class for derived classes that want to save and restore their own 29158 * state in {@link android.view.View#onSaveInstanceState()}. 29159 */ 29160 public static class BaseSavedState extends AbsSavedState { 29161 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 29162 static final int IS_AUTOFILLED = 0b10; 29163 static final int AUTOFILL_ID = 0b100; 29164 29165 // Flags that describe what data in this state is valid 29166 int mSavedData; 29167 String mStartActivityRequestWhoSaved; 29168 boolean mIsAutofilled; 29169 boolean mHideHighlight; 29170 int mAutofillViewId; 29171 29172 /** 29173 * Constructor used when reading from a parcel. Reads the state of the superclass. 29174 * 29175 * @param source parcel to read from 29176 */ BaseSavedState(Parcel source)29177 public BaseSavedState(Parcel source) { 29178 this(source, null); 29179 } 29180 29181 /** 29182 * Constructor used when reading from a parcel using a given class loader. 29183 * Reads the state of the superclass. 29184 * 29185 * @param source parcel to read from 29186 * @param loader ClassLoader to use for reading 29187 */ BaseSavedState(Parcel source, ClassLoader loader)29188 public BaseSavedState(Parcel source, ClassLoader loader) { 29189 super(source, loader); 29190 mSavedData = source.readInt(); 29191 mStartActivityRequestWhoSaved = source.readString(); 29192 mIsAutofilled = source.readBoolean(); 29193 mHideHighlight = source.readBoolean(); 29194 mAutofillViewId = source.readInt(); 29195 } 29196 29197 /** 29198 * Constructor called by derived classes when creating their SavedState objects 29199 * 29200 * @param superState The state of the superclass of this view 29201 */ BaseSavedState(Parcelable superState)29202 public BaseSavedState(Parcelable superState) { 29203 super(superState); 29204 } 29205 29206 @Override writeToParcel(Parcel out, int flags)29207 public void writeToParcel(Parcel out, int flags) { 29208 super.writeToParcel(out, flags); 29209 29210 out.writeInt(mSavedData); 29211 out.writeString(mStartActivityRequestWhoSaved); 29212 out.writeBoolean(mIsAutofilled); 29213 out.writeBoolean(mHideHighlight); 29214 out.writeInt(mAutofillViewId); 29215 } 29216 29217 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 29218 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 29219 @Override 29220 public BaseSavedState createFromParcel(Parcel in) { 29221 return new BaseSavedState(in); 29222 } 29223 29224 @Override 29225 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 29226 return new BaseSavedState(in, loader); 29227 } 29228 29229 @Override 29230 public BaseSavedState[] newArray(int size) { 29231 return new BaseSavedState[size]; 29232 } 29233 }; 29234 } 29235 29236 /** 29237 * A set of information given to a view when it is attached to its parent 29238 * window. 29239 */ 29240 final static class AttachInfo { 29241 29242 interface Callbacks { playSoundEffect(int effectId)29243 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)29244 boolean performHapticFeedback(int effectId, boolean always); 29245 } 29246 29247 /** 29248 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 29249 * to a Handler. This class contains the target (View) to invalidate and 29250 * the coordinates of the dirty rectangle. 29251 * 29252 * For performance purposes, this class also implements a pool of up to 29253 * POOL_LIMIT objects that get reused. This reduces memory allocations 29254 * whenever possible. 29255 */ 29256 static class InvalidateInfo { 29257 29258 @UnsupportedAppUsage InvalidateInfo()29259 InvalidateInfo() { 29260 } 29261 29262 private static final int POOL_LIMIT = 10; 29263 29264 private static final SynchronizedPool<InvalidateInfo> sPool = 29265 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 29266 29267 @UnsupportedAppUsage 29268 View target; 29269 29270 @UnsupportedAppUsage 29271 int left; 29272 @UnsupportedAppUsage 29273 int top; 29274 @UnsupportedAppUsage 29275 int right; 29276 @UnsupportedAppUsage 29277 int bottom; 29278 obtain()29279 public static InvalidateInfo obtain() { 29280 InvalidateInfo instance = sPool.acquire(); 29281 return (instance != null) ? instance : new InvalidateInfo(); 29282 } 29283 recycle()29284 public void recycle() { 29285 target = null; 29286 sPool.release(this); 29287 } 29288 } 29289 29290 @UnsupportedAppUsage 29291 final IWindowSession mSession; 29292 29293 @UnsupportedAppUsage 29294 final IWindow mWindow; 29295 29296 final IBinder mWindowToken; 29297 29298 Display mDisplay; 29299 29300 final Callbacks mRootCallbacks; 29301 29302 IWindowId mIWindowId; 29303 WindowId mWindowId; 29304 29305 /** 29306 * The top view of the hierarchy. 29307 */ 29308 View mRootView; 29309 29310 IBinder mPanelParentWindowToken; 29311 29312 boolean mHardwareAccelerated; 29313 boolean mHardwareAccelerationRequested; 29314 ThreadedRenderer mThreadedRenderer; 29315 List<RenderNode> mPendingAnimatingRenderNodes; 29316 29317 /** 29318 * The state of the display to which the window is attached, as reported 29319 * by {@link Display#getState()}. Note that the display state constants 29320 * declared by {@link Display} do not exactly line up with the screen state 29321 * constants declared by {@link View} (there are more display states than 29322 * screen states). 29323 */ 29324 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29325 int mDisplayState = Display.STATE_UNKNOWN; 29326 29327 /** 29328 * Scale factor used by the compatibility mode 29329 */ 29330 @UnsupportedAppUsage 29331 float mApplicationScale; 29332 29333 /** 29334 * Indicates whether the application is in compatibility mode 29335 */ 29336 @UnsupportedAppUsage 29337 boolean mScalingRequired; 29338 29339 /** 29340 * Left position of this view's window 29341 */ 29342 int mWindowLeft; 29343 29344 /** 29345 * Top position of this view's window 29346 */ 29347 int mWindowTop; 29348 29349 /** 29350 * Indicates whether views need to use 32-bit drawing caches 29351 */ 29352 boolean mUse32BitDrawingCache; 29353 29354 /** 29355 * For windows that are full-screen but using insets to layout inside 29356 * of the screen decorations, these are the current insets for the 29357 * content of the window. 29358 */ 29359 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 29360 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 29361 final Rect mContentInsets = new Rect(); 29362 29363 /** 29364 * For windows that are full-screen but using insets to layout inside 29365 * of the screen decorations, these are the current insets for the 29366 * actual visible parts of the window. 29367 */ 29368 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 29369 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 29370 final Rect mVisibleInsets = new Rect(); 29371 29372 /** 29373 * For windows that are full-screen but using insets to layout inside 29374 * of the screen decorations, these are the current insets for the 29375 * stable system windows. 29376 */ 29377 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 29378 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 29379 final Rect mStableInsets = new Rect(); 29380 29381 /** 29382 * Current caption insets to the display coordinate. 29383 */ 29384 final Rect mCaptionInsets = new Rect(); 29385 29386 /** 29387 * In multi-window we force show the system bars. Because we don't want that the surface 29388 * size changes in this mode, we instead have a flag whether the system bars sizes should 29389 * always be consumed, so the app is treated like there are no virtual system bars at all. 29390 */ 29391 boolean mAlwaysConsumeSystemBars; 29392 29393 /** 29394 * The internal insets given by this window. This value is 29395 * supplied by the client (through 29396 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 29397 * be given to the window manager when changed to be used in laying 29398 * out windows behind it. 29399 */ 29400 @UnsupportedAppUsage 29401 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 29402 = new ViewTreeObserver.InternalInsetsInfo(); 29403 29404 /** 29405 * Set to true when mGivenInternalInsets is non-empty. 29406 */ 29407 boolean mHasNonEmptyGivenInternalInsets; 29408 29409 /** 29410 * All views in the window's hierarchy that serve as scroll containers, 29411 * used to determine if the window can be resized or must be panned 29412 * to adjust for a soft input area. 29413 */ 29414 @UnsupportedAppUsage 29415 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 29416 29417 @UnsupportedAppUsage 29418 final KeyEvent.DispatcherState mKeyDispatchState 29419 = new KeyEvent.DispatcherState(); 29420 29421 /** 29422 * Indicates whether the view's window currently has the focus. 29423 */ 29424 @UnsupportedAppUsage 29425 boolean mHasWindowFocus; 29426 29427 /** 29428 * The current visibility of the window. 29429 */ 29430 int mWindowVisibility; 29431 29432 /** 29433 * Indicates the time at which drawing started to occur. 29434 */ 29435 @UnsupportedAppUsage 29436 long mDrawingTime; 29437 29438 /** 29439 * Indicates whether the view's window is currently in touch mode. 29440 */ 29441 @UnsupportedAppUsage 29442 boolean mInTouchMode; 29443 29444 /** 29445 * Indicates whether the view has requested unbuffered input dispatching for the current 29446 * event stream. 29447 */ 29448 boolean mUnbufferedDispatchRequested; 29449 29450 /** 29451 * Indicates that ViewAncestor should trigger a global layout change 29452 * the next time it performs a traversal 29453 */ 29454 @UnsupportedAppUsage 29455 boolean mRecomputeGlobalAttributes; 29456 29457 /** 29458 * Always report new attributes at next traversal. 29459 */ 29460 boolean mForceReportNewAttributes; 29461 29462 /** 29463 * Set during a traveral if any views want to keep the screen on. 29464 */ 29465 @UnsupportedAppUsage 29466 boolean mKeepScreenOn; 29467 29468 /** 29469 * Set during a traveral if the light center needs to be updated. 29470 */ 29471 boolean mNeedsUpdateLightCenter; 29472 29473 /** 29474 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 29475 */ 29476 int mSystemUiVisibility; 29477 29478 /** 29479 * Hack to force certain system UI visibility flags to be cleared. 29480 */ 29481 int mDisabledSystemUiVisibility; 29482 29483 /** 29484 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 29485 * attached. 29486 */ 29487 boolean mHasSystemUiListeners; 29488 29489 /** 29490 * Set if the visibility of any views has changed. 29491 */ 29492 @UnsupportedAppUsage 29493 boolean mViewVisibilityChanged; 29494 29495 /** 29496 * Set to true if a view has been scrolled. 29497 */ 29498 @UnsupportedAppUsage 29499 boolean mViewScrollChanged; 29500 29501 /** 29502 * Set to true if a pointer event is currently being handled. 29503 */ 29504 boolean mHandlingPointerEvent; 29505 29506 /** 29507 * The offset of this view's window when it's on an embedded display that is re-parented 29508 * to another window. 29509 */ 29510 final Point mLocationInParentDisplay = new Point(); 29511 29512 /** 29513 * The screen matrix of this view when it's on a {@link SurfaceControlViewHost} that is 29514 * embedded within a SurfaceView. 29515 */ 29516 Matrix mScreenMatrixInEmbeddedHierarchy; 29517 29518 /** 29519 * Global to the view hierarchy used as a temporary for dealing with 29520 * x/y points in the transparent region computations. 29521 */ 29522 final int[] mTransparentLocation = new int[2]; 29523 29524 /** 29525 * Global to the view hierarchy used as a temporary for dealing with 29526 * x/y points in the ViewGroup.invalidateChild implementation. 29527 */ 29528 final int[] mInvalidateChildLocation = new int[2]; 29529 29530 /** 29531 * Global to the view hierarchy used as a temporary for dealing with 29532 * computing absolute on-screen location. 29533 */ 29534 final int[] mTmpLocation = new int[2]; 29535 29536 /** 29537 * Global to the view hierarchy used as a temporary for dealing with 29538 * x/y location when view is transformed. 29539 */ 29540 final float[] mTmpTransformLocation = new float[2]; 29541 29542 /** 29543 * The view tree observer used to dispatch global events like 29544 * layout, pre-draw, touch mode change, etc. 29545 */ 29546 @UnsupportedAppUsage 29547 final ViewTreeObserver mTreeObserver; 29548 29549 /** 29550 * A Canvas used by the view hierarchy to perform bitmap caching. 29551 */ 29552 Canvas mCanvas; 29553 29554 /** 29555 * The view root impl. 29556 */ 29557 final ViewRootImpl mViewRootImpl; 29558 29559 /** 29560 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 29561 * handler can be used to pump events in the UI events queue. 29562 */ 29563 @UnsupportedAppUsage 29564 final Handler mHandler; 29565 29566 /** 29567 * Temporary for use in computing invalidate rectangles while 29568 * calling up the hierarchy. 29569 */ 29570 final Rect mTmpInvalRect = new Rect(); 29571 29572 /** 29573 * Temporary for use in computing hit areas with transformed views 29574 */ 29575 final RectF mTmpTransformRect = new RectF(); 29576 29577 /** 29578 * Temporary for use in computing hit areas with transformed views 29579 */ 29580 final RectF mTmpTransformRect1 = new RectF(); 29581 29582 /** 29583 * Temporary list of rectanges. 29584 */ 29585 final List<RectF> mTmpRectList = new ArrayList<>(); 29586 29587 /** 29588 * Temporary for use in transforming invalidation rect 29589 */ 29590 final Matrix mTmpMatrix = new Matrix(); 29591 29592 /** 29593 * Temporary for use in transforming invalidation rect 29594 */ 29595 final Transformation mTmpTransformation = new Transformation(); 29596 29597 /** 29598 * Temporary for use in querying outlines from OutlineProviders 29599 */ 29600 final Outline mTmpOutline = new Outline(); 29601 29602 /** 29603 * Temporary list for use in collecting focusable descendents of a view. 29604 */ 29605 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 29606 29607 /** 29608 * The id of the window for accessibility purposes. 29609 */ 29610 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 29611 29612 /** 29613 * Flags related to accessibility processing. 29614 * 29615 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 29616 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 29617 */ 29618 int mAccessibilityFetchFlags; 29619 29620 /** 29621 * The drawable for highlighting accessibility focus. 29622 */ 29623 Drawable mAccessibilityFocusDrawable; 29624 29625 /** 29626 * The drawable for highlighting autofilled views. 29627 * 29628 * @see #isAutofilled() 29629 */ 29630 Drawable mAutofilledDrawable; 29631 29632 /** 29633 * Show where the margins, bounds and layout bounds are for each view. 29634 */ 29635 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 29636 29637 /** 29638 * Point used to compute visible regions. 29639 */ 29640 final Point mPoint = new Point(); 29641 29642 /** 29643 * Used to track which View originated a requestLayout() call, used when 29644 * requestLayout() is called during layout. 29645 */ 29646 View mViewRequestingLayout; 29647 29648 /** 29649 * Used to track the identity of the current drag operation. 29650 */ 29651 IBinder mDragToken; 29652 29653 /** 29654 * The drag shadow surface for the current drag operation. 29655 */ 29656 public Surface mDragSurface; 29657 29658 29659 /** 29660 * The view that currently has a tooltip displayed. 29661 */ 29662 View mTooltipHost; 29663 29664 /** 29665 * The initial structure has been reported so the view is ready to report updates. 29666 */ 29667 boolean mReadyForContentCaptureUpdates; 29668 29669 /** 29670 * Map(keyed by session) of content capture events that need to be notified after the view 29671 * hierarchy is traversed: value is either the view itself for appearead events, or its 29672 * autofill id for disappeared. 29673 */ 29674 SparseArray<ArrayList<Object>> mContentCaptureEvents; 29675 29676 /** 29677 * Cached reference to the {@link ContentCaptureManager}. 29678 */ 29679 ContentCaptureManager mContentCaptureManager; 29680 29681 /** 29682 * Listener used to fit content on window level. 29683 */ 29684 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 29685 29686 /** 29687 * The leash token of this view's parent when it's in an embedded hierarchy that is 29688 * re-parented to another window. 29689 */ 29690 IBinder mLeashedParentToken; 29691 29692 /** 29693 * The accessibility view id of this view's parent when it's in an embedded 29694 * hierarchy that is re-parented to another window. 29695 */ 29696 int mLeashedParentAccessibilityViewId; 29697 29698 /** 29699 * 29700 */ 29701 ScrollCaptureInternal mScrollCaptureInternal; 29702 29703 /** 29704 * Creates a new set of attachment information with the specified 29705 * events handler and thread. 29706 * 29707 * @param handler the events handler the view must use 29708 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)29709 AttachInfo(IWindowSession session, IWindow window, Display display, 29710 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 29711 Context context) { 29712 mSession = session; 29713 mWindow = window; 29714 mWindowToken = window.asBinder(); 29715 mDisplay = display; 29716 mViewRootImpl = viewRootImpl; 29717 mHandler = handler; 29718 mRootCallbacks = effectPlayer; 29719 mTreeObserver = new ViewTreeObserver(context); 29720 } 29721 29722 @Nullable getContentCaptureManager(@onNull Context context)29723 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 29724 if (mContentCaptureManager != null) { 29725 return mContentCaptureManager; 29726 } 29727 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 29728 return mContentCaptureManager; 29729 } 29730 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)29731 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 29732 if (mContentCaptureManager == null) { 29733 return; 29734 } 29735 29736 ArrayList<Object> events = ensureEvents( 29737 mContentCaptureManager.getMainContentCaptureSession()); 29738 events.add(insets); 29739 } 29740 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)29741 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 29742 @NonNull View view, boolean appeared) { 29743 ArrayList<Object> events = ensureEvents(session); 29744 events.add(appeared ? view : view.getAutofillId()); 29745 } 29746 29747 @NonNull ensureEvents(@onNull ContentCaptureSession session)29748 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 29749 if (mContentCaptureEvents == null) { 29750 // Most of the time there will be just one session, so intial capacity is 1 29751 mContentCaptureEvents = new SparseArray<>(1); 29752 } 29753 int sessionId = session.getId(); 29754 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 29755 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 29756 if (events == null) { 29757 events = new ArrayList<>(); 29758 mContentCaptureEvents.put(sessionId, events); 29759 } 29760 29761 return events; 29762 } 29763 29764 @Nullable getScrollCaptureInternal()29765 ScrollCaptureInternal getScrollCaptureInternal() { 29766 if (mScrollCaptureInternal != null) { 29767 mScrollCaptureInternal = new ScrollCaptureInternal(); 29768 } 29769 return mScrollCaptureInternal; 29770 } 29771 getRootSurfaceControl()29772 AttachedSurfaceControl getRootSurfaceControl() { 29773 return mViewRootImpl; 29774 } 29775 dump(String prefix, PrintWriter writer)29776 public void dump(String prefix, PrintWriter writer) { 29777 String innerPrefix = prefix + " "; 29778 writer.println(prefix + "AttachInfo:"); 29779 writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); 29780 writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); 29781 writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); 29782 writer.println(innerPrefix + "mUnbufferedDispatchRequested=" 29783 + mUnbufferedDispatchRequested); 29784 } 29785 } 29786 29787 /** 29788 * <p>ScrollabilityCache holds various fields used by a View when scrolling 29789 * is supported. This avoids keeping too many unused fields in most 29790 * instances of View.</p> 29791 */ 29792 private static class ScrollabilityCache implements Runnable { 29793 29794 /** 29795 * Scrollbars are not visible 29796 */ 29797 public static final int OFF = 0; 29798 29799 /** 29800 * Scrollbars are visible 29801 */ 29802 public static final int ON = 1; 29803 29804 /** 29805 * Scrollbars are fading away 29806 */ 29807 public static final int FADING = 2; 29808 29809 public boolean fadeScrollBars; 29810 29811 public int fadingEdgeLength; 29812 public int scrollBarDefaultDelayBeforeFade; 29813 public int scrollBarFadeDuration; 29814 29815 public int scrollBarSize; 29816 public int scrollBarMinTouchTarget; 29817 @UnsupportedAppUsage 29818 public ScrollBarDrawable scrollBar; 29819 public float[] interpolatorValues; 29820 @UnsupportedAppUsage 29821 public View host; 29822 29823 public final Paint paint; 29824 public final Matrix matrix; 29825 public Shader shader; 29826 29827 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 29828 29829 private static final float[] OPAQUE = { 255 }; 29830 private static final float[] TRANSPARENT = { 0.0f }; 29831 29832 /** 29833 * When fading should start. This time moves into the future every time 29834 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 29835 */ 29836 public long fadeStartTime; 29837 29838 29839 /** 29840 * The current state of the scrollbars: ON, OFF, or FADING 29841 */ 29842 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29843 public int state = OFF; 29844 29845 private int mLastColor; 29846 29847 public final Rect mScrollBarBounds = new Rect(); 29848 public final Rect mScrollBarTouchBounds = new Rect(); 29849 29850 public static final int NOT_DRAGGING = 0; 29851 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 29852 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 29853 public int mScrollBarDraggingState = NOT_DRAGGING; 29854 29855 public float mScrollBarDraggingPos = 0; 29856 ScrollabilityCache(ViewConfiguration configuration, View host)29857 public ScrollabilityCache(ViewConfiguration configuration, View host) { 29858 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 29859 scrollBarSize = configuration.getScaledScrollBarSize(); 29860 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 29861 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 29862 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 29863 29864 paint = new Paint(); 29865 matrix = new Matrix(); 29866 // use use a height of 1, and then wack the matrix each time we 29867 // actually use it. 29868 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 29869 paint.setShader(shader); 29870 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 29871 29872 this.host = host; 29873 } 29874 setFadeColor(int color)29875 public void setFadeColor(int color) { 29876 if (color != mLastColor) { 29877 mLastColor = color; 29878 29879 if (color != 0) { 29880 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 29881 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 29882 paint.setShader(shader); 29883 // Restore the default transfer mode (src_over) 29884 paint.setXfermode(null); 29885 } else { 29886 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 29887 paint.setShader(shader); 29888 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 29889 } 29890 } 29891 } 29892 run()29893 public void run() { 29894 long now = AnimationUtils.currentAnimationTimeMillis(); 29895 if (now >= fadeStartTime) { 29896 29897 // the animation fades the scrollbars out by changing 29898 // the opacity (alpha) from fully opaque to fully 29899 // transparent 29900 int nextFrame = (int) now; 29901 int framesCount = 0; 29902 29903 Interpolator interpolator = scrollBarInterpolator; 29904 29905 // Start opaque 29906 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 29907 29908 // End transparent 29909 nextFrame += scrollBarFadeDuration; 29910 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 29911 29912 state = FADING; 29913 29914 // Kick off the fade animation 29915 host.invalidate(true); 29916 } 29917 } 29918 } 29919 29920 private class SendAccessibilityEventThrottle implements Runnable { 29921 public volatile boolean mIsPending; 29922 private AccessibilityEvent mAccessibilityEvent; 29923 post(AccessibilityEvent accessibilityEvent)29924 public void post(AccessibilityEvent accessibilityEvent) { 29925 updateWithAccessibilityEvent(accessibilityEvent); 29926 if (!mIsPending) { 29927 mIsPending = true; 29928 postDelayed(this, 29929 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 29930 } 29931 } 29932 29933 @Override run()29934 public void run() { 29935 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 29936 requestParentSendAccessibilityEvent(mAccessibilityEvent); 29937 } 29938 reset(); 29939 } 29940 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)29941 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 29942 mAccessibilityEvent = accessibilityEvent; 29943 } 29944 reset()29945 public void reset() { 29946 mIsPending = false; 29947 mAccessibilityEvent = null; 29948 } 29949 29950 } 29951 29952 /** 29953 * Resuable callback for sending 29954 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 29955 */ 29956 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 29957 public int mDeltaX; 29958 public int mDeltaY; 29959 29960 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)29961 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 29962 super.updateWithAccessibilityEvent(accessibilityEvent); 29963 mDeltaX += accessibilityEvent.getScrollDeltaX(); 29964 mDeltaY += accessibilityEvent.getScrollDeltaY(); 29965 accessibilityEvent.setScrollDeltaX(mDeltaX); 29966 accessibilityEvent.setScrollDeltaY(mDeltaY); 29967 } 29968 29969 @Override reset()29970 public void reset() { 29971 super.reset(); 29972 mDeltaX = 0; 29973 mDeltaY = 0; 29974 } 29975 } 29976 /** 29977 * Remove the pending callback for sending a throttled accessibility event. 29978 */ 29979 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)29980 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 29981 if (callback == null || !callback.mIsPending) return; 29982 removeCallbacks(callback); 29983 callback.reset(); 29984 } 29985 29986 /** 29987 * <p> 29988 * This class represents a delegate that can be registered in a {@link View} 29989 * to enhance accessibility support via composition rather via inheritance. 29990 * It is specifically targeted to widget developers that extend basic View 29991 * classes i.e. classes in package android.view, that would like their 29992 * applications to be backwards compatible. 29993 * </p> 29994 * <div class="special reference"> 29995 * <h3>Developer Guides</h3> 29996 * <p>For more information about making applications accessible, read the 29997 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 29998 * developer guide.</p> 29999 * </div> 30000 * <p> 30001 * A scenario in which a developer would like to use an accessibility delegate 30002 * is overriding a method introduced in a later API version than the minimal API 30003 * version supported by the application. For example, the method 30004 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 30005 * in API version 4 when the accessibility APIs were first introduced. If a 30006 * developer would like their application to run on API version 4 devices (assuming 30007 * all other APIs used by the application are version 4 or lower) and take advantage 30008 * of this method, instead of overriding the method which would break the application's 30009 * backwards compatibility, they can override the corresponding method in this 30010 * delegate and register the delegate in the target View if the API version of 30011 * the system is high enough, i.e. the API version is the same as or higher than the API 30012 * version that introduced 30013 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 30014 * </p> 30015 * <p> 30016 * Here is an example implementation: 30017 * </p> 30018 * <code><pre><p> 30019 * if (Build.VERSION.SDK_INT >= 14) { 30020 * // If the API version is equal of higher than the version in 30021 * // which onInitializeAccessibilityNodeInfo was introduced we 30022 * // register a delegate with a customized implementation. 30023 * View view = findViewById(R.id.view_id); 30024 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 30025 * public void onInitializeAccessibilityNodeInfo(View host, 30026 * AccessibilityNodeInfo info) { 30027 * // Let the default implementation populate the info. 30028 * super.onInitializeAccessibilityNodeInfo(host, info); 30029 * // Set some other information. 30030 * info.setEnabled(host.isEnabled()); 30031 * } 30032 * }); 30033 * } 30034 * </code></pre></p> 30035 * <p> 30036 * This delegate contains methods that correspond to the accessibility methods 30037 * in View. If a delegate has been specified the implementation in View hands 30038 * off handling to the corresponding method in this delegate. The default 30039 * implementation the delegate methods behaves exactly as the corresponding 30040 * method in View for the case of no accessibility delegate been set. Hence, 30041 * to customize the behavior of a View method, clients can override only the 30042 * corresponding delegate method without altering the behavior of the rest 30043 * accessibility related methods of the host view. 30044 * </p> 30045 * <p> 30046 * <strong>Note:</strong> On platform versions prior to 30047 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 30048 * views in the {@code android.widget.*} package are called <i>before</i> 30049 * host methods. This prevents certain properties such as class name from 30050 * being modified by overriding 30051 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 30052 * as any changes will be overwritten by the host class. 30053 * <p> 30054 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 30055 * methods are called <i>after</i> host methods, which all properties to be 30056 * modified without being overwritten by the host class. 30057 */ 30058 public static class AccessibilityDelegate { 30059 30060 /** 30061 * Sends an accessibility event of the given type. If accessibility is not 30062 * enabled this method has no effect. 30063 * <p> 30064 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 30065 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 30066 * been set. 30067 * </p> 30068 * 30069 * @param host The View hosting the delegate. 30070 * @param eventType The type of the event to send. 30071 * 30072 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 30073 */ sendAccessibilityEvent(View host, int eventType)30074 public void sendAccessibilityEvent(View host, int eventType) { 30075 host.sendAccessibilityEventInternal(eventType); 30076 } 30077 30078 /** 30079 * Performs the specified accessibility action on the view. For 30080 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 30081 * <p> 30082 * The default implementation behaves as 30083 * {@link View#performAccessibilityAction(int, Bundle) 30084 * View#performAccessibilityAction(int, Bundle)} for the case of 30085 * no accessibility delegate been set. 30086 * </p> 30087 * 30088 * @param action The action to perform. 30089 * @return Whether the action was performed. 30090 * 30091 * @see View#performAccessibilityAction(int, Bundle) 30092 * View#performAccessibilityAction(int, Bundle) 30093 */ performAccessibilityAction(View host, int action, Bundle args)30094 public boolean performAccessibilityAction(View host, int action, Bundle args) { 30095 return host.performAccessibilityActionInternal(action, args); 30096 } 30097 30098 /** 30099 * Sends an accessibility event. This method behaves exactly as 30100 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 30101 * empty {@link AccessibilityEvent} and does not perform a check whether 30102 * accessibility is enabled. 30103 * <p> 30104 * The default implementation behaves as 30105 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 30106 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 30107 * the case of no accessibility delegate been set. 30108 * </p> 30109 * 30110 * @param host The View hosting the delegate. 30111 * @param event The event to send. 30112 * 30113 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 30114 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 30115 */ sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)30116 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 30117 host.sendAccessibilityEventUncheckedInternal(event); 30118 } 30119 30120 /** 30121 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 30122 * to its children for adding their text content to the event. 30123 * <p> 30124 * The default implementation behaves as 30125 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30126 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 30127 * the case of no accessibility delegate been set. 30128 * </p> 30129 * 30130 * @param host The View hosting the delegate. 30131 * @param event The event. 30132 * @return True if the event population was completed. 30133 * 30134 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30135 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30136 */ dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)30137 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 30138 return host.dispatchPopulateAccessibilityEventInternal(event); 30139 } 30140 30141 /** 30142 * Gives a chance to the host View to populate the accessibility event with its 30143 * text content. 30144 * <p> 30145 * The default implementation behaves as 30146 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 30147 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 30148 * the case of no accessibility delegate been set. 30149 * </p> 30150 * 30151 * @param host The View hosting the delegate. 30152 * @param event The accessibility event which to populate. 30153 * 30154 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 30155 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 30156 */ onPopulateAccessibilityEvent(View host, AccessibilityEvent event)30157 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 30158 host.onPopulateAccessibilityEventInternal(event); 30159 } 30160 30161 /** 30162 * Initializes an {@link AccessibilityEvent} with information about the 30163 * the host View which is the event source. 30164 * <p> 30165 * The default implementation behaves as 30166 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 30167 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 30168 * the case of no accessibility delegate been set. 30169 * </p> 30170 * 30171 * @param host The View hosting the delegate. 30172 * @param event The event to initialize. 30173 * 30174 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 30175 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 30176 */ onInitializeAccessibilityEvent(View host, AccessibilityEvent event)30177 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 30178 host.onInitializeAccessibilityEventInternal(event); 30179 } 30180 30181 /** 30182 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 30183 * <p> 30184 * The default implementation behaves as 30185 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30186 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 30187 * the case of no accessibility delegate been set. 30188 * </p> 30189 * 30190 * @param host The View hosting the delegate. 30191 * @param info The instance to initialize. 30192 * 30193 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30194 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30195 */ onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)30196 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 30197 host.onInitializeAccessibilityNodeInfoInternal(info); 30198 } 30199 30200 /** 30201 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 30202 * additional data. 30203 * <p> 30204 * This method only needs to be implemented if the View offers to provide additional data. 30205 * </p> 30206 * <p> 30207 * The default implementation behaves as 30208 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 30209 * for the case where no accessibility delegate is set. 30210 * </p> 30211 * 30212 * @param host The View hosting the delegate. Never {@code null}. 30213 * @param info The info to which to add the extra data. Never {@code null}. 30214 * @param extraDataKey A key specifying the type of extra data to add to the info. The 30215 * extra data should be added to the {@link Bundle} returned by 30216 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 30217 * {@code null}. 30218 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 30219 * May be {@code null} if the if the service provided no arguments. 30220 * 30221 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 30222 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)30223 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 30224 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 30225 @Nullable Bundle arguments) { 30226 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 30227 } 30228 30229 /** 30230 * Called when a child of the host View has requested sending an 30231 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 30232 * to augment the event. 30233 * <p> 30234 * The default implementation behaves as 30235 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30236 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 30237 * the case of no accessibility delegate been set. 30238 * </p> 30239 * 30240 * @param host The View hosting the delegate. 30241 * @param child The child which requests sending the event. 30242 * @param event The event to be sent. 30243 * @return True if the event should be sent 30244 * 30245 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30246 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30247 */ onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)30248 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 30249 AccessibilityEvent event) { 30250 return host.onRequestSendAccessibilityEventInternal(child, event); 30251 } 30252 30253 /** 30254 * Gets the provider for managing a virtual view hierarchy rooted at this View 30255 * and reported to {@link android.accessibilityservice.AccessibilityService}s 30256 * that explore the window content. 30257 * <p> 30258 * The default implementation behaves as 30259 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 30260 * the case of no accessibility delegate been set. 30261 * </p> 30262 * 30263 * @return The provider. 30264 * 30265 * @see AccessibilityNodeProvider 30266 */ getAccessibilityNodeProvider(View host)30267 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 30268 return null; 30269 } 30270 30271 /** 30272 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 30273 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 30274 * This method is responsible for obtaining an accessibility node info from a 30275 * pool of reusable instances and calling 30276 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 30277 * view to initialize the former. 30278 * <p> 30279 * <strong>Note:</strong> The client is responsible for recycling the obtained 30280 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 30281 * creation. 30282 * </p> 30283 * <p> 30284 * The default implementation behaves as 30285 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 30286 * the case of no accessibility delegate been set. 30287 * </p> 30288 * @return A populated {@link AccessibilityNodeInfo}. 30289 * 30290 * @see AccessibilityNodeInfo 30291 * 30292 * @hide 30293 */ 30294 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) createAccessibilityNodeInfo(View host)30295 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 30296 return host.createAccessibilityNodeInfoInternal(); 30297 } 30298 } 30299 30300 private static class MatchIdPredicate implements Predicate<View> { 30301 public int mId; 30302 30303 @Override test(View view)30304 public boolean test(View view) { 30305 return (view.mID == mId); 30306 } 30307 } 30308 30309 private static class MatchLabelForPredicate implements Predicate<View> { 30310 private int mLabeledId; 30311 30312 @Override test(View view)30313 public boolean test(View view) { 30314 return (view.mLabelForId == mLabeledId); 30315 } 30316 } 30317 30318 30319 /** 30320 * Returns the current scroll capture hint for this view. 30321 * 30322 * @return the current scroll capture hint 30323 */ 30324 @ScrollCaptureHint getScrollCaptureHint()30325 public int getScrollCaptureHint() { 30326 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 30327 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 30328 } 30329 30330 /** 30331 * Sets the scroll capture hint for this View. These flags affect the search for a potential 30332 * scroll capture targets. 30333 * 30334 * @param hint the scrollCaptureHint flags value to set 30335 */ setScrollCaptureHint(@crollCaptureHint int hint)30336 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 30337 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 30338 // Since include/exclude are mutually exclusive, exclude takes precedence. 30339 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 30340 hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; 30341 } 30342 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 30343 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 30344 } 30345 30346 /** 30347 * Sets the callback to receive scroll capture requests. This component is the adapter between 30348 * the scroll capture API and application UI code. If no callback is set, the system may provide 30349 * an implementation. Any value provided here will take precedence over a system version. 30350 * <p> 30351 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 30352 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 30353 * <p> 30354 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 30355 * setting a custom callback to help ensure it is selected as the target. 30356 * 30357 * @param callback the new callback to assign 30358 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)30359 public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 30360 getListenerInfo().mScrollCaptureCallback = callback; 30361 } 30362 30363 /** {@hide} */ 30364 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)30365 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 30366 @NonNull Point windowOffset) { 30367 if (mAttachInfo == null) { 30368 return null; 30369 } 30370 if (mAttachInfo.mScrollCaptureInternal == null) { 30371 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 30372 } 30373 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 30374 windowOffset); 30375 } 30376 30377 /** 30378 * Dispatch a scroll capture search request down the view hierarchy. 30379 * 30380 * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to 30381 * the parent 30382 * @param windowOffset the offset of this view within the window 30383 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 30384 * results.accept} may be called zero or more times on the calling 30385 * thread before onScrollCaptureSearch returns 30386 */ dispatchScrollCaptureSearch( @onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)30387 public void dispatchScrollCaptureSearch( 30388 @NonNull Rect localVisibleRect, @NonNull Point windowOffset, 30389 @NonNull Consumer<ScrollCaptureTarget> targets) { 30390 onScrollCaptureSearch(localVisibleRect, windowOffset, targets); 30391 } 30392 30393 /** 30394 * Called when scroll capture is requested, to search for appropriate content to scroll. If 30395 * applicable, this view adds itself to the provided list for consideration, subject to the 30396 * flags set by {@link #setScrollCaptureHint}. 30397 * 30398 * @param localVisibleRect the local visible rect of this view 30399 * @param windowOffset the offset of localVisibleRect within the window 30400 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 30401 * results.accept} may be called zero or more times on the calling 30402 * thread before onScrollCaptureSearch returns 30403 * @throws IllegalStateException if this view is not attached to a window 30404 */ onScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)30405 public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, 30406 @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { 30407 int hint = getScrollCaptureHint(); 30408 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 30409 return; 30410 } 30411 boolean rectIsVisible = true; 30412 30413 // Apply clipBounds if present. 30414 if (mClipBounds != null) { 30415 rectIsVisible = localVisibleRect.intersect(mClipBounds); 30416 } 30417 if (!rectIsVisible) { 30418 return; 30419 } 30420 30421 // Get a callback provided by the framework, library or application. 30422 ScrollCaptureCallback callback = 30423 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 30424 30425 // Try framework support for standard scrolling containers. 30426 if (callback == null) { 30427 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 30428 } 30429 30430 // If found, then add it to the list. 30431 if (callback != null) { 30432 // Add to the list for consideration 30433 Point offset = new Point(windowOffset.x, windowOffset.y); 30434 Rect rect = new Rect(localVisibleRect); 30435 targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); 30436 } 30437 } 30438 30439 /** 30440 * Dump all private flags in readable format, useful for documentation and 30441 * consistency checking. 30442 */ dumpFlags()30443 private static void dumpFlags() { 30444 final HashMap<String, String> found = Maps.newHashMap(); 30445 try { 30446 for (Field field : View.class.getDeclaredFields()) { 30447 final int modifiers = field.getModifiers(); 30448 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 30449 if (field.getType().equals(int.class)) { 30450 final int value = field.getInt(null); 30451 dumpFlag(found, field.getName(), value); 30452 } else if (field.getType().equals(int[].class)) { 30453 final int[] values = (int[]) field.get(null); 30454 for (int i = 0; i < values.length; i++) { 30455 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 30456 } 30457 } 30458 } 30459 } 30460 } catch (IllegalAccessException e) { 30461 throw new RuntimeException(e); 30462 } 30463 30464 final ArrayList<String> keys = Lists.newArrayList(); 30465 keys.addAll(found.keySet()); 30466 Collections.sort(keys); 30467 for (String key : keys) { 30468 Log.d(VIEW_LOG_TAG, found.get(key)); 30469 } 30470 } 30471 dumpFlag(HashMap<String, String> found, String name, int value)30472 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 30473 // Sort flags by prefix, then by bits, always keeping unique keys 30474 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 30475 final int prefix = name.indexOf('_'); 30476 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 30477 final String output = bits + " " + name; 30478 found.put(key, output); 30479 } 30480 30481 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)30482 public void encode(@NonNull ViewHierarchyEncoder stream) { 30483 stream.beginObject(this); 30484 encodeProperties(stream); 30485 stream.endObject(); 30486 } 30487 30488 /** {@hide} */ 30489 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)30490 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 30491 Object resolveId = ViewDebug.resolveId(getContext(), mID); 30492 if (resolveId instanceof String) { 30493 stream.addProperty("id", (String) resolveId); 30494 } else { 30495 stream.addProperty("id", mID); 30496 } 30497 30498 stream.addProperty("misc:transformation.alpha", 30499 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 30500 stream.addProperty("misc:transitionName", getTransitionName()); 30501 30502 // layout 30503 stream.addProperty("layout:left", mLeft); 30504 stream.addProperty("layout:right", mRight); 30505 stream.addProperty("layout:top", mTop); 30506 stream.addProperty("layout:bottom", mBottom); 30507 stream.addProperty("layout:width", getWidth()); 30508 stream.addProperty("layout:height", getHeight()); 30509 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 30510 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 30511 stream.addProperty("layout:hasTransientState", hasTransientState()); 30512 stream.addProperty("layout:baseline", getBaseline()); 30513 30514 // layout params 30515 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 30516 if (layoutParams != null) { 30517 stream.addPropertyKey("layoutParams"); 30518 layoutParams.encode(stream); 30519 } 30520 30521 // scrolling 30522 stream.addProperty("scrolling:scrollX", mScrollX); 30523 stream.addProperty("scrolling:scrollY", mScrollY); 30524 30525 // padding 30526 stream.addProperty("padding:paddingLeft", mPaddingLeft); 30527 stream.addProperty("padding:paddingRight", mPaddingRight); 30528 stream.addProperty("padding:paddingTop", mPaddingTop); 30529 stream.addProperty("padding:paddingBottom", mPaddingBottom); 30530 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 30531 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 30532 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 30533 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 30534 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 30535 30536 // measurement 30537 stream.addProperty("measurement:minHeight", mMinHeight); 30538 stream.addProperty("measurement:minWidth", mMinWidth); 30539 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 30540 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 30541 30542 // drawing 30543 stream.addProperty("drawing:elevation", getElevation()); 30544 stream.addProperty("drawing:translationX", getTranslationX()); 30545 stream.addProperty("drawing:translationY", getTranslationY()); 30546 stream.addProperty("drawing:translationZ", getTranslationZ()); 30547 stream.addProperty("drawing:rotation", getRotation()); 30548 stream.addProperty("drawing:rotationX", getRotationX()); 30549 stream.addProperty("drawing:rotationY", getRotationY()); 30550 stream.addProperty("drawing:scaleX", getScaleX()); 30551 stream.addProperty("drawing:scaleY", getScaleY()); 30552 stream.addProperty("drawing:pivotX", getPivotX()); 30553 stream.addProperty("drawing:pivotY", getPivotY()); 30554 stream.addProperty("drawing:clipBounds", 30555 mClipBounds == null ? null : mClipBounds.toString()); 30556 stream.addProperty("drawing:opaque", isOpaque()); 30557 stream.addProperty("drawing:alpha", getAlpha()); 30558 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 30559 stream.addProperty("drawing:shadow", hasShadow()); 30560 stream.addProperty("drawing:solidColor", getSolidColor()); 30561 stream.addProperty("drawing:layerType", mLayerType); 30562 stream.addProperty("drawing:willNotDraw", willNotDraw()); 30563 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 30564 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 30565 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 30566 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 30567 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 30568 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 30569 30570 // focus 30571 stream.addProperty("focus:hasFocus", hasFocus()); 30572 stream.addProperty("focus:isFocused", isFocused()); 30573 stream.addProperty("focus:focusable", getFocusable()); 30574 stream.addProperty("focus:isFocusable", isFocusable()); 30575 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 30576 30577 stream.addProperty("misc:clickable", isClickable()); 30578 stream.addProperty("misc:pressed", isPressed()); 30579 stream.addProperty("misc:selected", isSelected()); 30580 stream.addProperty("misc:touchMode", isInTouchMode()); 30581 stream.addProperty("misc:hovered", isHovered()); 30582 stream.addProperty("misc:activated", isActivated()); 30583 30584 stream.addProperty("misc:visibility", getVisibility()); 30585 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 30586 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 30587 30588 stream.addProperty("misc:enabled", isEnabled()); 30589 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 30590 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 30591 30592 // theme attributes 30593 Resources.Theme theme = getContext().getTheme(); 30594 if (theme != null) { 30595 stream.addPropertyKey("theme"); 30596 theme.encode(stream); 30597 } 30598 30599 // view attribute information 30600 int n = mAttributes != null ? mAttributes.length : 0; 30601 stream.addProperty("meta:__attrCount__", n/2); 30602 for (int i = 0; i < n; i += 2) { 30603 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 30604 } 30605 30606 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 30607 30608 // text 30609 stream.addProperty("text:textDirection", getTextDirection()); 30610 stream.addProperty("text:textAlignment", getTextAlignment()); 30611 30612 // accessibility 30613 CharSequence contentDescription = getContentDescription(); 30614 stream.addUserProperty("accessibility:contentDescription", 30615 contentDescription == null ? "" : contentDescription.toString()); 30616 stream.addProperty("accessibility:labelFor", getLabelFor()); 30617 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 30618 } 30619 30620 /** 30621 * Determine if this view is rendered on a round wearable device and is the main view 30622 * on the screen. 30623 */ shouldDrawRoundScrollbar()30624 boolean shouldDrawRoundScrollbar() { 30625 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 30626 return false; 30627 } 30628 30629 final View rootView = getRootView(); 30630 final WindowInsets insets = getRootWindowInsets(); 30631 30632 int height = getHeight(); 30633 int width = getWidth(); 30634 int displayHeight = rootView.getHeight(); 30635 int displayWidth = rootView.getWidth(); 30636 30637 if (height != displayHeight || width != displayWidth) { 30638 return false; 30639 } 30640 30641 getLocationInWindow(mAttachInfo.mTmpLocation); 30642 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 30643 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 30644 } 30645 30646 /** 30647 * Sets the tooltip text which will be displayed in a small popup next to the view. 30648 * <p> 30649 * The tooltip will be displayed: 30650 * <ul> 30651 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 30652 * menu). </li> 30653 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 30654 * </ul> 30655 * <p> 30656 * <strong>Note:</strong> Do not override this method, as it will have no 30657 * effect on the text displayed in the tooltip. 30658 * 30659 * @param tooltipText the tooltip text, or null if no tooltip is required 30660 * @see #getTooltipText() 30661 * @attr ref android.R.styleable#View_tooltipText 30662 */ setTooltipText(@ullable CharSequence tooltipText)30663 public void setTooltipText(@Nullable CharSequence tooltipText) { 30664 if (TextUtils.isEmpty(tooltipText)) { 30665 setFlags(0, TOOLTIP); 30666 hideTooltip(); 30667 mTooltipInfo = null; 30668 } else { 30669 setFlags(TOOLTIP, TOOLTIP); 30670 if (mTooltipInfo == null) { 30671 mTooltipInfo = new TooltipInfo(); 30672 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 30673 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 30674 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 30675 mTooltipInfo.clearAnchorPos(); 30676 } 30677 mTooltipInfo.mTooltipText = tooltipText; 30678 } 30679 } 30680 30681 /** 30682 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 30683 */ 30684 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)30685 public void setTooltip(@Nullable CharSequence tooltipText) { 30686 setTooltipText(tooltipText); 30687 } 30688 30689 /** 30690 * Returns the view's tooltip text. 30691 * 30692 * <strong>Note:</strong> Do not override this method, as it will have no 30693 * effect on the text displayed in the tooltip. You must call 30694 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 30695 * 30696 * @return the tooltip text 30697 * @see #setTooltipText(CharSequence) 30698 * @attr ref android.R.styleable#View_tooltipText 30699 */ 30700 @InspectableProperty 30701 @Nullable getTooltipText()30702 public CharSequence getTooltipText() { 30703 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 30704 } 30705 30706 /** 30707 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 30708 */ 30709 @Nullable getTooltip()30710 public CharSequence getTooltip() { 30711 return getTooltipText(); 30712 } 30713 showTooltip(int x, int y, boolean fromLongClick)30714 private boolean showTooltip(int x, int y, boolean fromLongClick) { 30715 if (mAttachInfo == null || mTooltipInfo == null) { 30716 return false; 30717 } 30718 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 30719 return false; 30720 } 30721 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 30722 return false; 30723 } 30724 hideTooltip(); 30725 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 30726 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 30727 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 30728 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 30729 mAttachInfo.mTooltipHost = this; 30730 // The available accessibility actions have changed 30731 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 30732 return true; 30733 } 30734 30735 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hideTooltip()30736 void hideTooltip() { 30737 if (mTooltipInfo == null) { 30738 return; 30739 } 30740 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30741 if (mTooltipInfo.mTooltipPopup == null) { 30742 return; 30743 } 30744 mTooltipInfo.mTooltipPopup.hide(); 30745 mTooltipInfo.mTooltipPopup = null; 30746 mTooltipInfo.mTooltipFromLongClick = false; 30747 mTooltipInfo.clearAnchorPos(); 30748 if (mAttachInfo != null) { 30749 mAttachInfo.mTooltipHost = null; 30750 } 30751 // The available accessibility actions have changed 30752 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 30753 } 30754 showLongClickTooltip(int x, int y)30755 private boolean showLongClickTooltip(int x, int y) { 30756 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30757 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30758 return showTooltip(x, y, true); 30759 } 30760 showHoverTooltip()30761 private boolean showHoverTooltip() { 30762 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 30763 } 30764 dispatchTooltipHoverEvent(MotionEvent event)30765 boolean dispatchTooltipHoverEvent(MotionEvent event) { 30766 if (mTooltipInfo == null) { 30767 return false; 30768 } 30769 switch(event.getAction()) { 30770 case MotionEvent.ACTION_HOVER_MOVE: 30771 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 30772 break; 30773 } 30774 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 30775 if (mTooltipInfo.mTooltipPopup == null) { 30776 // Schedule showing the tooltip after a timeout. 30777 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30778 postDelayed(mTooltipInfo.mShowTooltipRunnable, 30779 ViewConfiguration.getHoverTooltipShowTimeout()); 30780 } 30781 30782 // Hide hover-triggered tooltip after a period of inactivity. 30783 // Match the timeout used by NativeInputManager to hide the mouse pointer 30784 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 30785 final int timeout; 30786 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 30787 == SYSTEM_UI_FLAG_LOW_PROFILE) { 30788 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 30789 } else { 30790 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 30791 } 30792 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30793 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 30794 } 30795 return true; 30796 30797 case MotionEvent.ACTION_HOVER_EXIT: 30798 mTooltipInfo.clearAnchorPos(); 30799 if (!mTooltipInfo.mTooltipFromLongClick) { 30800 hideTooltip(); 30801 } 30802 break; 30803 } 30804 return false; 30805 } 30806 handleTooltipKey(KeyEvent event)30807 void handleTooltipKey(KeyEvent event) { 30808 switch (event.getAction()) { 30809 case KeyEvent.ACTION_DOWN: 30810 if (event.getRepeatCount() == 0) { 30811 hideTooltip(); 30812 } 30813 break; 30814 30815 case KeyEvent.ACTION_UP: 30816 handleTooltipUp(); 30817 break; 30818 } 30819 } 30820 handleTooltipUp()30821 private void handleTooltipUp() { 30822 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 30823 return; 30824 } 30825 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30826 postDelayed(mTooltipInfo.mHideTooltipRunnable, 30827 ViewConfiguration.getLongPressTooltipHideTimeout()); 30828 } 30829 getFocusableAttribute(TypedArray attributes)30830 private int getFocusableAttribute(TypedArray attributes) { 30831 TypedValue val = new TypedValue(); 30832 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 30833 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 30834 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 30835 } else { 30836 return val.data; 30837 } 30838 } else { 30839 return FOCUSABLE_AUTO; 30840 } 30841 } 30842 30843 /** 30844 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 30845 * is not showing. 30846 * @hide 30847 */ 30848 @TestApi getTooltipView()30849 public View getTooltipView() { 30850 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 30851 return null; 30852 } 30853 return mTooltipInfo.mTooltipPopup.getContentView(); 30854 } 30855 30856 /** 30857 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 30858 * @hide 30859 */ 30860 @TestApi isDefaultFocusHighlightEnabled()30861 public static boolean isDefaultFocusHighlightEnabled() { 30862 return sUseDefaultFocusHighlight; 30863 } 30864 30865 /** 30866 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 30867 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 30868 * (visually on-top views first). 30869 * 30870 * @param evt the previously unhandled {@link KeyEvent}. 30871 * @return the {@link View} which consumed the event or {@code null} if not consumed. 30872 */ dispatchUnhandledKeyEvent(KeyEvent evt)30873 View dispatchUnhandledKeyEvent(KeyEvent evt) { 30874 if (onUnhandledKeyEvent(evt)) { 30875 return this; 30876 } 30877 return null; 30878 } 30879 30880 /** 30881 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 30882 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 30883 * this will dispatch into all the listeners registered via 30884 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 30885 * order (most recently added will receive events first). 30886 * 30887 * @param event An unhandled event. 30888 * @return {@code true} if the event was handled, {@code false} otherwise. 30889 * @see #addOnUnhandledKeyEventListener 30890 */ onUnhandledKeyEvent(@onNull KeyEvent event)30891 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 30892 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 30893 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 30894 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 30895 return true; 30896 } 30897 } 30898 } 30899 return false; 30900 } 30901 hasUnhandledKeyListener()30902 boolean hasUnhandledKeyListener() { 30903 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 30904 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 30905 } 30906 30907 /** 30908 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 30909 * UI thread. 30910 * 30911 * @param listener a receiver of unhandled {@link KeyEvent}s. 30912 * @see #removeOnUnhandledKeyEventListener 30913 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)30914 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 30915 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 30916 if (listeners == null) { 30917 listeners = new ArrayList<>(); 30918 getListenerInfo().mUnhandledKeyListeners = listeners; 30919 } 30920 listeners.add(listener); 30921 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 30922 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 30923 } 30924 } 30925 30926 /** 30927 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 30928 * UI thread. 30929 * 30930 * @param listener a receiver of unhandled {@link KeyEvent}s. 30931 * @see #addOnUnhandledKeyEventListener 30932 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)30933 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 30934 if (mListenerInfo != null) { 30935 if (mListenerInfo.mUnhandledKeyListeners != null 30936 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 30937 mListenerInfo.mUnhandledKeyListeners.remove(listener); 30938 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 30939 mListenerInfo.mUnhandledKeyListeners = null; 30940 if (mParent instanceof ViewGroup) { 30941 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 30942 } 30943 } 30944 } 30945 } 30946 } 30947 30948 /** 30949 * Set the view to be detached or not detached. 30950 * 30951 * @param detached Whether the view is detached. 30952 * 30953 * @hide 30954 */ setDetached(boolean detached)30955 protected void setDetached(boolean detached) { 30956 if (detached) { 30957 mPrivateFlags4 |= PFLAG4_DETACHED; 30958 } else { 30959 mPrivateFlags4 &= ~PFLAG4_DETACHED; 30960 } 30961 } 30962 30963 /** 30964 * Collects a {@link ViewTranslationRequest} which represents the content to be translated in 30965 * the view. 30966 * 30967 * <p>The default implementation does nothing.</p> 30968 * 30969 * @param supportedFormats the supported translation formats. For now, the only possible value 30970 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 30971 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be used to 30972 * collect the information to be translated in the view. The {@code requestsCollector} only 30973 * accepts one request; an IllegalStateException is thrown if more than one 30974 * {@link ViewTranslationRequest} is submitted to it. The {@link AutofillId} must be set on the 30975 * {@link ViewTranslationRequest}. 30976 */ onCreateViewTranslationRequest(@onNull @ataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)30977 public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, 30978 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 30979 } 30980 30981 /** 30982 * Collects {@link ViewTranslationRequest}s which represents the content to be translated 30983 * for the virtual views in the host view. This is called if this view returned a virtual 30984 * view structure from {@link #onProvideContentCaptureStructure} and the system determined that 30985 * those virtual views were relevant for translation. 30986 * 30987 * <p>The default implementation does nothing.</p> 30988 * 30989 * @param virtualIds the virtual view ids which represents the virtual views in the host 30990 * view. 30991 * @param supportedFormats the supported translation formats. For now, the only possible value 30992 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 30993 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called 30994 * multiple times to collect the information to be translated in the host view. One 30995 * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must 30996 * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this 30997 * Consumer after the method returns. 30998 */ 30999 @SuppressLint("NullableCollection") onCreateVirtualViewTranslationRequests(@onNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)31000 public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, 31001 @NonNull @DataFormat int[] supportedFormats, 31002 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 31003 // no-op 31004 } 31005 31006 /** 31007 * Returns a {@link ViewTranslationCallback} that is used to display the translated information 31008 * or {@code null} if this View doesn't support translation. 31009 * 31010 * @hide 31011 */ 31012 @Nullable getViewTranslationCallback()31013 public ViewTranslationCallback getViewTranslationCallback() { 31014 return mViewTranslationCallback; 31015 } 31016 31017 /** 31018 * Sets a {@link ViewTranslationCallback} that is used to display/hide the translated 31019 * information. Developers can provide the customized implementation for show/hide translated 31020 * information. 31021 * 31022 * @param callback a {@link ViewTranslationCallback} that is used to control how to display the 31023 * translated information 31024 */ setViewTranslationCallback(@onNull ViewTranslationCallback callback)31025 public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { 31026 mViewTranslationCallback = callback; 31027 } 31028 31029 /** 31030 * Clear the {@link ViewTranslationCallback} from this view. 31031 */ clearViewTranslationCallback()31032 public void clearViewTranslationCallback() { 31033 mViewTranslationCallback = null; 31034 } 31035 31036 /** 31037 * Returns the {@link ViewTranslationResponse} associated with this view. The response will be 31038 * set when the translation is done then {@link #onViewTranslationResponse} is called. The 31039 * {@link ViewTranslationCallback} can use to get {@link ViewTranslationResponse} to display the 31040 * translated information. 31041 * 31042 * @return a {@link ViewTranslationResponse} that contains the translated information associated 31043 * with this view or {@code null} if this View doesn't have the translation. 31044 */ 31045 @Nullable getViewTranslationResponse()31046 public ViewTranslationResponse getViewTranslationResponse() { 31047 return mViewTranslationResponse; 31048 } 31049 31050 /** 31051 * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated 31052 * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that 31053 * the {@link ViewTranslationResponse} can be used to display the translation when the system 31054 * calls {@link ViewTranslationCallback#onShowTranslation}. 31055 * 31056 * <p> The default implementation will set the ViewTranslationResponse that can be get from 31057 * {@link View#getViewTranslationResponse}. </p> 31058 * 31059 * @param response a {@link ViewTranslationResponse} that contains the translated information 31060 * which can be shown in the view. 31061 */ onViewTranslationResponse(@onNull ViewTranslationResponse response)31062 public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { 31063 mViewTranslationResponse = response; 31064 } 31065 31066 /** 31067 * Clears the ViewTranslationResponse stored by the default implementation of {@link 31068 * #onViewTranslationResponse}. 31069 * 31070 * @hide 31071 */ clearViewTranslationResponse()31072 public void clearViewTranslationResponse() { 31073 mViewTranslationResponse = null; 31074 } 31075 31076 /** 31077 * Called when the content from {@link View#onCreateVirtualViewTranslationRequests} had been 31078 * translated by the TranslationService. 31079 * 31080 * <p> The default implementation does nothing.</p> 31081 * 31082 * @param response a {@link ViewTranslationResponse} SparseArray for the request that send by 31083 * {@link View#onCreateVirtualViewTranslationRequests} that contains the translated information 31084 * which can be shown in the view. The key of SparseArray is the virtual child ids. 31085 */ onVirtualViewTranslationResponses( @onNull LongSparseArray<ViewTranslationResponse> response)31086 public void onVirtualViewTranslationResponses( 31087 @NonNull LongSparseArray<ViewTranslationResponse> response) { 31088 // no-op 31089 } 31090 31091 /** 31092 * Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing 31093 * the hierarchy when the app requests ui translation. Typically, this method should only be 31094 * overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other 31095 * classes should override {@link View#onCreateViewTranslationRequest} for normal view or 31096 * override {@link View#onVirtualViewTranslationResponses} for view contains virtual children. 31097 * When requested to start the ui translation, the system will call this method to traverse the 31098 * view hierarchy to collect {@link ViewTranslationRequest}s and create a 31099 * {@link android.view.translation.Translator} to translate the requests. All the 31100 * {@link ViewTranslationRequest}s must be added when the traversal is done. 31101 * 31102 * <p> The default implementation calls {@link View#onCreateViewTranslationRequest} for normal 31103 * view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual 31104 * children to build {@link ViewTranslationRequest} if the view should be translated. 31105 * The view is marked as having {@link #setHasTransientState(boolean) transient state} so that 31106 * recycling of views doesn't prevent the system from attaching the response to it. Therefore, 31107 * if overriding this method, you should set or reset the transient state. </p> 31108 * 31109 * @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or 31110 * {@code null} if the view doesn't have virtual child that should be translated. The virtual 31111 * child ids are the same virtual ids provided by ContentCapture. 31112 * @param supportedFormats the supported translation formats. For now, the only possible value 31113 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 31114 * @param capability a {@link TranslationCapability} that holds translation capability. 31115 * information, e.g. source spec, target spec. 31116 * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose. 31117 */ dispatchCreateViewTranslationRequest(@onNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests)31118 public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, 31119 @NonNull @DataFormat int[] supportedFormats, 31120 @NonNull TranslationCapability capability, 31121 @NonNull List<ViewTranslationRequest> requests) { 31122 AutofillId autofillId = getAutofillId(); 31123 if (viewIds.containsKey(autofillId)) { 31124 if (viewIds.get(autofillId) == null) { 31125 // TODO: avoiding the allocation per view 31126 onCreateViewTranslationRequest(supportedFormats, 31127 new ViewTranslationRequestConsumer(requests)); 31128 } else { 31129 onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, 31130 request -> { 31131 requests.add(request); 31132 }); 31133 } 31134 } 31135 } 31136 31137 private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { 31138 private final List<ViewTranslationRequest> mRequests; 31139 private boolean mCalled; 31140 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests)31141 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { 31142 mRequests = requests; 31143 } 31144 31145 @Override accept(ViewTranslationRequest request)31146 public void accept(ViewTranslationRequest request) { 31147 if (mCalled) { 31148 throw new IllegalStateException("The translation Consumer is not reusable."); 31149 } 31150 mCalled = true; 31151 if (request != null && request.getKeys().size() > 0) { 31152 mRequests.add(request); 31153 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 31154 Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " 31155 + getAutofillId()); 31156 } 31157 setHasTransientState(true); 31158 setHasTranslationTransientState(true); 31159 } 31160 } 31161 } 31162 31163 /** 31164 * Called to generate a {@link DisplayHash} for this view. 31165 * 31166 * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of 31167 * the values returned from 31168 * {@link DisplayHashManager#getSupportedHashAlgorithms()} 31169 * @param bounds The bounds for the content within the View to generate the hash for. If 31170 * bounds are null, the entire View's bounds will be used. If empty, it will 31171 * invoke the callback 31172 * {@link DisplayHashResultCallback#onDisplayHashError} with error 31173 * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} 31174 * @param executor The executor that the callback should be invoked on. 31175 * @param callback The callback to handle the results of generating the display hash 31176 */ generateDisplayHash(@onNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback)31177 public void generateDisplayHash(@NonNull String hashAlgorithm, 31178 @Nullable Rect bounds, @NonNull Executor executor, 31179 @NonNull DisplayHashResultCallback callback) { 31180 IWindowSession session = getWindowSession(); 31181 if (session == null) { 31182 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 31183 return; 31184 } 31185 IWindow window = getWindow(); 31186 if (window == null) { 31187 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 31188 return; 31189 } 31190 31191 Rect visibleBounds = new Rect(); 31192 getGlobalVisibleRect(visibleBounds); 31193 31194 if (bounds != null && bounds.isEmpty()) { 31195 callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); 31196 return; 31197 } 31198 31199 if (bounds != null) { 31200 bounds.offset(visibleBounds.left, visibleBounds.top); 31201 visibleBounds.intersectUnchecked(bounds); 31202 } 31203 31204 if (visibleBounds.isEmpty()) { 31205 callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); 31206 return; 31207 } 31208 31209 RemoteCallback remoteCallback = new RemoteCallback(result -> 31210 executor.execute(() -> { 31211 DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH); 31212 int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, 31213 DISPLAY_HASH_ERROR_UNKNOWN); 31214 if (displayHash != null) { 31215 callback.onDisplayHashResult(displayHash); 31216 } else { 31217 callback.onDisplayHashError(errorCode); 31218 } 31219 })); 31220 31221 try { 31222 session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); 31223 } catch (RemoteException e) { 31224 Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); 31225 callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); 31226 } 31227 } 31228 31229 /** 31230 * The AttachedSurfaceControl itself is not a View, it is just the interface to the 31231 * windowing-system object that contains the entire view hierarchy. 31232 * For the root View of a given hierarchy see {@link #getRootView}. 31233 31234 * @return The {@link android.view.AttachedSurfaceControl} interface for this View. 31235 * This will only return a non-null value when called between {@link #onAttachedToWindow} 31236 * and {@link #onDetachedFromWindow}. 31237 */ getRootSurfaceControl()31238 public @Nullable AttachedSurfaceControl getRootSurfaceControl() { 31239 if (mAttachInfo != null) { 31240 return mAttachInfo.getRootSurfaceControl(); 31241 } 31242 return null; 31243 } 31244 } 31245