1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import static android.content.res.Resources.ID_NULL; 20 import static android.os.Trace.TRACE_TAG_APP; 21 import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; 22 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 23 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; 24 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 25 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; 26 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; 27 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; 28 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; 29 30 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 31 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 32 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 33 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 34 35 import static java.lang.Math.max; 36 37 import android.animation.AnimatorInflater; 38 import android.animation.StateListAnimator; 39 import android.annotation.AttrRes; 40 import android.annotation.CallSuper; 41 import android.annotation.ColorInt; 42 import android.annotation.DrawableRes; 43 import android.annotation.FloatRange; 44 import android.annotation.IdRes; 45 import android.annotation.IntDef; 46 import android.annotation.IntRange; 47 import android.annotation.LayoutRes; 48 import android.annotation.NonNull; 49 import android.annotation.Nullable; 50 import android.annotation.RequiresPermission; 51 import android.annotation.Size; 52 import android.annotation.StyleRes; 53 import android.annotation.SuppressLint; 54 import android.annotation.SystemApi; 55 import android.annotation.TestApi; 56 import android.annotation.UiContext; 57 import android.annotation.UiThread; 58 import android.compat.annotation.UnsupportedAppUsage; 59 import android.content.AutofillOptions; 60 import android.content.ClipData; 61 import android.content.ClipDescription; 62 import android.content.Context; 63 import android.content.ContextWrapper; 64 import android.content.Intent; 65 import android.content.res.ColorStateList; 66 import android.content.res.Configuration; 67 import android.content.res.Resources; 68 import android.content.res.TypedArray; 69 import android.graphics.Bitmap; 70 import android.graphics.BlendMode; 71 import android.graphics.Canvas; 72 import android.graphics.Color; 73 import android.graphics.Insets; 74 import android.graphics.Interpolator; 75 import android.graphics.LinearGradient; 76 import android.graphics.Matrix; 77 import android.graphics.Outline; 78 import android.graphics.Paint; 79 import android.graphics.PixelFormat; 80 import android.graphics.Point; 81 import android.graphics.PorterDuff; 82 import android.graphics.PorterDuffXfermode; 83 import android.graphics.RecordingCanvas; 84 import android.graphics.Rect; 85 import android.graphics.RectF; 86 import android.graphics.Region; 87 import android.graphics.RenderEffect; 88 import android.graphics.RenderNode; 89 import android.graphics.Shader; 90 import android.graphics.drawable.ColorDrawable; 91 import android.graphics.drawable.Drawable; 92 import android.graphics.drawable.GradientDrawable; 93 import android.hardware.display.DisplayManagerGlobal; 94 import android.net.Uri; 95 import android.os.Build; 96 import android.os.Bundle; 97 import android.os.Handler; 98 import android.os.IBinder; 99 import android.os.Message; 100 import android.os.Parcel; 101 import android.os.Parcelable; 102 import android.os.RemoteCallback; 103 import android.os.RemoteException; 104 import android.os.SystemClock; 105 import android.os.Trace; 106 import android.sysprop.DisplayProperties; 107 import android.text.InputType; 108 import android.text.TextUtils; 109 import android.util.AttributeSet; 110 import android.util.FloatProperty; 111 import android.util.LayoutDirection; 112 import android.util.Log; 113 import android.util.LongSparseArray; 114 import android.util.LongSparseLongArray; 115 import android.util.Pair; 116 import android.util.Pools.SynchronizedPool; 117 import android.util.Property; 118 import android.util.SparseArray; 119 import android.util.SparseIntArray; 120 import android.util.StateSet; 121 import android.util.SuperNotCalledException; 122 import android.util.TypedValue; 123 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 124 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 125 import android.view.AccessibilityIterators.TextSegmentIterator; 126 import android.view.AccessibilityIterators.WordTextSegmentIterator; 127 import android.view.ContextMenu.ContextMenuInfo; 128 import android.view.InputDevice.InputSourceClass; 129 import android.view.Window.OnContentApplyWindowInsetsListener; 130 import android.view.WindowInsets.Type; 131 import android.view.WindowInsetsAnimation.Bounds; 132 import android.view.WindowManager.LayoutParams; 133 import android.view.accessibility.AccessibilityEvent; 134 import android.view.accessibility.AccessibilityEventSource; 135 import android.view.accessibility.AccessibilityManager; 136 import android.view.accessibility.AccessibilityNodeIdManager; 137 import android.view.accessibility.AccessibilityNodeInfo; 138 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 139 import android.view.accessibility.AccessibilityNodeProvider; 140 import android.view.accessibility.AccessibilityWindowInfo; 141 import android.view.animation.Animation; 142 import android.view.animation.AnimationUtils; 143 import android.view.animation.Transformation; 144 import android.view.autofill.AutofillId; 145 import android.view.autofill.AutofillManager; 146 import android.view.autofill.AutofillValue; 147 import android.view.contentcapture.ContentCaptureContext; 148 import android.view.contentcapture.ContentCaptureManager; 149 import android.view.contentcapture.ContentCaptureSession; 150 import android.view.displayhash.DisplayHash; 151 import android.view.displayhash.DisplayHashManager; 152 import android.view.displayhash.DisplayHashResultCallback; 153 import android.view.inputmethod.EditorInfo; 154 import android.view.inputmethod.InputConnection; 155 import android.view.inspector.InspectableProperty; 156 import android.view.inspector.InspectableProperty.EnumEntry; 157 import android.view.inspector.InspectableProperty.FlagEntry; 158 import android.view.translation.TranslationCapability; 159 import android.view.translation.TranslationSpec.DataFormat; 160 import android.view.translation.ViewTranslationCallback; 161 import android.view.translation.ViewTranslationRequest; 162 import android.view.translation.ViewTranslationResponse; 163 import android.widget.Checkable; 164 import android.widget.FrameLayout; 165 import android.widget.ScrollBarDrawable; 166 import android.window.OnBackInvokedDispatcher; 167 168 import com.android.internal.R; 169 import com.android.internal.util.ArrayUtils; 170 import com.android.internal.util.FrameworkStatsLog; 171 import com.android.internal.util.Preconditions; 172 import com.android.internal.view.ScrollCaptureInternal; 173 import com.android.internal.view.TooltipPopup; 174 import com.android.internal.view.menu.MenuBuilder; 175 import com.android.internal.widget.ScrollBarUtils; 176 177 import com.google.android.collect.Lists; 178 import com.google.android.collect.Maps; 179 180 import java.io.PrintWriter; 181 import java.lang.annotation.Retention; 182 import java.lang.annotation.RetentionPolicy; 183 import java.lang.ref.WeakReference; 184 import java.lang.reflect.Field; 185 import java.lang.reflect.InvocationTargetException; 186 import java.lang.reflect.Method; 187 import java.lang.reflect.Modifier; 188 import java.util.ArrayList; 189 import java.util.Arrays; 190 import java.util.Calendar; 191 import java.util.Collection; 192 import java.util.Collections; 193 import java.util.HashMap; 194 import java.util.List; 195 import java.util.Locale; 196 import java.util.Map; 197 import java.util.concurrent.CopyOnWriteArrayList; 198 import java.util.concurrent.Executor; 199 import java.util.concurrent.atomic.AtomicInteger; 200 import java.util.function.Consumer; 201 import java.util.function.Predicate; 202 203 /** 204 * <p> 205 * This class represents the basic building block for user interface components. A View 206 * occupies a rectangular area on the screen and is responsible for drawing and 207 * event handling. View is the base class for <em>widgets</em>, which are 208 * used to create interactive UI components (buttons, text fields, etc.). The 209 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 210 * are invisible containers that hold other Views (or other ViewGroups) and define 211 * their layout properties. 212 * </p> 213 * 214 * <div class="special reference"> 215 * <h3>Developer Guides</h3> 216 * <p>For information about using this class to develop your application's user interface, 217 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 218 * </div> 219 * 220 * <a name="Using"></a> 221 * <h3>Using Views</h3> 222 * <p> 223 * All of the views in a window are arranged in a single tree. You can add views 224 * either from code or by specifying a tree of views in one or more XML layout 225 * files. There are many specialized subclasses of views that act as controls or 226 * are capable of displaying text, images, or other content. 227 * </p> 228 * <p> 229 * Once you have created a tree of views, there are typically a few types of 230 * common operations you may wish to perform: 231 * <ul> 232 * <li><strong>Set properties:</strong> for example setting the text of a 233 * {@link android.widget.TextView}. The available properties and the methods 234 * that set them will vary among the different subclasses of views. Note that 235 * properties that are known at build time can be set in the XML layout 236 * files.</li> 237 * <li><strong>Set focus:</strong> The framework will handle moving focus in 238 * response to user input. To force focus to a specific view, call 239 * {@link #requestFocus}.</li> 240 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 241 * that will be notified when something interesting happens to the view. For 242 * example, all views will let you set a listener to be notified when the view 243 * gains or loses focus. You can register such a listener using 244 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 245 * Other view subclasses offer more specialized listeners. For example, a Button 246 * exposes a listener to notify clients when the button is clicked.</li> 247 * <li><strong>Set visibility:</strong> You can hide or show views using 248 * {@link #setVisibility(int)}.</li> 249 * </ul> 250 * </p> 251 * <p><em> 252 * Note: The Android framework is responsible for measuring, laying out and 253 * drawing views. You should not call methods that perform these actions on 254 * views yourself unless you are actually implementing a 255 * {@link android.view.ViewGroup}. 256 * </em></p> 257 * 258 * <a name="Lifecycle"></a> 259 * <h3>Implementing a Custom View</h3> 260 * 261 * <p> 262 * To implement a custom view, you will usually begin by providing overrides for 263 * some of the standard methods that the framework calls on all views. You do 264 * not need to override all of these methods. In fact, you can start by just 265 * overriding {@link #onDraw(android.graphics.Canvas)}. 266 * <table border="2" width="85%" align="center" cellpadding="5"> 267 * <thead> 268 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 269 * </thead> 270 * 271 * <tbody> 272 * <tr> 273 * <td rowspan="2">Creation</td> 274 * <td>Constructors</td> 275 * <td>There is a form of the constructor that are called when the view 276 * is created from code and a form that is called when the view is 277 * inflated from a layout file. The second form should parse and apply 278 * any attributes defined in the layout file. 279 * </td> 280 * </tr> 281 * <tr> 282 * <td><code>{@link #onFinishInflate()}</code></td> 283 * <td>Called after a view and all of its children has been inflated 284 * from XML.</td> 285 * </tr> 286 * 287 * <tr> 288 * <td rowspan="3">Layout</td> 289 * <td><code>{@link #onMeasure(int, int)}</code></td> 290 * <td>Called to determine the size requirements for this view and all 291 * of its children. 292 * </td> 293 * </tr> 294 * <tr> 295 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 296 * <td>Called when this view should assign a size and position to all 297 * of its children. 298 * </td> 299 * </tr> 300 * <tr> 301 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 302 * <td>Called when the size of this view has changed. 303 * </td> 304 * </tr> 305 * 306 * <tr> 307 * <td>Drawing</td> 308 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 309 * <td>Called when the view should render its content. 310 * </td> 311 * </tr> 312 * 313 * <tr> 314 * <td rowspan="4">Event processing</td> 315 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 316 * <td>Called when a new hardware key event occurs. 317 * </td> 318 * </tr> 319 * <tr> 320 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 321 * <td>Called when a hardware key up event occurs. 322 * </td> 323 * </tr> 324 * <tr> 325 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 326 * <td>Called when a trackball motion event occurs. 327 * </td> 328 * </tr> 329 * <tr> 330 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 331 * <td>Called when a touch screen motion event occurs. 332 * </td> 333 * </tr> 334 * 335 * <tr> 336 * <td rowspan="2">Focus</td> 337 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 338 * <td>Called when the view gains or loses focus. 339 * </td> 340 * </tr> 341 * 342 * <tr> 343 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 344 * <td>Called when the window containing the view gains or loses focus. 345 * </td> 346 * </tr> 347 * 348 * <tr> 349 * <td rowspan="3">Attaching</td> 350 * <td><code>{@link #onAttachedToWindow()}</code></td> 351 * <td>Called when the view is attached to a window. 352 * </td> 353 * </tr> 354 * 355 * <tr> 356 * <td><code>{@link #onDetachedFromWindow}</code></td> 357 * <td>Called when the view is detached from its window. 358 * </td> 359 * </tr> 360 * 361 * <tr> 362 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 363 * <td>Called when the visibility of the window containing the view 364 * has changed. 365 * </td> 366 * </tr> 367 * </tbody> 368 * 369 * </table> 370 * </p> 371 * 372 * <a name="IDs"></a> 373 * <h3>IDs</h3> 374 * Views may have an integer id associated with them. These ids are typically 375 * assigned in the layout XML files, and are used to find specific views within 376 * the view tree. A common pattern is to: 377 * <ul> 378 * <li>Define a Button in the layout file and assign it a unique ID. 379 * <pre> 380 * <Button 381 * android:id="@+id/my_button" 382 * android:layout_width="wrap_content" 383 * android:layout_height="wrap_content" 384 * android:text="@string/my_button_text"/> 385 * </pre></li> 386 * <li>From the onCreate method of an Activity, find the Button 387 * <pre class="prettyprint"> 388 * Button myButton = findViewById(R.id.my_button); 389 * </pre></li> 390 * </ul> 391 * <p> 392 * View IDs need not be unique throughout the tree, but it is good practice to 393 * ensure that they are at least unique within the part of the tree you are 394 * searching. 395 * </p> 396 * 397 * <a name="Position"></a> 398 * <h3>Position</h3> 399 * <p> 400 * The geometry of a view is that of a rectangle. A view has a location, 401 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 402 * two dimensions, expressed as a width and a height. The unit for location 403 * and dimensions is the pixel. 404 * </p> 405 * 406 * <p> 407 * It is possible to retrieve the location of a view by invoking the methods 408 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 409 * coordinate of the rectangle representing the view. The latter returns the 410 * top, or Y, coordinate of the rectangle representing the view. These methods 411 * both return the location of the view relative to its parent. For instance, 412 * when getLeft() returns 20, that means the view is located 20 pixels to the 413 * right of the left edge of its direct parent. 414 * </p> 415 * 416 * <p> 417 * In addition, several convenience methods are offered to avoid unnecessary 418 * computations, namely {@link #getRight()} and {@link #getBottom()}. 419 * These methods return the coordinates of the right and bottom edges of the 420 * rectangle representing the view. For instance, calling {@link #getRight()} 421 * is similar to the following computation: <code>getLeft() + getWidth()</code> 422 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 423 * </p> 424 * 425 * <a name="SizePaddingMargins"></a> 426 * <h3>Size, padding and margins</h3> 427 * <p> 428 * The size of a view is expressed with a width and a height. A view actually 429 * possess two pairs of width and height values. 430 * </p> 431 * 432 * <p> 433 * The first pair is known as <em>measured width</em> and 434 * <em>measured height</em>. These dimensions define how big a view wants to be 435 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 436 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 437 * and {@link #getMeasuredHeight()}. 438 * </p> 439 * 440 * <p> 441 * The second pair is simply known as <em>width</em> and <em>height</em>, or 442 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 443 * dimensions define the actual size of the view on screen, at drawing time and 444 * after layout. These values may, but do not have to, be different from the 445 * measured width and height. The width and height can be obtained by calling 446 * {@link #getWidth()} and {@link #getHeight()}. 447 * </p> 448 * 449 * <p> 450 * To measure its dimensions, a view takes into account its padding. The padding 451 * is expressed in pixels for the left, top, right and bottom parts of the view. 452 * Padding can be used to offset the content of the view by a specific amount of 453 * pixels. For instance, a left padding of 2 will push the view's content by 454 * 2 pixels to the right of the left edge. Padding can be set using the 455 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 456 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 457 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 458 * {@link #getPaddingEnd()}. 459 * </p> 460 * 461 * <p> 462 * Even though a view can define a padding, it does not provide any support for 463 * margins. However, view groups provide such a support. Refer to 464 * {@link android.view.ViewGroup} and 465 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 466 * </p> 467 * 468 * <a name="Layout"></a> 469 * <h3>Layout</h3> 470 * <p> 471 * Layout is a two pass process: a measure pass and a layout pass. The measuring 472 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 473 * of the view tree. Each view pushes dimension specifications down the tree 474 * during the recursion. At the end of the measure pass, every view has stored 475 * its measurements. The second pass happens in 476 * {@link #layout(int,int,int,int)} and is also top-down. During 477 * this pass each parent is responsible for positioning all of its children 478 * using the sizes computed in the measure pass. 479 * </p> 480 * 481 * <p> 482 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 483 * {@link #getMeasuredHeight()} values must be set, along with those for all of 484 * that view's descendants. A view's measured width and measured height values 485 * must respect the constraints imposed by the view's parents. This guarantees 486 * that at the end of the measure pass, all parents accept all of their 487 * children's measurements. A parent view may call measure() more than once on 488 * its children. For example, the parent may measure each child once with 489 * unspecified dimensions to find out how big they want to be, then call 490 * measure() on them again with actual numbers if the sum of all the children's 491 * unconstrained sizes is too big or too small. 492 * </p> 493 * 494 * <p> 495 * The measure pass uses two classes to communicate dimensions. The 496 * {@link MeasureSpec} class is used by views to tell their parents how they 497 * want to be measured and positioned. The base LayoutParams class just 498 * describes how big the view wants to be for both width and height. For each 499 * dimension, it can specify one of: 500 * <ul> 501 * <li> an exact number 502 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 503 * (minus padding) 504 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 505 * enclose its content (plus padding). 506 * </ul> 507 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 508 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 509 * an X and Y value. 510 * </p> 511 * 512 * <p> 513 * MeasureSpecs are used to push requirements down the tree from parent to 514 * child. A MeasureSpec can be in one of three modes: 515 * <ul> 516 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 517 * of a child view. For example, a LinearLayout may call measure() on its child 518 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 519 * tall the child view wants to be given a width of 240 pixels. 520 * <li>EXACTLY: This is used by the parent to impose an exact size on the 521 * child. The child must use this size, and guarantee that all of its 522 * descendants will fit within this size. 523 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 524 * child. The child must guarantee that it and all of its descendants will fit 525 * within this size. 526 * </ul> 527 * </p> 528 * 529 * <p> 530 * To initiate a layout, call {@link #requestLayout}. This method is typically 531 * called by a view on itself when it believes that it can no longer fit within 532 * its current bounds. 533 * </p> 534 * 535 * <a name="Drawing"></a> 536 * <h3>Drawing</h3> 537 * <p> 538 * Drawing is handled by walking the tree and recording the drawing commands of 539 * any View that needs to update. After this, the drawing commands of the 540 * entire tree are issued to screen, clipped to the newly damaged area. 541 * </p> 542 * 543 * <p> 544 * The tree is largely recorded and drawn in order, with parents drawn before 545 * (i.e., behind) their children, with siblings drawn in the order they appear 546 * in the tree. If you set a background drawable for a View, then the View will 547 * draw it before calling back to its <code>onDraw()</code> method. The child 548 * drawing order can be overridden with 549 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 550 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 551 * </p> 552 * 553 * <p> 554 * To force a view to draw, call {@link #invalidate()}. 555 * </p> 556 * 557 * <a name="EventHandlingThreading"></a> 558 * <h3>Event Handling and Threading</h3> 559 * <p> 560 * The basic cycle of a view is as follows: 561 * <ol> 562 * <li>An event comes in and is dispatched to the appropriate view. The view 563 * handles the event and notifies any listeners.</li> 564 * <li>If in the course of processing the event, the view's bounds may need 565 * to be changed, the view will call {@link #requestLayout()}.</li> 566 * <li>Similarly, if in the course of processing the event the view's appearance 567 * may need to be changed, the view will call {@link #invalidate()}.</li> 568 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 569 * the framework will take care of measuring, laying out, and drawing the tree 570 * as appropriate.</li> 571 * </ol> 572 * </p> 573 * 574 * <p><em>Note: The entire view tree is single threaded. You must always be on 575 * the UI thread when calling any method on any view.</em> 576 * If you are doing work on other threads and want to update the state of a view 577 * from that thread, you should use a {@link Handler}. 578 * </p> 579 * 580 * <a name="FocusHandling"></a> 581 * <h3>Focus Handling</h3> 582 * <p> 583 * The framework will handle routine focus movement in response to user input. 584 * This includes changing the focus as views are removed or hidden, or as new 585 * views become available. Views indicate their willingness to take focus 586 * through the {@link #isFocusable} method. To change whether a view can take 587 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 588 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 589 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 590 * </p> 591 * <p> 592 * Focus movement is based on an algorithm which finds the nearest neighbor in a 593 * given direction. In rare cases, the default algorithm may not match the 594 * intended behavior of the developer. In these situations, you can provide 595 * explicit overrides by using these XML attributes in the layout file: 596 * <pre> 597 * nextFocusDown 598 * nextFocusLeft 599 * nextFocusRight 600 * nextFocusUp 601 * </pre> 602 * </p> 603 * 604 * 605 * <p> 606 * To get a particular view to take focus, call {@link #requestFocus()}. 607 * </p> 608 * 609 * <a name="TouchMode"></a> 610 * <h3>Touch Mode</h3> 611 * <p> 612 * When a user is navigating a user interface via directional keys such as a D-pad, it is 613 * necessary to give focus to actionable items such as buttons so the user can see 614 * what will take input. If the device has touch capabilities, however, and the user 615 * begins interacting with the interface by touching it, it is no longer necessary to 616 * always highlight, or give focus to, a particular view. This motivates a mode 617 * for interaction named 'touch mode'. 618 * </p> 619 * <p> 620 * For a touch capable device, once the user touches the screen, the device 621 * will enter touch mode. From this point onward, only views for which 622 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 623 * Other views that are touchable, like buttons, will not take focus when touched; they will 624 * only fire the on click listeners. 625 * </p> 626 * <p> 627 * Any time a user hits a directional key, such as a D-pad direction, the view device will 628 * exit touch mode, and find a view to take focus, so that the user may resume interacting 629 * with the user interface without touching the screen again. 630 * </p> 631 * <p> 632 * The touch mode state is maintained across {@link android.app.Activity}s. Call 633 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 634 * </p> 635 * 636 * <a name="Scrolling"></a> 637 * <h3>Scrolling</h3> 638 * <p> 639 * The framework provides basic support for views that wish to internally 640 * scroll their content. This includes keeping track of the X and Y scroll 641 * offset as well as mechanisms for drawing scrollbars. See 642 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 643 * {@link #awakenScrollBars()} for more details. 644 * </p> 645 * 646 * <a name="Tags"></a> 647 * <h3>Tags</h3> 648 * <p> 649 * Unlike IDs, tags are not used to identify views. Tags are essentially an 650 * extra piece of information that can be associated with a view. They are most 651 * often used as a convenience to store data related to views in the views 652 * themselves rather than by putting them in a separate structure. 653 * </p> 654 * <p> 655 * Tags may be specified with character sequence values in layout XML as either 656 * a single tag using the {@link android.R.styleable#View_tag android:tag} 657 * attribute or multiple tags using the {@code <tag>} child element: 658 * <pre> 659 * <View ... 660 * android:tag="@string/mytag_value" /> 661 * <View ...> 662 * <tag android:id="@+id/mytag" 663 * android:value="@string/mytag_value" /> 664 * </View> 665 * </pre> 666 * </p> 667 * <p> 668 * Tags may also be specified with arbitrary objects from code using 669 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 670 * </p> 671 * 672 * <a name="Themes"></a> 673 * <h3>Themes</h3> 674 * <p> 675 * By default, Views are created using the theme of the Context object supplied 676 * to their constructor; however, a different theme may be specified by using 677 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 678 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 679 * code. 680 * </p> 681 * <p> 682 * When the {@link android.R.styleable#View_theme android:theme} attribute is 683 * used in XML, the specified theme is applied on top of the inflation 684 * context's theme (see {@link LayoutInflater}) and used for the view itself as 685 * well as any child elements. 686 * </p> 687 * <p> 688 * In the following example, both views will be created using the Material dark 689 * color scheme; however, because an overlay theme is used which only defines a 690 * subset of attributes, the value of 691 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 692 * the inflation context's theme (e.g. the Activity theme) will be preserved. 693 * <pre> 694 * <LinearLayout 695 * ... 696 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 697 * <View ...> 698 * </LinearLayout> 699 * </pre> 700 * </p> 701 * 702 * <a name="Properties"></a> 703 * <h3>Properties</h3> 704 * <p> 705 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 706 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 707 * available both in the {@link Property} form as well as in similarly-named setter/getter 708 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 709 * be used to set persistent state associated with these rendering-related properties on the view. 710 * The properties and methods can also be used in conjunction with 711 * {@link android.animation.Animator Animator}-based animations, described more in the 712 * <a href="#Animation">Animation</a> section. 713 * </p> 714 * 715 * <a name="Animation"></a> 716 * <h3>Animation</h3> 717 * <p> 718 * Starting with Android 3.0, the preferred way of animating views is to use the 719 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 720 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 721 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 722 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 723 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 724 * makes animating these View properties particularly easy and efficient. 725 * </p> 726 * <p> 727 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 728 * You can attach an {@link Animation} object to a view using 729 * {@link #setAnimation(Animation)} or 730 * {@link #startAnimation(Animation)}. The animation can alter the scale, 731 * rotation, translation and alpha of a view over time. If the animation is 732 * attached to a view that has children, the animation will affect the entire 733 * subtree rooted by that node. When an animation is started, the framework will 734 * take care of redrawing the appropriate views until the animation completes. 735 * </p> 736 * 737 * <a name="Security"></a> 738 * <h3>Security</h3> 739 * <p> 740 * Sometimes it is essential that an application be able to verify that an action 741 * is being performed with the full knowledge and consent of the user, such as 742 * granting a permission request, making a purchase or clicking on an advertisement. 743 * Unfortunately, a malicious application could try to spoof the user into 744 * performing these actions, unaware, by concealing the intended purpose of the view. 745 * As a remedy, the framework offers a touch filtering mechanism that can be used to 746 * improve the security of views that provide access to sensitive functionality. 747 * </p><p> 748 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 749 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 750 * will discard touches that are received whenever the view's window is obscured by 751 * another visible window at the touched location. As a result, the view will not receive touches 752 * whenever the touch passed through a toast, dialog or other window that appears above the view's 753 * window. 754 * </p><p> 755 * For more fine-grained control over security, consider overriding the 756 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 757 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 758 * </p> 759 * 760 * @attr ref android.R.styleable#View_accessibilityHeading 761 * @attr ref android.R.styleable#View_allowClickWhenDisabled 762 * @attr ref android.R.styleable#View_alpha 763 * @attr ref android.R.styleable#View_background 764 * @attr ref android.R.styleable#View_clickable 765 * @attr ref android.R.styleable#View_clipToOutline 766 * @attr ref android.R.styleable#View_contentDescription 767 * @attr ref android.R.styleable#View_drawingCacheQuality 768 * @attr ref android.R.styleable#View_duplicateParentState 769 * @attr ref android.R.styleable#View_id 770 * @attr ref android.R.styleable#View_requiresFadingEdge 771 * @attr ref android.R.styleable#View_fadeScrollbars 772 * @attr ref android.R.styleable#View_fadingEdgeLength 773 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 774 * @attr ref android.R.styleable#View_fitsSystemWindows 775 * @attr ref android.R.styleable#View_isScrollContainer 776 * @attr ref android.R.styleable#View_focusable 777 * @attr ref android.R.styleable#View_focusableInTouchMode 778 * @attr ref android.R.styleable#View_focusedByDefault 779 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 780 * @attr ref android.R.styleable#View_keepScreenOn 781 * @attr ref android.R.styleable#View_keyboardNavigationCluster 782 * @attr ref android.R.styleable#View_layerType 783 * @attr ref android.R.styleable#View_layoutDirection 784 * @attr ref android.R.styleable#View_longClickable 785 * @attr ref android.R.styleable#View_minHeight 786 * @attr ref android.R.styleable#View_minWidth 787 * @attr ref android.R.styleable#View_nextClusterForward 788 * @attr ref android.R.styleable#View_nextFocusDown 789 * @attr ref android.R.styleable#View_nextFocusLeft 790 * @attr ref android.R.styleable#View_nextFocusRight 791 * @attr ref android.R.styleable#View_nextFocusUp 792 * @attr ref android.R.styleable#View_onClick 793 * @attr ref android.R.styleable#View_outlineSpotShadowColor 794 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 795 * @attr ref android.R.styleable#View_padding 796 * @attr ref android.R.styleable#View_paddingHorizontal 797 * @attr ref android.R.styleable#View_paddingVertical 798 * @attr ref android.R.styleable#View_paddingBottom 799 * @attr ref android.R.styleable#View_paddingLeft 800 * @attr ref android.R.styleable#View_paddingRight 801 * @attr ref android.R.styleable#View_paddingTop 802 * @attr ref android.R.styleable#View_paddingStart 803 * @attr ref android.R.styleable#View_paddingEnd 804 * @attr ref android.R.styleable#View_saveEnabled 805 * @attr ref android.R.styleable#View_rotation 806 * @attr ref android.R.styleable#View_rotationX 807 * @attr ref android.R.styleable#View_rotationY 808 * @attr ref android.R.styleable#View_scaleX 809 * @attr ref android.R.styleable#View_scaleY 810 * @attr ref android.R.styleable#View_scrollX 811 * @attr ref android.R.styleable#View_scrollY 812 * @attr ref android.R.styleable#View_scrollbarSize 813 * @attr ref android.R.styleable#View_scrollbarStyle 814 * @attr ref android.R.styleable#View_scrollbars 815 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 816 * @attr ref android.R.styleable#View_scrollbarFadeDuration 817 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 818 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 819 * @attr ref android.R.styleable#View_scrollbarThumbVertical 820 * @attr ref android.R.styleable#View_scrollbarTrackVertical 821 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 822 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 823 * @attr ref android.R.styleable#View_stateListAnimator 824 * @attr ref android.R.styleable#View_transitionName 825 * @attr ref android.R.styleable#View_soundEffectsEnabled 826 * @attr ref android.R.styleable#View_tag 827 * @attr ref android.R.styleable#View_textAlignment 828 * @attr ref android.R.styleable#View_textDirection 829 * @attr ref android.R.styleable#View_transformPivotX 830 * @attr ref android.R.styleable#View_transformPivotY 831 * @attr ref android.R.styleable#View_translationX 832 * @attr ref android.R.styleable#View_translationY 833 * @attr ref android.R.styleable#View_translationZ 834 * @attr ref android.R.styleable#View_visibility 835 * @attr ref android.R.styleable#View_theme 836 * 837 * @see android.view.ViewGroup 838 */ 839 @UiThread 840 public class View implements Drawable.Callback, KeyEvent.Callback, 841 AccessibilityEventSource { 842 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 843 private static final boolean DBG = false; 844 845 /** @hide */ 846 public static boolean DEBUG_DRAW = false; 847 848 /** 849 * The logging tag used by this class with android.util.Log. 850 */ 851 protected static final String VIEW_LOG_TAG = "View"; 852 853 /** 854 * The logging tag used by this class when logging verbose, autofill-related messages. 855 */ 856 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 857 // set if a session is not started. 858 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 859 860 /** 861 * The logging tag used by this class when logging content capture-related messages. 862 */ 863 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 864 865 private static final boolean DEBUG_CONTENT_CAPTURE = false; 866 867 /** 868 * When set to true, this view will save its attribute data. 869 * 870 * @hide 871 */ 872 public static boolean sDebugViewAttributes = false; 873 874 /** 875 * When set to this application package view will save its attribute data. 876 * 877 * @hide 878 */ 879 public static String sDebugViewAttributesApplicationPackage; 880 881 /** 882 * Used to mark a View that has no ID. 883 */ 884 public static final int NO_ID = -1; 885 886 /** 887 * Last ID that is given to Views that are no part of activities. 888 * 889 * {@hide} 890 */ 891 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 892 893 /** 894 * Attribute to find the autofilled highlight 895 * 896 * @see #getAutofilledDrawable() 897 */ 898 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 899 new int[]{android.R.attr.autofilledHighlight}; 900 901 /** 902 * Signals that compatibility booleans have been initialized according to 903 * target SDK versions. 904 */ 905 private static boolean sCompatibilityDone = false; 906 907 /** 908 * Use the old (broken) way of building MeasureSpecs. 909 */ 910 private static boolean sUseBrokenMakeMeasureSpec = false; 911 912 /** 913 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 914 */ 915 static boolean sUseZeroUnspecifiedMeasureSpec = false; 916 917 /** 918 * Ignore any optimizations using the measure cache. 919 */ 920 private static boolean sIgnoreMeasureCache = false; 921 922 /** 923 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 924 */ 925 private static boolean sAlwaysRemeasureExactly = false; 926 927 /** 928 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 929 * without throwing 930 */ 931 static boolean sTextureViewIgnoresDrawableSetters = false; 932 933 /** 934 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 935 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 936 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 937 * check is implemented for backwards compatibility. 938 * 939 * {@hide} 940 */ 941 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 942 943 /** 944 * Prior to N, when drag enters into child of a view that has already received an 945 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 946 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 947 * false from its event handler for these events. 948 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 949 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 950 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 951 */ 952 static boolean sCascadedDragDrop; 953 954 /** 955 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 956 * to determine things like whether or not to permit item click events. We can't break 957 * apps that do this just because more things (clickable things) are now auto-focusable 958 * and they would get different results, so give old behavior to old apps. 959 */ 960 static boolean sHasFocusableExcludeAutoFocusable; 961 962 /** 963 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 964 * made focusable by default. As a result, apps could (incorrectly) change the clickable 965 * setting of views off the UI thread. Now that clickable can effect the focusable state, 966 * changing the clickable attribute off the UI thread will cause an exception (since changing 967 * the focusable state checks). In order to prevent apps from crashing, we will handle this 968 * specific case and just not notify parents on new focusables resulting from marking views 969 * clickable from outside the UI thread. 970 */ 971 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 972 973 /** 974 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 975 * Float.NaN. If the app is targetting P or later then passing these values will result in an 976 * exception being thrown. If the app is targetting an earlier SDK version, then we will 977 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 978 * these bogus values. 979 */ 980 private static boolean sThrowOnInvalidFloatProperties; 981 982 /** 983 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 984 * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead. 985 */ 986 private static boolean sAcceptZeroSizeDragShadow; 987 988 /** 989 * When true, measure and layout passes of all the newly attached views will be logged with 990 * {@link Trace}, so we can better debug jank due to complex view hierarchies. 991 */ 992 private static boolean sTraceLayoutSteps; 993 994 /** 995 * When not null, emits a {@link Trace} instant event and the stacktrace every time a relayout 996 * of a class having this name happens. 997 */ 998 private static String sTraceRequestLayoutClass; 999 1000 /** Used to avoid computing the full strings each time when layout tracing is enabled. */ 1001 @Nullable 1002 private ViewTraversalTracingStrings mTracingStrings; 1003 1004 /** 1005 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 1006 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 1007 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 1008 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 1009 * thus, the hierarchical dispatching mechanism was hard to use for apps. 1010 * <p> 1011 * In order to make window inset dispatching work properly, we dispatch window insets 1012 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 1013 */ 1014 static boolean sBrokenInsetsDispatch; 1015 1016 /** 1017 * Prior to Q, calling 1018 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 1019 * did not call update the window format so the opacity of the background was not correctly 1020 * applied to the window. Some applications rely on this misbehavior to work properly. 1021 * <p> 1022 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 1023 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 1024 * which updates the window format. 1025 * @hide 1026 */ 1027 protected static boolean sBrokenWindowBackground; 1028 1029 /** 1030 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 1031 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 1032 * calling {@link #requestLayout} when they need to relayout based on an insets change. 1033 */ 1034 static boolean sForceLayoutWhenInsetsChanged; 1035 1036 /** @hide */ 1037 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 1038 @Retention(RetentionPolicy.SOURCE) 1039 public @interface Focusable {} 1040 1041 /** 1042 * This view does not want keystrokes. 1043 * <p> 1044 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1045 * android:focusable}. 1046 */ 1047 public static final int NOT_FOCUSABLE = 0x00000000; 1048 1049 /** 1050 * This view wants keystrokes. 1051 * <p> 1052 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1053 * android:focusable}. 1054 */ 1055 public static final int FOCUSABLE = 0x00000001; 1056 1057 /** 1058 * This view determines focusability automatically. This is the default. 1059 * <p> 1060 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1061 * android:focusable}. 1062 */ 1063 public static final int FOCUSABLE_AUTO = 0x00000010; 1064 1065 /** 1066 * Mask for use with setFlags indicating bits used for focus. 1067 */ 1068 private static final int FOCUSABLE_MASK = 0x00000011; 1069 1070 /** 1071 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1072 */ 1073 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1074 1075 /** @hide */ 1076 @IntDef({VISIBLE, INVISIBLE, GONE}) 1077 @Retention(RetentionPolicy.SOURCE) 1078 public @interface Visibility {} 1079 1080 /** 1081 * This view is visible. 1082 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1083 * android:visibility}. 1084 */ 1085 public static final int VISIBLE = 0x00000000; 1086 1087 /** 1088 * This view is invisible, but it still takes up space for layout purposes. 1089 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1090 * android:visibility}. 1091 */ 1092 public static final int INVISIBLE = 0x00000004; 1093 1094 /** 1095 * This view is invisible, and it doesn't take any space for layout 1096 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1097 * android:visibility}. 1098 */ 1099 public static final int GONE = 0x00000008; 1100 1101 /** 1102 * Mask for use with setFlags indicating bits used for visibility. 1103 * {@hide} 1104 */ 1105 static final int VISIBILITY_MASK = 0x0000000C; 1106 1107 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1108 1109 /** 1110 * Hint indicating that this view can be autofilled with an email address. 1111 * 1112 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1113 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1114 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1115 * 1116 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1117 */ 1118 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1119 1120 /** 1121 * Hint indicating that this view can be autofilled with a user's real name. 1122 * 1123 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1124 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1125 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1126 * 1127 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1128 */ 1129 public static final String AUTOFILL_HINT_NAME = "name"; 1130 1131 /** 1132 * Hint indicating that this view can be autofilled with a username. 1133 * 1134 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1135 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1136 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1137 * 1138 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1139 */ 1140 public static final String AUTOFILL_HINT_USERNAME = "username"; 1141 1142 /** 1143 * Hint indicating that this view can be autofilled with a password. 1144 * 1145 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1146 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1147 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1148 * 1149 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1150 */ 1151 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1152 1153 /** 1154 * Hint indicating that this view can be autofilled with a phone number. 1155 * 1156 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1157 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1158 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1159 * 1160 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1161 */ 1162 public static final String AUTOFILL_HINT_PHONE = "phone"; 1163 1164 /** 1165 * Hint indicating that this view can be autofilled with a postal address. 1166 * 1167 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1168 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1169 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1170 * 1171 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1172 */ 1173 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1174 1175 /** 1176 * Hint indicating that this view can be autofilled with a postal code. 1177 * 1178 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1179 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1180 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1181 * 1182 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1183 */ 1184 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1185 1186 /** 1187 * Hint indicating that this view can be autofilled with a credit card number. 1188 * 1189 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1190 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1191 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1192 * 1193 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1194 */ 1195 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1196 1197 /** 1198 * Hint indicating that this view can be autofilled with a credit card security code. 1199 * 1200 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1201 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1202 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1203 * 1204 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1205 */ 1206 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1207 1208 /** 1209 * Hint indicating that this view can be autofilled with a credit card expiration date. 1210 * 1211 * <p>It should be used when the credit card expiration date is represented by just one view; 1212 * if it is represented by more than one (for example, one view for the month and another view 1213 * for the year), then each of these views should use the hint specific for the unit 1214 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1215 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1216 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1217 * 1218 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1219 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1220 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1221 * 1222 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1223 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1224 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1225 * the following options: 1226 * 1227 * <ul> 1228 * <li>{@code "04/2020"} 1229 * <li>{@code "4/2020"} 1230 * <li>{@code "2020/04"} 1231 * <li>{@code "2020/4"} 1232 * <li>{@code "April/2020"} 1233 * <li>{@code "Apr/2020"} 1234 * </ul> 1235 * 1236 * <p>You define a date autofill value for the view by overriding the following methods: 1237 * 1238 * <ol> 1239 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1240 * <li>{@link #getAutofillValue()} to return a 1241 * {@link AutofillValue#forDate(long) date autofillvalue}. 1242 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1243 * </ol> 1244 * 1245 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1246 */ 1247 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1248 "creditCardExpirationDate"; 1249 1250 /** 1251 * Hint indicating that this view can be autofilled with a credit card expiration month. 1252 * 1253 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1254 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1255 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1256 * 1257 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1258 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1259 * ambiguity when the autofill service provides a value for it. To understand why a 1260 * value can be ambiguous, consider "January", which could be represented as either of 1261 * 1262 * <ul> 1263 * <li>{@code "1"}: recommended way. 1264 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1265 * <li>{@code "January"}: full name, in English. 1266 * <li>{@code "jan"}: abbreviated name, in English. 1267 * <li>{@code "Janeiro"}: full name, in another language. 1268 * </ul> 1269 * 1270 * <p>Another recommended approach is to use a date autofill value - see 1271 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1272 * 1273 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1274 */ 1275 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1276 "creditCardExpirationMonth"; 1277 1278 /** 1279 * Hint indicating that this view can be autofilled with a credit card expiration year. 1280 * 1281 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1282 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1283 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1284 * 1285 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1286 */ 1287 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1288 "creditCardExpirationYear"; 1289 1290 /** 1291 * Hint indicating that this view can be autofilled with a credit card expiration day. 1292 * 1293 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1294 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1295 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1296 * 1297 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1298 */ 1299 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1300 1301 /** 1302 * A hint indicating that this view can be autofilled with a password. 1303 * 1304 * This is a heuristic-based hint that is meant to be used by UI Toolkit developers when a 1305 * view is a password field but doesn't specify a 1306 * <code>{@value View#AUTOFILL_HINT_PASSWORD}</code>. 1307 * @hide 1308 */ 1309 // TODO(229765029): unhide this for UI toolkit 1310 public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto"; 1311 1312 /** 1313 * Hints for the autofill services that describes the content of the view. 1314 */ 1315 private @Nullable String[] mAutofillHints; 1316 1317 /** 1318 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1319 */ 1320 private AutofillId mAutofillId; 1321 1322 /** @hide */ 1323 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1324 AUTOFILL_TYPE_NONE, 1325 AUTOFILL_TYPE_TEXT, 1326 AUTOFILL_TYPE_TOGGLE, 1327 AUTOFILL_TYPE_LIST, 1328 AUTOFILL_TYPE_DATE, 1329 }) 1330 @Retention(RetentionPolicy.SOURCE) 1331 public @interface AutofillType {} 1332 1333 /** 1334 * Autofill type for views that cannot be autofilled. 1335 * 1336 * <p>Typically used when the view is read-only; for example, a text label. 1337 * 1338 * @see #getAutofillType() 1339 */ 1340 public static final int AUTOFILL_TYPE_NONE = 0; 1341 1342 /** 1343 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1344 * 1345 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1346 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1347 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1348 * 1349 * @see #getAutofillType() 1350 */ 1351 public static final int AUTOFILL_TYPE_TEXT = 1; 1352 1353 /** 1354 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1355 * 1356 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1357 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1358 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1359 * 1360 * @see #getAutofillType() 1361 */ 1362 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1363 1364 /** 1365 * Autofill type for a selection list field, which is filled by an {@code int} 1366 * representing the element index inside the list (starting at {@code 0}). 1367 * 1368 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1369 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1370 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1371 * 1372 * <p>The available options in the selection list are typically provided by 1373 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1374 * 1375 * @see #getAutofillType() 1376 */ 1377 public static final int AUTOFILL_TYPE_LIST = 3; 1378 1379 /** 1380 * Autofill type for a field that contains a date, which is represented by a long representing 1381 * the number of milliseconds since the standard base time known as "the epoch", namely 1382 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1383 * 1384 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1385 * {@link AutofillValue#forDate(long)}, and the values passed to 1386 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1387 * 1388 * @see #getAutofillType() 1389 */ 1390 public static final int AUTOFILL_TYPE_DATE = 4; 1391 1392 1393 /** @hide */ 1394 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1395 IMPORTANT_FOR_AUTOFILL_AUTO, 1396 IMPORTANT_FOR_AUTOFILL_YES, 1397 IMPORTANT_FOR_AUTOFILL_NO, 1398 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1399 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1400 }) 1401 @Retention(RetentionPolicy.SOURCE) 1402 public @interface AutofillImportance {} 1403 1404 /** 1405 * Automatically determine whether a view is important for autofill. 1406 * 1407 * @see #isImportantForAutofill() 1408 * @see #setImportantForAutofill(int) 1409 */ 1410 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1411 1412 /** 1413 * The view is important for autofill, and its children (if any) will be traversed. 1414 * 1415 * @see #isImportantForAutofill() 1416 * @see #setImportantForAutofill(int) 1417 */ 1418 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1419 1420 /** 1421 * The view is not important for autofill, but its children (if any) will be traversed. 1422 * 1423 * @see #isImportantForAutofill() 1424 * @see #setImportantForAutofill(int) 1425 */ 1426 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1427 1428 /** 1429 * The view is important for autofill, but its children (if any) will not be traversed. 1430 * 1431 * @see #isImportantForAutofill() 1432 * @see #setImportantForAutofill(int) 1433 */ 1434 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1435 1436 /** 1437 * The view is not important for autofill, and its children (if any) will not be traversed. 1438 * 1439 * @see #isImportantForAutofill() 1440 * @see #setImportantForAutofill(int) 1441 */ 1442 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1443 1444 /** @hide */ 1445 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1446 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1447 }) 1448 @Retention(RetentionPolicy.SOURCE) 1449 public @interface AutofillFlags {} 1450 1451 /** 1452 * Flag requesting you to add views that are marked as not important for autofill 1453 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1454 */ 1455 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1456 1457 /** @hide */ 1458 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1459 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1460 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1461 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1462 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1463 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1464 }) 1465 @Retention(RetentionPolicy.SOURCE) 1466 public @interface ContentCaptureImportance {} 1467 1468 /** 1469 * Automatically determine whether a view is important for content capture. 1470 * 1471 * @see #isImportantForContentCapture() 1472 * @see #setImportantForContentCapture(int) 1473 */ 1474 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1475 1476 /** 1477 * The view is important for content capture, and its children (if any) will be traversed. 1478 * 1479 * @see #isImportantForContentCapture() 1480 * @see #setImportantForContentCapture(int) 1481 */ 1482 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1483 1484 /** 1485 * The view is not important for content capture, but its children (if any) will be traversed. 1486 * 1487 * @see #isImportantForContentCapture() 1488 * @see #setImportantForContentCapture(int) 1489 */ 1490 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1491 1492 /** 1493 * The view is important for content capture, but its children (if any) will not be traversed. 1494 * 1495 * @see #isImportantForContentCapture() 1496 * @see #setImportantForContentCapture(int) 1497 */ 1498 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1499 1500 /** 1501 * The view is not important for content capture, and its children (if any) will not be 1502 * traversed. 1503 * 1504 * @see #isImportantForContentCapture() 1505 * @see #setImportantForContentCapture(int) 1506 */ 1507 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1508 1509 /** {@hide} */ 1510 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1511 value = { 1512 SCROLL_CAPTURE_HINT_AUTO, 1513 SCROLL_CAPTURE_HINT_EXCLUDE, 1514 SCROLL_CAPTURE_HINT_INCLUDE, 1515 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1516 }) 1517 @Retention(RetentionPolicy.SOURCE) 1518 public @interface ScrollCaptureHint {} 1519 1520 /** 1521 * The content of this view will be considered for scroll capture if scrolling is possible. 1522 * 1523 * @see #getScrollCaptureHint() 1524 * @see #setScrollCaptureHint(int) 1525 */ 1526 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1527 1528 /** 1529 * Explicitly exclude this view as a potential scroll capture target. The system will not 1530 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1531 * takes precedence over. 1532 * 1533 * @see #getScrollCaptureHint() 1534 * @see #setScrollCaptureHint(int) 1535 */ 1536 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1537 1538 /** 1539 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1540 * capture target, this view will be prioritized before others without this flag. Mutually 1541 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1542 * 1543 * @see #getScrollCaptureHint() 1544 * @see #setScrollCaptureHint(int) 1545 */ 1546 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1547 1548 /** 1549 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1550 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1551 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1552 * 1553 * @see #getScrollCaptureHint() 1554 * @see #setScrollCaptureHint(int) 1555 */ 1556 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1557 1558 /** 1559 * This view is enabled. Interpretation varies by subclass. 1560 * Use with ENABLED_MASK when calling setFlags. 1561 * {@hide} 1562 */ 1563 static final int ENABLED = 0x00000000; 1564 1565 /** 1566 * This view is disabled. Interpretation varies by subclass. 1567 * Use with ENABLED_MASK when calling setFlags. 1568 * {@hide} 1569 */ 1570 static final int DISABLED = 0x00000020; 1571 1572 /** 1573 * Mask for use with setFlags indicating bits used for indicating whether 1574 * this view is enabled 1575 * {@hide} 1576 */ 1577 static final int ENABLED_MASK = 0x00000020; 1578 1579 /** 1580 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1581 * called and further optimizations will be performed. It is okay to have 1582 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1583 * {@hide} 1584 */ 1585 static final int WILL_NOT_DRAW = 0x00000080; 1586 1587 /** 1588 * Mask for use with setFlags indicating bits used for indicating whether 1589 * this view is will draw 1590 * {@hide} 1591 */ 1592 static final int DRAW_MASK = 0x00000080; 1593 1594 /** 1595 * <p>This view doesn't show scrollbars.</p> 1596 * {@hide} 1597 */ 1598 static final int SCROLLBARS_NONE = 0x00000000; 1599 1600 /** 1601 * <p>This view shows horizontal scrollbars.</p> 1602 * {@hide} 1603 */ 1604 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1605 1606 /** 1607 * <p>This view shows vertical scrollbars.</p> 1608 * {@hide} 1609 */ 1610 static final int SCROLLBARS_VERTICAL = 0x00000200; 1611 1612 /** 1613 * <p>Mask for use with setFlags indicating bits used for indicating which 1614 * scrollbars are enabled.</p> 1615 * {@hide} 1616 */ 1617 static final int SCROLLBARS_MASK = 0x00000300; 1618 1619 /** 1620 * Indicates that the view should filter touches when its window is obscured. 1621 * Refer to the class comments for more information about this security feature. 1622 * {@hide} 1623 */ 1624 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1625 1626 /** 1627 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1628 * that they are optional and should be skipped if the window has 1629 * requested system UI flags that ignore those insets for layout. 1630 * <p> 1631 * This is only used for support library as of Android R. The framework now uses 1632 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1633 * insets path that loses insets information. 1634 */ 1635 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1636 1637 /** 1638 * <p>This view doesn't show fading edges.</p> 1639 * {@hide} 1640 */ 1641 static final int FADING_EDGE_NONE = 0x00000000; 1642 1643 /** 1644 * <p>This view shows horizontal fading edges.</p> 1645 * {@hide} 1646 */ 1647 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1648 1649 /** 1650 * <p>This view shows vertical fading edges.</p> 1651 * {@hide} 1652 */ 1653 static final int FADING_EDGE_VERTICAL = 0x00002000; 1654 1655 /** 1656 * <p>Mask for use with setFlags indicating bits used for indicating which 1657 * fading edges are enabled.</p> 1658 * {@hide} 1659 */ 1660 static final int FADING_EDGE_MASK = 0x00003000; 1661 1662 /** 1663 * <p>Indicates this view can be clicked. When clickable, a View reacts 1664 * to clicks by notifying the OnClickListener.<p> 1665 * {@hide} 1666 */ 1667 static final int CLICKABLE = 0x00004000; 1668 1669 /** 1670 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1671 * {@hide} 1672 */ 1673 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1674 1675 /** 1676 * <p>Indicates that no icicle should be saved for this view.<p> 1677 * {@hide} 1678 */ 1679 static final int SAVE_DISABLED = 0x000010000; 1680 1681 /** 1682 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1683 * property.</p> 1684 * {@hide} 1685 */ 1686 static final int SAVE_DISABLED_MASK = 0x000010000; 1687 1688 /** 1689 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1690 * {@hide} 1691 */ 1692 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1693 1694 /** 1695 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1696 * {@hide} 1697 */ 1698 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1699 1700 /** @hide */ 1701 @Retention(RetentionPolicy.SOURCE) 1702 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1703 DRAWING_CACHE_QUALITY_LOW, 1704 DRAWING_CACHE_QUALITY_HIGH, 1705 DRAWING_CACHE_QUALITY_AUTO 1706 }) 1707 public @interface DrawingCacheQuality {} 1708 1709 /** 1710 * <p>Enables low quality mode for the drawing cache.</p> 1711 * 1712 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1713 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1714 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1715 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1716 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1717 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1718 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1719 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1720 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1721 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1722 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1723 * reports or unit testing the {@link PixelCopy} API is recommended. 1724 */ 1725 @Deprecated 1726 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1727 1728 /** 1729 * <p>Enables high quality mode for the drawing cache.</p> 1730 * 1731 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1732 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1733 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1734 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1735 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1736 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1737 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1738 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1739 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1740 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1741 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1742 * reports or unit testing the {@link PixelCopy} API is recommended. 1743 */ 1744 @Deprecated 1745 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1746 1747 /** 1748 * <p>Enables automatic quality mode for the drawing cache.</p> 1749 * 1750 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1751 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1752 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1753 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1754 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1755 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1756 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1757 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1758 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1759 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1760 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1761 * reports or unit testing the {@link PixelCopy} API is recommended. 1762 */ 1763 @Deprecated 1764 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1765 1766 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1767 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1768 }; 1769 1770 /** 1771 * <p>Mask for use with setFlags indicating bits used for the cache 1772 * quality property.</p> 1773 * {@hide} 1774 */ 1775 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1776 1777 /** 1778 * <p> 1779 * Indicates this view can be long clicked. When long clickable, a View 1780 * reacts to long clicks by notifying the OnLongClickListener or showing a 1781 * context menu. 1782 * </p> 1783 * {@hide} 1784 */ 1785 static final int LONG_CLICKABLE = 0x00200000; 1786 1787 /** 1788 * <p>Indicates that this view gets its drawable states from its direct parent 1789 * and ignores its original internal states.</p> 1790 * 1791 * @hide 1792 */ 1793 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1794 1795 /** 1796 * <p> 1797 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1798 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1799 * OnContextClickListener. 1800 * </p> 1801 * {@hide} 1802 */ 1803 static final int CONTEXT_CLICKABLE = 0x00800000; 1804 1805 /** @hide */ 1806 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1807 SCROLLBARS_INSIDE_OVERLAY, 1808 SCROLLBARS_INSIDE_INSET, 1809 SCROLLBARS_OUTSIDE_OVERLAY, 1810 SCROLLBARS_OUTSIDE_INSET 1811 }) 1812 @Retention(RetentionPolicy.SOURCE) 1813 public @interface ScrollBarStyle {} 1814 1815 /** 1816 * The scrollbar style to display the scrollbars inside the content area, 1817 * without increasing the padding. The scrollbars will be overlaid with 1818 * translucency on the view's content. 1819 */ 1820 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1821 1822 /** 1823 * The scrollbar style to display the scrollbars inside the padded area, 1824 * increasing the padding of the view. The scrollbars will not overlap the 1825 * content area of the view. 1826 */ 1827 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1828 1829 /** 1830 * The scrollbar style to display the scrollbars at the edge of the view, 1831 * without increasing the padding. The scrollbars will be overlaid with 1832 * translucency. 1833 */ 1834 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1835 1836 /** 1837 * The scrollbar style to display the scrollbars at the edge of the view, 1838 * increasing the padding of the view. The scrollbars will only overlap the 1839 * background, if any. 1840 */ 1841 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1842 1843 /** 1844 * Mask to check if the scrollbar style is overlay or inset. 1845 * {@hide} 1846 */ 1847 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1848 1849 /** 1850 * Mask to check if the scrollbar style is inside or outside. 1851 * {@hide} 1852 */ 1853 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1854 1855 /** 1856 * Mask for scrollbar style. 1857 * {@hide} 1858 */ 1859 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1860 1861 /** 1862 * View flag indicating that the screen should remain on while the 1863 * window containing this view is visible to the user. This effectively 1864 * takes care of automatically setting the WindowManager's 1865 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1866 */ 1867 public static final int KEEP_SCREEN_ON = 0x04000000; 1868 1869 /** 1870 * View flag indicating whether this view should have sound effects enabled 1871 * for events such as clicking and touching. 1872 */ 1873 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1874 1875 /** 1876 * View flag indicating whether this view should have haptic feedback 1877 * enabled for events such as long presses. 1878 */ 1879 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1880 1881 /** 1882 * <p>Indicates that the view hierarchy should stop saving state when 1883 * it reaches this view. If state saving is initiated immediately at 1884 * the view, it will be allowed. 1885 * {@hide} 1886 */ 1887 static final int PARENT_SAVE_DISABLED = 0x20000000; 1888 1889 /** 1890 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1891 * {@hide} 1892 */ 1893 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1894 1895 private static Paint sDebugPaint; 1896 1897 /** 1898 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1899 * {@hide} 1900 */ 1901 static final int TOOLTIP = 0x40000000; 1902 1903 /** @hide */ 1904 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1905 FOCUSABLES_ALL, 1906 FOCUSABLES_TOUCH_MODE 1907 }) 1908 @Retention(RetentionPolicy.SOURCE) 1909 public @interface FocusableMode {} 1910 1911 /** 1912 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1913 * should add all focusable Views regardless if they are focusable in touch mode. 1914 */ 1915 public static final int FOCUSABLES_ALL = 0x00000000; 1916 1917 /** 1918 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1919 * should add only Views focusable in touch mode. 1920 */ 1921 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1922 1923 /** @hide */ 1924 @IntDef(prefix = { "FOCUS_" }, value = { 1925 FOCUS_BACKWARD, 1926 FOCUS_FORWARD, 1927 FOCUS_LEFT, 1928 FOCUS_UP, 1929 FOCUS_RIGHT, 1930 FOCUS_DOWN 1931 }) 1932 @Retention(RetentionPolicy.SOURCE) 1933 public @interface FocusDirection {} 1934 1935 /** @hide */ 1936 @IntDef(prefix = { "FOCUS_" }, value = { 1937 FOCUS_LEFT, 1938 FOCUS_UP, 1939 FOCUS_RIGHT, 1940 FOCUS_DOWN 1941 }) 1942 @Retention(RetentionPolicy.SOURCE) 1943 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1944 1945 /** 1946 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1947 * item. 1948 */ 1949 public static final int FOCUS_BACKWARD = 0x00000001; 1950 1951 /** 1952 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1953 * item. 1954 */ 1955 public static final int FOCUS_FORWARD = 0x00000002; 1956 1957 /** 1958 * Use with {@link #focusSearch(int)}. Move focus to the left. 1959 */ 1960 public static final int FOCUS_LEFT = 0x00000011; 1961 1962 /** 1963 * Use with {@link #focusSearch(int)}. Move focus up. 1964 */ 1965 public static final int FOCUS_UP = 0x00000021; 1966 1967 /** 1968 * Use with {@link #focusSearch(int)}. Move focus to the right. 1969 */ 1970 public static final int FOCUS_RIGHT = 0x00000042; 1971 1972 /** 1973 * Use with {@link #focusSearch(int)}. Move focus down. 1974 */ 1975 public static final int FOCUS_DOWN = 0x00000082; 1976 1977 /** 1978 * Bits of {@link #getMeasuredWidthAndState()} and 1979 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1980 */ 1981 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1982 1983 /** 1984 * Bits of {@link #getMeasuredWidthAndState()} and 1985 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1986 */ 1987 public static final int MEASURED_STATE_MASK = 0xff000000; 1988 1989 /** 1990 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1991 * for functions that combine both width and height into a single int, 1992 * such as {@link #getMeasuredState()} and the childState argument of 1993 * {@link #resolveSizeAndState(int, int, int)}. 1994 */ 1995 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1996 1997 /** 1998 * Bit of {@link #getMeasuredWidthAndState()} and 1999 * {@link #getMeasuredWidthAndState()} that indicates the measured size 2000 * is smaller that the space the view would like to have. 2001 */ 2002 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 2003 2004 /** 2005 * Base View state sets 2006 */ 2007 // Singles 2008 /** 2009 * Indicates the view has no states set. States are used with 2010 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2011 * view depending on its state. 2012 * 2013 * @see android.graphics.drawable.Drawable 2014 * @see #getDrawableState() 2015 */ 2016 protected static final int[] EMPTY_STATE_SET; 2017 /** 2018 * Indicates the view is enabled. States are used with 2019 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2020 * view depending on its state. 2021 * 2022 * @see android.graphics.drawable.Drawable 2023 * @see #getDrawableState() 2024 */ 2025 protected static final int[] ENABLED_STATE_SET; 2026 /** 2027 * Indicates the view is focused. States are used with 2028 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2029 * view depending on its state. 2030 * 2031 * @see android.graphics.drawable.Drawable 2032 * @see #getDrawableState() 2033 */ 2034 protected static final int[] FOCUSED_STATE_SET; 2035 /** 2036 * Indicates the view is selected. States are used with 2037 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2038 * view depending on its state. 2039 * 2040 * @see android.graphics.drawable.Drawable 2041 * @see #getDrawableState() 2042 */ 2043 protected static final int[] SELECTED_STATE_SET; 2044 /** 2045 * Indicates the view is pressed. States are used with 2046 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2047 * view depending on its state. 2048 * 2049 * @see android.graphics.drawable.Drawable 2050 * @see #getDrawableState() 2051 */ 2052 protected static final int[] PRESSED_STATE_SET; 2053 /** 2054 * Indicates the view's window has focus. States are used with 2055 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2056 * view depending on its state. 2057 * 2058 * @see android.graphics.drawable.Drawable 2059 * @see #getDrawableState() 2060 */ 2061 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2062 // Doubles 2063 /** 2064 * Indicates the view is enabled and has the focus. 2065 * 2066 * @see #ENABLED_STATE_SET 2067 * @see #FOCUSED_STATE_SET 2068 */ 2069 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2070 /** 2071 * Indicates the view is enabled and selected. 2072 * 2073 * @see #ENABLED_STATE_SET 2074 * @see #SELECTED_STATE_SET 2075 */ 2076 protected static final int[] ENABLED_SELECTED_STATE_SET; 2077 /** 2078 * Indicates the view is enabled and that its window has focus. 2079 * 2080 * @see #ENABLED_STATE_SET 2081 * @see #WINDOW_FOCUSED_STATE_SET 2082 */ 2083 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2084 /** 2085 * Indicates the view is focused and selected. 2086 * 2087 * @see #FOCUSED_STATE_SET 2088 * @see #SELECTED_STATE_SET 2089 */ 2090 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2091 /** 2092 * Indicates the view has the focus and that its window has the focus. 2093 * 2094 * @see #FOCUSED_STATE_SET 2095 * @see #WINDOW_FOCUSED_STATE_SET 2096 */ 2097 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2098 /** 2099 * Indicates the view is selected and that its window has the focus. 2100 * 2101 * @see #SELECTED_STATE_SET 2102 * @see #WINDOW_FOCUSED_STATE_SET 2103 */ 2104 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2105 // Triples 2106 /** 2107 * Indicates the view is enabled, focused and selected. 2108 * 2109 * @see #ENABLED_STATE_SET 2110 * @see #FOCUSED_STATE_SET 2111 * @see #SELECTED_STATE_SET 2112 */ 2113 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2114 /** 2115 * Indicates the view is enabled, focused and its window has the focus. 2116 * 2117 * @see #ENABLED_STATE_SET 2118 * @see #FOCUSED_STATE_SET 2119 * @see #WINDOW_FOCUSED_STATE_SET 2120 */ 2121 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2122 /** 2123 * Indicates the view is enabled, selected and its window has the focus. 2124 * 2125 * @see #ENABLED_STATE_SET 2126 * @see #SELECTED_STATE_SET 2127 * @see #WINDOW_FOCUSED_STATE_SET 2128 */ 2129 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2130 /** 2131 * Indicates the view is focused, selected and its window has the focus. 2132 * 2133 * @see #FOCUSED_STATE_SET 2134 * @see #SELECTED_STATE_SET 2135 * @see #WINDOW_FOCUSED_STATE_SET 2136 */ 2137 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2138 /** 2139 * Indicates the view is enabled, focused, selected and its window 2140 * has the focus. 2141 * 2142 * @see #ENABLED_STATE_SET 2143 * @see #FOCUSED_STATE_SET 2144 * @see #SELECTED_STATE_SET 2145 * @see #WINDOW_FOCUSED_STATE_SET 2146 */ 2147 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2148 /** 2149 * Indicates the view is pressed and its window has the focus. 2150 * 2151 * @see #PRESSED_STATE_SET 2152 * @see #WINDOW_FOCUSED_STATE_SET 2153 */ 2154 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2155 /** 2156 * Indicates the view is pressed and selected. 2157 * 2158 * @see #PRESSED_STATE_SET 2159 * @see #SELECTED_STATE_SET 2160 */ 2161 protected static final int[] PRESSED_SELECTED_STATE_SET; 2162 /** 2163 * Indicates the view is pressed, selected and its window has the focus. 2164 * 2165 * @see #PRESSED_STATE_SET 2166 * @see #SELECTED_STATE_SET 2167 * @see #WINDOW_FOCUSED_STATE_SET 2168 */ 2169 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2170 /** 2171 * Indicates the view is pressed and focused. 2172 * 2173 * @see #PRESSED_STATE_SET 2174 * @see #FOCUSED_STATE_SET 2175 */ 2176 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2177 /** 2178 * Indicates the view is pressed, focused and its window has the focus. 2179 * 2180 * @see #PRESSED_STATE_SET 2181 * @see #FOCUSED_STATE_SET 2182 * @see #WINDOW_FOCUSED_STATE_SET 2183 */ 2184 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2185 /** 2186 * Indicates the view is pressed, focused and selected. 2187 * 2188 * @see #PRESSED_STATE_SET 2189 * @see #SELECTED_STATE_SET 2190 * @see #FOCUSED_STATE_SET 2191 */ 2192 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2193 /** 2194 * Indicates the view is pressed, focused, selected and its window has the focus. 2195 * 2196 * @see #PRESSED_STATE_SET 2197 * @see #FOCUSED_STATE_SET 2198 * @see #SELECTED_STATE_SET 2199 * @see #WINDOW_FOCUSED_STATE_SET 2200 */ 2201 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2202 /** 2203 * Indicates the view is pressed and enabled. 2204 * 2205 * @see #PRESSED_STATE_SET 2206 * @see #ENABLED_STATE_SET 2207 */ 2208 protected static final int[] PRESSED_ENABLED_STATE_SET; 2209 /** 2210 * Indicates the view is pressed, enabled and its window has the focus. 2211 * 2212 * @see #PRESSED_STATE_SET 2213 * @see #ENABLED_STATE_SET 2214 * @see #WINDOW_FOCUSED_STATE_SET 2215 */ 2216 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2217 /** 2218 * Indicates the view is pressed, enabled and selected. 2219 * 2220 * @see #PRESSED_STATE_SET 2221 * @see #ENABLED_STATE_SET 2222 * @see #SELECTED_STATE_SET 2223 */ 2224 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2225 /** 2226 * Indicates the view is pressed, enabled, selected and its window has the 2227 * focus. 2228 * 2229 * @see #PRESSED_STATE_SET 2230 * @see #ENABLED_STATE_SET 2231 * @see #SELECTED_STATE_SET 2232 * @see #WINDOW_FOCUSED_STATE_SET 2233 */ 2234 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2235 /** 2236 * Indicates the view is pressed, enabled and focused. 2237 * 2238 * @see #PRESSED_STATE_SET 2239 * @see #ENABLED_STATE_SET 2240 * @see #FOCUSED_STATE_SET 2241 */ 2242 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2243 /** 2244 * Indicates the view is pressed, enabled, focused and its window has the 2245 * focus. 2246 * 2247 * @see #PRESSED_STATE_SET 2248 * @see #ENABLED_STATE_SET 2249 * @see #FOCUSED_STATE_SET 2250 * @see #WINDOW_FOCUSED_STATE_SET 2251 */ 2252 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2253 /** 2254 * Indicates the view is pressed, enabled, focused and selected. 2255 * 2256 * @see #PRESSED_STATE_SET 2257 * @see #ENABLED_STATE_SET 2258 * @see #SELECTED_STATE_SET 2259 * @see #FOCUSED_STATE_SET 2260 */ 2261 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2262 /** 2263 * Indicates the view is pressed, enabled, focused, selected and its window 2264 * has the focus. 2265 * 2266 * @see #PRESSED_STATE_SET 2267 * @see #ENABLED_STATE_SET 2268 * @see #SELECTED_STATE_SET 2269 * @see #FOCUSED_STATE_SET 2270 * @see #WINDOW_FOCUSED_STATE_SET 2271 */ 2272 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2273 2274 static { 2275 EMPTY_STATE_SET = StateSet.get(0); 2276 2277 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2278 2279 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2280 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2281 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2282 2283 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2284 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2285 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2286 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2287 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2288 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2289 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2290 | StateSet.VIEW_STATE_FOCUSED); 2291 2292 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2293 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2294 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2295 ENABLED_SELECTED_STATE_SET = StateSet.get( 2296 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2297 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2298 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2299 | StateSet.VIEW_STATE_ENABLED); 2300 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2301 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2302 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2303 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2304 | StateSet.VIEW_STATE_ENABLED); 2305 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2306 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2307 | StateSet.VIEW_STATE_ENABLED); 2308 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2309 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2310 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2311 2312 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2313 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2314 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2315 PRESSED_SELECTED_STATE_SET = StateSet.get( 2316 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2317 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2318 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2319 | StateSet.VIEW_STATE_PRESSED); 2320 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2321 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2322 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2323 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2324 | StateSet.VIEW_STATE_PRESSED); 2325 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2326 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2327 | StateSet.VIEW_STATE_PRESSED); 2328 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2329 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2330 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2331 PRESSED_ENABLED_STATE_SET = StateSet.get( 2332 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2333 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2334 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2335 | StateSet.VIEW_STATE_PRESSED); 2336 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2337 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2338 | StateSet.VIEW_STATE_PRESSED); 2339 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2340 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2341 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2342 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2343 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2344 | StateSet.VIEW_STATE_PRESSED); 2345 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2346 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2347 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2348 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2349 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2350 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2351 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2352 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2353 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2354 | StateSet.VIEW_STATE_PRESSED); 2355 } 2356 2357 /** 2358 * Accessibility event types that are dispatched for text population. 2359 */ 2360 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2361 AccessibilityEvent.TYPE_VIEW_CLICKED 2362 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2363 | AccessibilityEvent.TYPE_VIEW_SELECTED 2364 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2365 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2366 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2367 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2368 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2369 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2370 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2371 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2372 2373 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2374 2375 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2376 2377 /** 2378 * Temporary Rect currently for use in setBackground(). This will probably 2379 * be extended in the future to hold our own class with more than just 2380 * a Rect. :) 2381 */ 2382 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2383 2384 /** 2385 * Map used to store views' tags. 2386 */ 2387 @UnsupportedAppUsage 2388 private SparseArray<Object> mKeyedTags; 2389 2390 /** 2391 * The next available accessibility id. 2392 */ 2393 private static int sNextAccessibilityViewId; 2394 2395 /** 2396 * The animation currently associated with this view. 2397 * @hide 2398 */ 2399 protected Animation mCurrentAnimation = null; 2400 2401 /** 2402 * Width as measured during measure pass. 2403 * {@hide} 2404 */ 2405 @ViewDebug.ExportedProperty(category = "measurement") 2406 @UnsupportedAppUsage 2407 int mMeasuredWidth; 2408 2409 /** 2410 * Height as measured during measure pass. 2411 * {@hide} 2412 */ 2413 @ViewDebug.ExportedProperty(category = "measurement") 2414 @UnsupportedAppUsage 2415 int mMeasuredHeight; 2416 2417 /** 2418 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2419 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2420 * its display list. This flag, used only when hw accelerated, allows us to clear the 2421 * flag while retaining this information until it's needed (at getDisplayList() time and 2422 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2423 * 2424 * {@hide} 2425 */ 2426 @UnsupportedAppUsage 2427 boolean mRecreateDisplayList = false; 2428 2429 /** 2430 * The view's identifier. 2431 * {@hide} 2432 * 2433 * @see #setId(int) 2434 * @see #getId() 2435 */ 2436 @IdRes 2437 @ViewDebug.ExportedProperty(resolveId = true) 2438 int mID = NO_ID; 2439 2440 /** The ID of this view for autofill purposes. 2441 * <ul> 2442 * <li>== {@link #NO_ID}: ID has not been assigned yet 2443 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2444 * unique in the process. This might change 2445 * over activity lifecycle events. 2446 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2447 * unique in the activity. This stays the same 2448 * over activity lifecycle events. 2449 */ 2450 private int mAutofillViewId = NO_ID; 2451 2452 // ID for accessibility purposes. This ID must be unique for every window 2453 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2454 private int mAccessibilityViewId = NO_ID; 2455 2456 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2457 2458 /** 2459 * The view's tag. 2460 * {@hide} 2461 * 2462 * @see #setTag(Object) 2463 * @see #getTag() 2464 */ 2465 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2466 protected Object mTag = null; 2467 2468 /* 2469 * Masks for mPrivateFlags, as generated by dumpFlags(): 2470 * 2471 * |-------|-------|-------|-------| 2472 * 1 PFLAG_WANTS_FOCUS 2473 * 1 PFLAG_FOCUSED 2474 * 1 PFLAG_SELECTED 2475 * 1 PFLAG_IS_ROOT_NAMESPACE 2476 * 1 PFLAG_HAS_BOUNDS 2477 * 1 PFLAG_DRAWN 2478 * 1 PFLAG_DRAW_ANIMATION 2479 * 1 PFLAG_SKIP_DRAW 2480 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2481 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2482 * 1 PFLAG_MEASURED_DIMENSION_SET 2483 * 1 PFLAG_FORCE_LAYOUT 2484 * 1 PFLAG_LAYOUT_REQUIRED 2485 * 1 PFLAG_PRESSED 2486 * 1 PFLAG_DRAWING_CACHE_VALID 2487 * 1 PFLAG_ANIMATION_STARTED 2488 * 1 PFLAG_SAVE_STATE_CALLED 2489 * 1 PFLAG_ALPHA_SET 2490 * 1 PFLAG_SCROLL_CONTAINER 2491 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2492 * 1 PFLAG_DIRTY 2493 * 1 PFLAG_DIRTY_MASK 2494 * 1 PFLAG_OPAQUE_BACKGROUND 2495 * 1 PFLAG_OPAQUE_SCROLLBARS 2496 * 11 PFLAG_OPAQUE_MASK 2497 * 1 PFLAG_PREPRESSED 2498 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2499 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2500 * 1 PFLAG_HOVERED 2501 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2502 * 1 PFLAG_ACTIVATED 2503 * 1 PFLAG_INVALIDATED 2504 * |-------|-------|-------|-------| 2505 */ 2506 /** {@hide} */ 2507 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2508 /** {@hide} */ 2509 static final int PFLAG_FOCUSED = 0x00000002; 2510 /** {@hide} */ 2511 static final int PFLAG_SELECTED = 0x00000004; 2512 /** {@hide} */ 2513 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2514 /** {@hide} */ 2515 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2516 /** {@hide} */ 2517 static final int PFLAG_DRAWN = 0x00000020; 2518 /** 2519 * When this flag is set, this view is running an animation on behalf of its 2520 * children and should therefore not cancel invalidate requests, even if they 2521 * lie outside of this view's bounds. 2522 * 2523 * {@hide} 2524 */ 2525 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2526 /** {@hide} */ 2527 static final int PFLAG_SKIP_DRAW = 0x00000080; 2528 /** {@hide} */ 2529 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2530 /** {@hide} */ 2531 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2532 /** {@hide} */ 2533 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2534 /** {@hide} */ 2535 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2536 /** {@hide} */ 2537 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2538 2539 private static final int PFLAG_PRESSED = 0x00004000; 2540 2541 /** {@hide} */ 2542 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2543 /** 2544 * Flag used to indicate that this view should be drawn once more (and only once 2545 * more) after its animation has completed. 2546 * {@hide} 2547 */ 2548 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2549 2550 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2551 2552 /** 2553 * Indicates that the View returned true when onSetAlpha() was called and that 2554 * the alpha must be restored. 2555 * {@hide} 2556 */ 2557 static final int PFLAG_ALPHA_SET = 0x00040000; 2558 2559 /** 2560 * Set by {@link #setScrollContainer(boolean)}. 2561 */ 2562 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2563 2564 /** 2565 * Set by {@link #setScrollContainer(boolean)}. 2566 */ 2567 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2568 2569 /** 2570 * View flag indicating whether this view was invalidated (fully or partially.) 2571 * 2572 * @hide 2573 */ 2574 static final int PFLAG_DIRTY = 0x00200000; 2575 2576 /** 2577 * Mask for {@link #PFLAG_DIRTY}. 2578 * 2579 * @hide 2580 */ 2581 static final int PFLAG_DIRTY_MASK = 0x00200000; 2582 2583 /** 2584 * Indicates whether the background is opaque. 2585 * 2586 * @hide 2587 */ 2588 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2589 2590 /** 2591 * Indicates whether the scrollbars are opaque. 2592 * 2593 * @hide 2594 */ 2595 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2596 2597 /** 2598 * Indicates whether the view is opaque. 2599 * 2600 * @hide 2601 */ 2602 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2603 2604 /** 2605 * Indicates a prepressed state; 2606 * the short time between ACTION_DOWN and recognizing 2607 * a 'real' press. Prepressed is used to recognize quick taps 2608 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2609 * 2610 * @hide 2611 */ 2612 private static final int PFLAG_PREPRESSED = 0x02000000; 2613 2614 /** 2615 * Indicates whether the view is temporarily detached. 2616 * 2617 * @hide 2618 */ 2619 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2620 2621 /** 2622 * Indicates that we should awaken scroll bars once attached 2623 * 2624 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2625 * during window attachment and it is no longer needed. Feel free to repurpose it. 2626 * 2627 * @hide 2628 */ 2629 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2630 2631 /** 2632 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2633 * @hide 2634 */ 2635 private static final int PFLAG_HOVERED = 0x10000000; 2636 2637 /** 2638 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2639 */ 2640 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2641 2642 /** {@hide} */ 2643 static final int PFLAG_ACTIVATED = 0x40000000; 2644 2645 /** 2646 * Indicates that this view was specifically invalidated, not just dirtied because some 2647 * child view was invalidated. The flag is used to determine when we need to recreate 2648 * a view's display list (as opposed to just returning a reference to its existing 2649 * display list). 2650 * 2651 * @hide 2652 */ 2653 static final int PFLAG_INVALIDATED = 0x80000000; 2654 2655 /* End of masks for mPrivateFlags */ 2656 2657 /* 2658 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2659 * 2660 * |-------|-------|-------|-------| 2661 * 1 PFLAG2_DRAG_CAN_ACCEPT 2662 * 1 PFLAG2_DRAG_HOVERED 2663 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2664 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2665 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2666 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2667 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2668 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2669 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2670 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2671 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2672 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2673 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2674 * 111 PFLAG2_TEXT_DIRECTION_MASK 2675 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2676 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2677 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2678 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2679 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2680 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2681 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2682 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2683 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2684 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2685 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2686 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2687 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2688 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2689 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2690 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2691 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2692 * 1 PFLAG2_VIEW_QUICK_REJECTED 2693 * 1 PFLAG2_PADDING_RESOLVED 2694 * 1 PFLAG2_DRAWABLE_RESOLVED 2695 * 1 PFLAG2_HAS_TRANSIENT_STATE 2696 * |-------|-------|-------|-------| 2697 */ 2698 2699 /** 2700 * Indicates that this view has reported that it can accept the current drag's content. 2701 * Cleared when the drag operation concludes. 2702 * @hide 2703 */ 2704 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2705 2706 /** 2707 * Indicates that this view is currently directly under the drag location in a 2708 * drag-and-drop operation involving content that it can accept. Cleared when 2709 * the drag exits the view, or when the drag operation concludes. 2710 * @hide 2711 */ 2712 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2713 2714 /** @hide */ 2715 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2716 LAYOUT_DIRECTION_LTR, 2717 LAYOUT_DIRECTION_RTL, 2718 LAYOUT_DIRECTION_INHERIT, 2719 LAYOUT_DIRECTION_LOCALE 2720 }) 2721 @Retention(RetentionPolicy.SOURCE) 2722 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2723 public @interface LayoutDir {} 2724 2725 /** @hide */ 2726 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2727 LAYOUT_DIRECTION_LTR, 2728 LAYOUT_DIRECTION_RTL 2729 }) 2730 @Retention(RetentionPolicy.SOURCE) 2731 public @interface ResolvedLayoutDir {} 2732 2733 /** 2734 * A flag to indicate that the layout direction of this view has not been defined yet. 2735 * @hide 2736 */ 2737 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2738 2739 /** 2740 * Horizontal layout direction of this view is from Left to Right. 2741 * Use with {@link #setLayoutDirection}. 2742 */ 2743 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2744 2745 /** 2746 * Horizontal layout direction of this view is from Right to Left. 2747 * Use with {@link #setLayoutDirection}. 2748 */ 2749 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2750 2751 /** 2752 * Horizontal layout direction of this view is inherited from its parent. 2753 * Use with {@link #setLayoutDirection}. 2754 */ 2755 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2756 2757 /** 2758 * Horizontal layout direction of this view is from deduced from the default language 2759 * script for the locale. Use with {@link #setLayoutDirection}. 2760 */ 2761 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2762 2763 /** 2764 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2765 * @hide 2766 */ 2767 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2768 2769 /** 2770 * Mask for use with private flags indicating bits used for horizontal layout direction. 2771 * @hide 2772 */ 2773 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2774 2775 /** 2776 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2777 * right-to-left direction. 2778 * @hide 2779 */ 2780 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2781 2782 /** 2783 * Indicates whether the view horizontal layout direction has been resolved. 2784 * @hide 2785 */ 2786 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2787 2788 /** 2789 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2790 * @hide 2791 */ 2792 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2793 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2794 2795 /* 2796 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2797 * flag value. 2798 * @hide 2799 */ 2800 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2801 LAYOUT_DIRECTION_LTR, 2802 LAYOUT_DIRECTION_RTL, 2803 LAYOUT_DIRECTION_INHERIT, 2804 LAYOUT_DIRECTION_LOCALE 2805 }; 2806 2807 /** 2808 * Default horizontal layout direction. 2809 */ 2810 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2811 2812 /** 2813 * Default horizontal layout direction. 2814 * @hide 2815 */ 2816 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2817 2818 /** 2819 * Text direction is inherited through {@link ViewGroup} 2820 */ 2821 public static final int TEXT_DIRECTION_INHERIT = 0; 2822 2823 /** 2824 * Text direction is using "first strong algorithm". The first strong directional character 2825 * determines the paragraph direction. If there is no strong directional character, the 2826 * paragraph direction is the view's resolved layout direction. 2827 */ 2828 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2829 2830 /** 2831 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2832 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2833 * If there are neither, the paragraph direction is the view's resolved layout direction. 2834 */ 2835 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2836 2837 /** 2838 * Text direction is forced to LTR. 2839 */ 2840 public static final int TEXT_DIRECTION_LTR = 3; 2841 2842 /** 2843 * Text direction is forced to RTL. 2844 */ 2845 public static final int TEXT_DIRECTION_RTL = 4; 2846 2847 /** 2848 * Text direction is coming from the system Locale. 2849 */ 2850 public static final int TEXT_DIRECTION_LOCALE = 5; 2851 2852 /** 2853 * Text direction is using "first strong algorithm". The first strong directional character 2854 * determines the paragraph direction. If there is no strong directional character, the 2855 * paragraph direction is LTR. 2856 */ 2857 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2858 2859 /** 2860 * Text direction is using "first strong algorithm". The first strong directional character 2861 * determines the paragraph direction. If there is no strong directional character, the 2862 * paragraph direction is RTL. 2863 */ 2864 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2865 2866 /** 2867 * Default text direction is inherited 2868 */ 2869 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2870 2871 /** 2872 * Default resolved text direction 2873 * @hide 2874 */ 2875 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2876 2877 /** 2878 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2879 * @hide 2880 */ 2881 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2882 2883 /** 2884 * Mask for use with private flags indicating bits used for text direction. 2885 * @hide 2886 */ 2887 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2888 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2889 2890 /** 2891 * Array of text direction flags for mapping attribute "textDirection" to correct 2892 * flag value. 2893 * @hide 2894 */ 2895 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2896 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2897 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2898 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2899 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2900 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2901 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2902 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2903 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2904 }; 2905 2906 /** 2907 * Indicates whether the view text direction has been resolved. 2908 * @hide 2909 */ 2910 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2911 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2912 2913 /** 2914 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2915 * @hide 2916 */ 2917 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2918 2919 /** 2920 * Mask for use with private flags indicating bits used for resolved text direction. 2921 * @hide 2922 */ 2923 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2924 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2925 2926 /** 2927 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2928 * @hide 2929 */ 2930 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2931 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2932 2933 /** @hide */ 2934 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2935 TEXT_ALIGNMENT_INHERIT, 2936 TEXT_ALIGNMENT_GRAVITY, 2937 TEXT_ALIGNMENT_CENTER, 2938 TEXT_ALIGNMENT_TEXT_START, 2939 TEXT_ALIGNMENT_TEXT_END, 2940 TEXT_ALIGNMENT_VIEW_START, 2941 TEXT_ALIGNMENT_VIEW_END 2942 }) 2943 @Retention(RetentionPolicy.SOURCE) 2944 public @interface TextAlignment {} 2945 2946 /** 2947 * Default text alignment. The text alignment of this View is inherited from its parent. 2948 * Use with {@link #setTextAlignment(int)} 2949 */ 2950 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2951 2952 /** 2953 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2954 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 2955 * 2956 * Use with {@link #setTextAlignment(int)} 2957 */ 2958 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2959 2960 /** 2961 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2962 * 2963 * Use with {@link #setTextAlignment(int)} 2964 */ 2965 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2966 2967 /** 2968 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2969 * 2970 * Use with {@link #setTextAlignment(int)} 2971 */ 2972 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2973 2974 /** 2975 * Center the paragraph, e.g. ALIGN_CENTER. 2976 * 2977 * Use with {@link #setTextAlignment(int)} 2978 */ 2979 public static final int TEXT_ALIGNMENT_CENTER = 4; 2980 2981 /** 2982 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 2983 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2984 * 2985 * Use with {@link #setTextAlignment(int)} 2986 */ 2987 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2988 2989 /** 2990 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 2991 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2992 * 2993 * Use with {@link #setTextAlignment(int)} 2994 */ 2995 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2996 2997 /** 2998 * Default text alignment is inherited 2999 */ 3000 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3001 3002 /** 3003 * Default resolved text alignment 3004 * @hide 3005 */ 3006 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3007 3008 /** 3009 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 3010 * @hide 3011 */ 3012 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 3013 3014 /** 3015 * Mask for use with private flags indicating bits used for text alignment. 3016 * @hide 3017 */ 3018 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3019 3020 /** 3021 * Array of text direction flags for mapping attribute "textAlignment" to correct 3022 * flag value. 3023 * @hide 3024 */ 3025 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 3026 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3027 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3028 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3029 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3030 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3031 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3032 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 3033 }; 3034 3035 /** 3036 * Indicates whether the view text alignment has been resolved. 3037 * @hide 3038 */ 3039 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3040 3041 /** 3042 * Bit shift to get the resolved text alignment. 3043 * @hide 3044 */ 3045 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 3046 3047 /** 3048 * Mask for use with private flags indicating bits used for text alignment. 3049 * @hide 3050 */ 3051 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 3052 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3053 3054 /** 3055 * Indicates whether if the view text alignment has been resolved to gravity 3056 */ 3057 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3058 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3059 3060 // Accessiblity constants for mPrivateFlags2 3061 3062 /** 3063 * Shift for the bits in {@link #mPrivateFlags2} related to the 3064 * "importantForAccessibility" attribute. 3065 */ 3066 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3067 3068 /** 3069 * Automatically determine whether a view is important for accessibility. 3070 */ 3071 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3072 3073 /** 3074 * The view is important for accessibility. 3075 */ 3076 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3077 3078 /** 3079 * The view is not important for accessibility. 3080 */ 3081 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3082 3083 /** 3084 * The view is not important for accessibility, nor are any of its 3085 * descendant views. 3086 */ 3087 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3088 3089 /** 3090 * The default whether the view is important for accessibility. 3091 */ 3092 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3093 3094 /** 3095 * Mask for obtaining the bits which specify how to determine 3096 * whether a view is important for accessibility. 3097 */ 3098 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3099 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3100 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3101 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3102 3103 /** 3104 * Shift for the bits in {@link #mPrivateFlags2} related to the 3105 * "accessibilityLiveRegion" attribute. 3106 */ 3107 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3108 3109 /** 3110 * Live region mode specifying that accessibility services should not 3111 * automatically announce changes to this view. This is the default live 3112 * region mode for most views. 3113 * <p> 3114 * Use with {@link #setAccessibilityLiveRegion(int)}. 3115 */ 3116 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3117 3118 /** 3119 * Live region mode specifying that accessibility services should announce 3120 * changes to this view. 3121 * <p> 3122 * Use with {@link #setAccessibilityLiveRegion(int)}. 3123 */ 3124 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3125 3126 /** 3127 * Live region mode specifying that accessibility services should interrupt 3128 * ongoing speech to immediately announce changes to this view. 3129 * <p> 3130 * Use with {@link #setAccessibilityLiveRegion(int)}. 3131 */ 3132 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3133 3134 /** 3135 * The default whether the view is important for accessibility. 3136 */ 3137 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3138 3139 /** 3140 * Mask for obtaining the bits which specify a view's accessibility live 3141 * region mode. 3142 */ 3143 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3144 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3145 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3146 3147 /** 3148 * Flag indicating whether a view has accessibility focus. 3149 */ 3150 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3151 3152 /** 3153 * Flag whether the accessibility state of the subtree rooted at this view changed. 3154 */ 3155 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3156 3157 /** 3158 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3159 * is used to check whether later changes to the view's transform should invalidate the 3160 * view to force the quickReject test to run again. 3161 */ 3162 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3163 3164 /** 3165 * Flag indicating that start/end padding has been resolved into left/right padding 3166 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3167 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3168 * during measurement. In some special cases this is required such as when an adapter-based 3169 * view measures prospective children without attaching them to a window. 3170 */ 3171 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3172 3173 /** 3174 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3175 */ 3176 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3177 3178 /** 3179 * Indicates that the view is tracking some sort of transient state 3180 * that the app should not need to be aware of, but that the framework 3181 * should take special care to preserve. 3182 */ 3183 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3184 3185 /** 3186 * Group of bits indicating that RTL properties resolution is done. 3187 */ 3188 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3189 PFLAG2_TEXT_DIRECTION_RESOLVED | 3190 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3191 PFLAG2_PADDING_RESOLVED | 3192 PFLAG2_DRAWABLE_RESOLVED; 3193 3194 // There are a couple of flags left in mPrivateFlags2 3195 3196 /* End of masks for mPrivateFlags2 */ 3197 3198 /* 3199 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3200 * 3201 * |-------|-------|-------|-------| 3202 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3203 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3204 * 1 PFLAG3_IS_LAID_OUT 3205 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3206 * 1 PFLAG3_CALLED_SUPER 3207 * 1 PFLAG3_APPLYING_INSETS 3208 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3209 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3210 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3211 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3212 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3213 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3214 * 1 PFLAG3_SCROLL_INDICATOR_START 3215 * 1 PFLAG3_SCROLL_INDICATOR_END 3216 * 1 PFLAG3_ASSIST_BLOCKED 3217 * 1 PFLAG3_CLUSTER 3218 * 1 PFLAG3_IS_AUTOFILLED 3219 * 1 PFLAG3_FINGER_DOWN 3220 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3221 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3222 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3223 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3224 * 1 PFLAG3_TEMPORARY_DETACH 3225 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3226 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3227 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3228 * 1 PFLAG3_AGGREGATED_VISIBLE 3229 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3230 * 1 PFLAG3_ACCESSIBILITY_HEADING 3231 * |-------|-------|-------|-------| 3232 */ 3233 3234 /** 3235 * Flag indicating that view has a transform animation set on it. This is used to track whether 3236 * an animation is cleared between successive frames, in order to tell the associated 3237 * DisplayList to clear its animation matrix. 3238 */ 3239 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3240 3241 /** 3242 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3243 * animation is cleared between successive frames, in order to tell the associated 3244 * DisplayList to restore its alpha value. 3245 */ 3246 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3247 3248 /** 3249 * Flag indicating that the view has been through at least one layout since it 3250 * was last attached to a window. 3251 */ 3252 static final int PFLAG3_IS_LAID_OUT = 0x4; 3253 3254 /** 3255 * Flag indicating that a call to measure() was skipped and should be done 3256 * instead when layout() is invoked. 3257 */ 3258 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3259 3260 /** 3261 * Flag indicating that an overridden method correctly called down to 3262 * the superclass implementation as required by the API spec. 3263 */ 3264 static final int PFLAG3_CALLED_SUPER = 0x10; 3265 3266 /** 3267 * Flag indicating that we're in the process of applying window insets. 3268 */ 3269 static final int PFLAG3_APPLYING_INSETS = 0x20; 3270 3271 /** 3272 * Flag indicating that we're in the process of fitting system windows using the old method. 3273 */ 3274 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3275 3276 /** 3277 * Flag indicating that nested scrolling is enabled for this view. 3278 * The view will optionally cooperate with views up its parent chain to allow for 3279 * integrated nested scrolling along the same axis. 3280 */ 3281 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3282 3283 /** 3284 * Flag indicating that the bottom scroll indicator should be displayed 3285 * when this view can scroll up. 3286 */ 3287 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3288 3289 /** 3290 * Flag indicating that the bottom scroll indicator should be displayed 3291 * when this view can scroll down. 3292 */ 3293 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3294 3295 /** 3296 * Flag indicating that the left scroll indicator should be displayed 3297 * when this view can scroll left. 3298 */ 3299 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3300 3301 /** 3302 * Flag indicating that the right scroll indicator should be displayed 3303 * when this view can scroll right. 3304 */ 3305 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3306 3307 /** 3308 * Flag indicating that the start scroll indicator should be displayed 3309 * when this view can scroll in the start direction. 3310 */ 3311 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3312 3313 /** 3314 * Flag indicating that the end scroll indicator should be displayed 3315 * when this view can scroll in the end direction. 3316 */ 3317 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3318 3319 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3320 3321 static final int SCROLL_INDICATORS_NONE = 0x0000; 3322 3323 /** 3324 * Mask for use with setFlags indicating bits used for indicating which 3325 * scroll indicators are enabled. 3326 */ 3327 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3328 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3329 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3330 | PFLAG3_SCROLL_INDICATOR_END; 3331 3332 /** 3333 * Left-shift required to translate between public scroll indicator flags 3334 * and internal PFLAGS3 flags. When used as a right-shift, translates 3335 * PFLAGS3 flags to public flags. 3336 */ 3337 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3338 3339 /** @hide */ 3340 @Retention(RetentionPolicy.SOURCE) 3341 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3342 SCROLL_INDICATOR_TOP, 3343 SCROLL_INDICATOR_BOTTOM, 3344 SCROLL_INDICATOR_LEFT, 3345 SCROLL_INDICATOR_RIGHT, 3346 SCROLL_INDICATOR_START, 3347 SCROLL_INDICATOR_END, 3348 }) 3349 public @interface ScrollIndicators {} 3350 3351 /** 3352 * Scroll indicator direction for the top edge of the view. 3353 * 3354 * @see #setScrollIndicators(int) 3355 * @see #setScrollIndicators(int, int) 3356 * @see #getScrollIndicators() 3357 */ 3358 public static final int SCROLL_INDICATOR_TOP = 3359 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3360 3361 /** 3362 * Scroll indicator direction for the bottom edge of the view. 3363 * 3364 * @see #setScrollIndicators(int) 3365 * @see #setScrollIndicators(int, int) 3366 * @see #getScrollIndicators() 3367 */ 3368 public static final int SCROLL_INDICATOR_BOTTOM = 3369 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3370 3371 /** 3372 * Scroll indicator direction for the left edge of the view. 3373 * 3374 * @see #setScrollIndicators(int) 3375 * @see #setScrollIndicators(int, int) 3376 * @see #getScrollIndicators() 3377 */ 3378 public static final int SCROLL_INDICATOR_LEFT = 3379 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3380 3381 /** 3382 * Scroll indicator direction for the right edge of the view. 3383 * 3384 * @see #setScrollIndicators(int) 3385 * @see #setScrollIndicators(int, int) 3386 * @see #getScrollIndicators() 3387 */ 3388 public static final int SCROLL_INDICATOR_RIGHT = 3389 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3390 3391 /** 3392 * Scroll indicator direction for the starting edge of the view. 3393 * <p> 3394 * Resolved according to the view's layout direction, see 3395 * {@link #getLayoutDirection()} for more information. 3396 * 3397 * @see #setScrollIndicators(int) 3398 * @see #setScrollIndicators(int, int) 3399 * @see #getScrollIndicators() 3400 */ 3401 public static final int SCROLL_INDICATOR_START = 3402 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3403 3404 /** 3405 * Scroll indicator direction for the ending edge of the view. 3406 * <p> 3407 * Resolved according to the view's layout direction, see 3408 * {@link #getLayoutDirection()} for more information. 3409 * 3410 * @see #setScrollIndicators(int) 3411 * @see #setScrollIndicators(int, int) 3412 * @see #getScrollIndicators() 3413 */ 3414 public static final int SCROLL_INDICATOR_END = 3415 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3416 3417 /** 3418 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3419 * into this view.<p> 3420 */ 3421 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3422 3423 /** 3424 * Flag indicating that the view is a root of a keyboard navigation cluster. 3425 * 3426 * @see #isKeyboardNavigationCluster() 3427 * @see #setKeyboardNavigationCluster(boolean) 3428 */ 3429 private static final int PFLAG3_CLUSTER = 0x8000; 3430 3431 /** 3432 * Flag indicating that the view is autofilled 3433 * 3434 * @see #isAutofilled() 3435 * @see #setAutofilled(boolean, boolean) 3436 */ 3437 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3438 3439 /** 3440 * Indicates that the user is currently touching the screen. 3441 * Currently used for the tooltip positioning only. 3442 */ 3443 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3444 3445 /** 3446 * Flag indicating that this view is the default-focus view. 3447 * 3448 * @see #isFocusedByDefault() 3449 * @see #setFocusedByDefault(boolean) 3450 */ 3451 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3452 3453 /** 3454 * Shift for the bits in {@link #mPrivateFlags3} related to the 3455 * "importantForAutofill" attribute. 3456 */ 3457 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3458 3459 /** 3460 * Mask for obtaining the bits which specify how to determine 3461 * whether a view is important for autofill. 3462 */ 3463 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3464 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3465 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3466 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3467 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3468 3469 /** 3470 * Whether this view has rendered elements that overlap (see {@link 3471 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3472 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3473 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3474 * determined by whatever {@link #hasOverlappingRendering()} returns. 3475 */ 3476 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3477 3478 /** 3479 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3480 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3481 */ 3482 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3483 3484 /** 3485 * Flag indicating that the view is temporarily detached from the parent view. 3486 * 3487 * @see #onStartTemporaryDetach() 3488 * @see #onFinishTemporaryDetach() 3489 */ 3490 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3491 3492 /** 3493 * Flag indicating that the view does not wish to be revealed within its parent 3494 * hierarchy when it gains focus. Expressed in the negative since the historical 3495 * default behavior is to reveal on focus; this flag suppresses that behavior. 3496 * 3497 * @see #setRevealOnFocusHint(boolean) 3498 * @see #getRevealOnFocusHint() 3499 */ 3500 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3501 3502 /** 3503 * Flag indicating that when layout is completed we should notify 3504 * that the view was entered for autofill purposes. To minimize 3505 * showing autofill for views not visible to the user we evaluate 3506 * user visibility which cannot be done until the view is laid out. 3507 */ 3508 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3509 3510 /** 3511 * Works like focusable for screen readers, but without the side effects on input focus. 3512 * @see #setScreenReaderFocusable(boolean) 3513 */ 3514 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3515 3516 /** 3517 * The last aggregated visibility. Used to detect when it truly changes. 3518 */ 3519 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3520 3521 /** 3522 * Used to indicate that {@link #mAutofillId} was explicitly set through 3523 * {@link #setAutofillId(AutofillId)}. 3524 */ 3525 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3526 3527 /** 3528 * Indicates if the View is a heading for accessibility purposes 3529 */ 3530 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3531 3532 /* End of masks for mPrivateFlags3 */ 3533 3534 /* 3535 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3536 * 3537 * |-------|-------|-------|-------| 3538 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3539 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3540 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3541 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3542 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3543 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3544 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3545 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3546 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3547 * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED 3548 * 1 PFLAG4_DETACHED 3549 * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE 3550 * 1 PFLAG4_DRAG_A11Y_STARTED 3551 * 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED 3552 * 1 PFLAG4_TRAVERSAL_TRACING_ENABLED 3553 * 1 PFLAG4_RELAYOUT_TRACING_ENABLED 3554 * |-------|-------|-------|-------| 3555 */ 3556 3557 /** 3558 * Mask for obtaining the bits which specify how to determine 3559 * whether a view is important for autofill. 3560 * 3561 * <p>NOTE: the important for content capture values were the first flags added and are set in 3562 * the rightmost position, so we don't need to shift them 3563 */ 3564 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3565 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3566 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3567 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3568 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3569 3570 /* 3571 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3572 * should be called. 3573 * 3574 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3575 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3576 */ 3577 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3578 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3579 3580 /* 3581 * Flags used to cache the value returned by isImportantForContentCapture while the view 3582 * hierarchy is being traversed. 3583 */ 3584 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3585 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3586 3587 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3588 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3589 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3590 3591 /** 3592 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3593 */ 3594 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3595 3596 /** 3597 * Flag indicating the field should not have yellow highlight when autofilled. 3598 */ 3599 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3600 3601 /** 3602 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3603 */ 3604 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3605 3606 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3607 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3608 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3609 3610 /** 3611 * Indicates if the view can receive click events when disabled. 3612 */ 3613 private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; 3614 3615 /** 3616 * Indicates if the view is just detached. 3617 */ 3618 private static final int PFLAG4_DETACHED = 0x000002000; 3619 3620 /** 3621 * Indicates that the view has transient state because the system is translating it. 3622 */ 3623 private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; 3624 3625 /** 3626 * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START} 3627 */ 3628 private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; 3629 3630 /** 3631 * Indicates that the view enables auto handwriting initiation. 3632 */ 3633 private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; 3634 3635 /** 3636 * When set, measure and layout passes of this view will be logged with {@link Trace}, so we 3637 * can better debug jank due to complex view hierarchies. 3638 */ 3639 private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000; 3640 3641 /** 3642 * When set, emits a {@link Trace} instant event and stacktrace every time a requestLayout of 3643 * this class happens. 3644 */ 3645 private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000; 3646 3647 /* End of masks for mPrivateFlags4 */ 3648 3649 /** @hide */ 3650 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3651 /** @hide */ 3652 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3653 /** @hide */ 3654 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3655 3656 /** @hide */ 3657 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3658 VIEW_STRUCTURE_FOR_ASSIST, 3659 VIEW_STRUCTURE_FOR_AUTOFILL, 3660 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3661 }) 3662 @Retention(RetentionPolicy.SOURCE) 3663 public @interface ViewStructureType {} 3664 3665 /** 3666 * Always allow a user to over-scroll this view, provided it is a 3667 * view that can scroll. 3668 * 3669 * @see #getOverScrollMode() 3670 * @see #setOverScrollMode(int) 3671 */ 3672 public static final int OVER_SCROLL_ALWAYS = 0; 3673 3674 /** 3675 * Allow a user to over-scroll this view only if the content is large 3676 * enough to meaningfully scroll, provided it is a view that can scroll. 3677 * 3678 * @see #getOverScrollMode() 3679 * @see #setOverScrollMode(int) 3680 */ 3681 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3682 3683 /** 3684 * Never allow a user to over-scroll this view. 3685 * 3686 * @see #getOverScrollMode() 3687 * @see #setOverScrollMode(int) 3688 */ 3689 public static final int OVER_SCROLL_NEVER = 2; 3690 3691 /** 3692 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3693 * requested the system UI (status bar) to be visible (the default). 3694 * 3695 * @see #setSystemUiVisibility(int) 3696 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 3697 * instead. 3698 */ 3699 @Deprecated 3700 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3701 3702 /** 3703 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3704 * system UI to enter an unobtrusive "low profile" mode. 3705 * 3706 * <p>This is for use in games, book readers, video players, or any other 3707 * "immersive" application where the usual system chrome is deemed too distracting. 3708 * 3709 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3710 * 3711 * @see #setSystemUiVisibility(int) 3712 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 3713 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 3714 * {@link Type#systemBars()}. 3715 */ 3716 @Deprecated 3717 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3718 3719 /** 3720 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3721 * system navigation be temporarily hidden. 3722 * 3723 * <p>This is an even less obtrusive state than that called for by 3724 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3725 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3726 * those to disappear. This is useful (in conjunction with the 3727 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3728 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3729 * window flags) for displaying content using every last pixel on the display. 3730 * 3731 * <p>There is a limitation: because navigation controls are so important, the least user 3732 * interaction will cause them to reappear immediately. When this happens, both 3733 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3734 * so that both elements reappear at the same time. 3735 * 3736 * @see #setSystemUiVisibility(int) 3737 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 3738 * instead. 3739 */ 3740 @Deprecated 3741 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3742 3743 /** 3744 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3745 * into the normal fullscreen mode so that its content can take over the screen 3746 * while still allowing the user to interact with the application. 3747 * 3748 * <p>This has the same visual effect as 3749 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3750 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3751 * meaning that non-critical screen decorations (such as the status bar) will be 3752 * hidden while the user is in the View's window, focusing the experience on 3753 * that content. Unlike the window flag, if you are using ActionBar in 3754 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3755 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3756 * hide the action bar. 3757 * 3758 * <p>This approach to going fullscreen is best used over the window flag when 3759 * it is a transient state -- that is, the application does this at certain 3760 * points in its user interaction where it wants to allow the user to focus 3761 * on content, but not as a continuous state. For situations where the application 3762 * would like to simply stay full screen the entire time (such as a game that 3763 * wants to take over the screen), the 3764 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3765 * is usually a better approach. The state set here will be removed by the system 3766 * in various situations (such as the user moving to another application) like 3767 * the other system UI states. 3768 * 3769 * <p>When using this flag, the application should provide some easy facility 3770 * for the user to go out of it. A common example would be in an e-book 3771 * reader, where tapping on the screen brings back whatever screen and UI 3772 * decorations that had been hidden while the user was immersed in reading 3773 * the book. 3774 * 3775 * @see #setSystemUiVisibility(int) 3776 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 3777 * instead. 3778 */ 3779 @Deprecated 3780 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3781 3782 /** 3783 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3784 * flags, we would like a stable view of the content insets given to 3785 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3786 * will always represent the worst case that the application can expect 3787 * as a continuous state. In the stock Android UI this is the space for 3788 * the system bar, nav bar, and status bar, but not more transient elements 3789 * such as an input method. 3790 * 3791 * The stable layout your UI sees is based on the system UI modes you can 3792 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3793 * then you will get a stable layout for changes of the 3794 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3795 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3796 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3797 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3798 * with a stable layout. (Note that you should avoid using 3799 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3800 * 3801 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3802 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3803 * then a hidden status bar will be considered a "stable" state for purposes 3804 * here. This allows your UI to continually hide the status bar, while still 3805 * using the system UI flags to hide the action bar while still retaining 3806 * a stable layout. Note that changing the window fullscreen flag will never 3807 * provide a stable layout for a clean transition. 3808 * 3809 * <p>If you are using ActionBar in 3810 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3811 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3812 * insets it adds to those given to the application. 3813 * 3814 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 3815 * insets that don't change when system bars change visibility state. 3816 */ 3817 @Deprecated 3818 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3819 3820 /** 3821 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3822 * to be laid out as if it has requested 3823 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3824 * allows it to avoid artifacts when switching in and out of that mode, at 3825 * the expense that some of its user interface may be covered by screen 3826 * decorations when they are shown. You can perform layout of your inner 3827 * UI elements to account for the navigation system UI through the 3828 * {@link #fitSystemWindows(Rect)} method. 3829 * 3830 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3831 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 3832 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3833 */ 3834 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3835 3836 /** 3837 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3838 * to be laid out as if it has requested 3839 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3840 * allows it to avoid artifacts when switching in and out of that mode, at 3841 * the expense that some of its user interface may be covered by screen 3842 * decorations when they are shown. You can perform layout of your inner 3843 * UI elements to account for non-fullscreen system UI through the 3844 * {@link #fitSystemWindows(Rect)} method. 3845 * 3846 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3847 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3848 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3849 * layoutInDisplayCutoutMode} is 3850 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3851 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3852 * 3853 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3854 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3855 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3856 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3857 * 3858 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3859 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 3860 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3861 */ 3862 @Deprecated 3863 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3864 3865 /** 3866 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3867 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3868 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3869 * user interaction. 3870 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3871 * has an effect when used in combination with that flag.</p> 3872 * 3873 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead. 3874 */ 3875 @Deprecated 3876 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3877 3878 /** 3879 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3880 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3881 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3882 * experience while also hiding the system bars. If this flag is not set, 3883 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3884 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3885 * if the user swipes from the top of the screen. 3886 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3887 * system gestures, such as swiping from the top of the screen. These transient system bars 3888 * will overlay app's content, may have some degree of transparency, and will automatically 3889 * hide after a short timeout. 3890 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3891 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3892 * with one or both of those flags.</p> 3893 * 3894 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 3895 */ 3896 @Deprecated 3897 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3898 3899 /** 3900 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3901 * is compatible with light status bar backgrounds. 3902 * 3903 * <p>For this to take effect, the window must request 3904 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3905 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3906 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3907 * FLAG_TRANSLUCENT_STATUS}. 3908 * 3909 * @see android.R.attr#windowLightStatusBar 3910 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 3911 */ 3912 @Deprecated 3913 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3914 3915 /** 3916 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3917 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3918 */ 3919 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3920 3921 /** 3922 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3923 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3924 */ 3925 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3926 3927 /** 3928 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3929 * that is compatible with light navigation bar backgrounds. 3930 * 3931 * <p>For this to take effect, the window must request 3932 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3933 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3934 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3935 * FLAG_TRANSLUCENT_NAVIGATION}. 3936 * 3937 * @see android.R.attr#windowLightNavigationBar 3938 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 3939 */ 3940 @Deprecated 3941 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3942 3943 /** 3944 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3945 */ 3946 @Deprecated 3947 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3948 3949 /** 3950 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3951 */ 3952 @Deprecated 3953 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3954 3955 /** 3956 * @hide 3957 * 3958 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3959 * out of the public fields to keep the undefined bits out of the developer's way. 3960 * 3961 * Flag to make the status bar not expandable. Unless you also 3962 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3963 */ 3964 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3965 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3966 3967 /** 3968 * @hide 3969 * 3970 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3971 * out of the public fields to keep the undefined bits out of the developer's way. 3972 * 3973 * Flag to hide notification icons and scrolling ticker text. 3974 */ 3975 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3976 3977 /** 3978 * @hide 3979 * 3980 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3981 * out of the public fields to keep the undefined bits out of the developer's way. 3982 * 3983 * Flag to disable incoming notification alerts. This will not block 3984 * icons, but it will block sound, vibrating and other visual or aural notifications. 3985 */ 3986 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3987 3988 /** 3989 * @hide 3990 * 3991 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3992 * out of the public fields to keep the undefined bits out of the developer's way. 3993 * 3994 * Flag to hide only the scrolling ticker. Note that 3995 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3996 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3997 */ 3998 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3999 4000 /** 4001 * @hide 4002 * 4003 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4004 * out of the public fields to keep the undefined bits out of the developer's way. 4005 * 4006 * Flag to hide the center system info area. 4007 */ 4008 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 4009 4010 /** 4011 * @hide 4012 * 4013 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4014 * out of the public fields to keep the undefined bits out of the developer's way. 4015 * 4016 * Flag to hide only the home button. Don't use this 4017 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4018 */ 4019 @UnsupportedAppUsage 4020 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 4021 4022 /** 4023 * @hide 4024 * 4025 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4026 * out of the public fields to keep the undefined bits out of the developer's way. 4027 * 4028 * Flag to hide only the back button. Don't use this 4029 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4030 */ 4031 @UnsupportedAppUsage 4032 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 4033 4034 /** 4035 * @hide 4036 * 4037 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4038 * out of the public fields to keep the undefined bits out of the developer's way. 4039 * 4040 * Flag to hide only the clock. You might use this if your activity has 4041 * its own clock making the status bar's clock redundant. 4042 */ 4043 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 4044 4045 /** 4046 * @hide 4047 * 4048 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4049 * out of the public fields to keep the undefined bits out of the developer's way. 4050 * 4051 * Flag to hide only the recent apps button. Don't use this 4052 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4053 */ 4054 @UnsupportedAppUsage 4055 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 4056 4057 /** 4058 * @hide 4059 * 4060 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4061 * out of the public fields to keep the undefined bits out of the developer's way. 4062 * 4063 * Flag to disable the global search gesture. Don't use this 4064 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4065 */ 4066 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 4067 4068 /** 4069 * @hide 4070 * 4071 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4072 * out of the public fields to keep the undefined bits out of the developer's way. 4073 * 4074 * Flag to disable the ongoing call chip. 4075 */ 4076 public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; 4077 4078 /** 4079 * @hide 4080 */ 4081 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4082 4083 /** 4084 * These are the system UI flags that can be cleared by events outside 4085 * of an application. Currently this is just the ability to tap on the 4086 * screen while hiding the navigation bar to have it return. 4087 * @hide 4088 */ 4089 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4090 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4091 | SYSTEM_UI_FLAG_FULLSCREEN; 4092 4093 /** 4094 * Flags that can impact the layout in relation to system UI. 4095 * 4096 * @deprecated System UI layout flags are deprecated. 4097 */ 4098 @Deprecated 4099 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4100 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4101 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4102 4103 /** @hide */ 4104 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4105 FIND_VIEWS_WITH_TEXT, 4106 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4107 }) 4108 @Retention(RetentionPolicy.SOURCE) 4109 public @interface FindViewFlags {} 4110 4111 /** 4112 * Find views that render the specified text. 4113 * 4114 * @see #findViewsWithText(ArrayList, CharSequence, int) 4115 */ 4116 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4117 4118 /** 4119 * Find find views that contain the specified content description. 4120 * 4121 * @see #findViewsWithText(ArrayList, CharSequence, int) 4122 */ 4123 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4124 4125 /** 4126 * Find views that contain {@link AccessibilityNodeProvider}. Such 4127 * a View is a root of virtual view hierarchy and may contain the searched 4128 * text. If this flag is set Views with providers are automatically 4129 * added and it is a responsibility of the client to call the APIs of 4130 * the provider to determine whether the virtual tree rooted at this View 4131 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4132 * representing the virtual views with this text. 4133 * 4134 * @see #findViewsWithText(ArrayList, CharSequence, int) 4135 * 4136 * @hide 4137 */ 4138 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4139 4140 /** 4141 * The undefined cursor position. 4142 * 4143 * @hide 4144 */ 4145 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4146 4147 /** 4148 * Indicates that the screen has changed state and is now off. 4149 * 4150 * @see #onScreenStateChanged(int) 4151 */ 4152 public static final int SCREEN_STATE_OFF = 0x0; 4153 4154 /** 4155 * Indicates that the screen has changed state and is now on. 4156 * 4157 * @see #onScreenStateChanged(int) 4158 */ 4159 public static final int SCREEN_STATE_ON = 0x1; 4160 4161 /** 4162 * Indicates no axis of view scrolling. 4163 */ 4164 public static final int SCROLL_AXIS_NONE = 0; 4165 4166 /** 4167 * Indicates scrolling along the horizontal axis. 4168 */ 4169 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4170 4171 /** 4172 * Indicates scrolling along the vertical axis. 4173 */ 4174 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4175 4176 /** 4177 * Controls the over-scroll mode for this view. 4178 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4179 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4180 * and {@link #OVER_SCROLL_NEVER}. 4181 */ 4182 private int mOverScrollMode; 4183 4184 /** 4185 * The parent this view is attached to. 4186 * {@hide} 4187 * 4188 * @see #getParent() 4189 */ 4190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4191 protected ViewParent mParent; 4192 4193 /** 4194 * {@hide} 4195 * 4196 * Not available for general use. If you need help, hang up and then dial one of the following 4197 * public APIs: 4198 * 4199 * @see #isAttachedToWindow() for current attach state 4200 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4201 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4202 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4203 * @see #getHandler() for posting messages to this view's UI thread/looper 4204 * @see #getParent() for interacting with the parent chain 4205 * @see #getWindowToken() for the current window token 4206 * @see #getRootView() for the view at the root of the attached hierarchy 4207 * @see #getDisplay() for the Display this view is presented on 4208 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4209 * @see #hasWindowFocus() for whether the attached window is currently focused 4210 * @see #getWindowVisibility() for checking the visibility of the attached window 4211 */ 4212 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4213 AttachInfo mAttachInfo; 4214 4215 /** 4216 * {@hide} 4217 */ 4218 @ViewDebug.ExportedProperty(flagMapping = { 4219 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4220 name = "FORCE_LAYOUT"), 4221 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4222 name = "LAYOUT_REQUIRED"), 4223 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4224 name = "DRAWING_CACHE_INVALID", outputIf = false), 4225 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4226 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4227 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4228 }, formatToHexString = true) 4229 4230 /* @hide */ 4231 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4232 public int mPrivateFlags; 4233 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4234 int mPrivateFlags2; 4235 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4236 int mPrivateFlags3; 4237 4238 private int mPrivateFlags4; 4239 4240 /** 4241 * This view's request for the visibility of the status bar. 4242 * @hide 4243 */ 4244 @ViewDebug.ExportedProperty(flagMapping = { 4245 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4246 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4247 name = "LOW_PROFILE"), 4248 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4249 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4250 name = "HIDE_NAVIGATION"), 4251 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4252 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4253 name = "FULLSCREEN"), 4254 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4255 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4256 name = "LAYOUT_STABLE"), 4257 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4258 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4259 name = "LAYOUT_HIDE_NAVIGATION"), 4260 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4261 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4262 name = "LAYOUT_FULLSCREEN"), 4263 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4264 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4265 name = "IMMERSIVE"), 4266 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4267 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4268 name = "IMMERSIVE_STICKY"), 4269 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4270 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4271 name = "LIGHT_STATUS_BAR"), 4272 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4273 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4274 name = "LIGHT_NAVIGATION_BAR"), 4275 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4276 equals = STATUS_BAR_DISABLE_EXPAND, 4277 name = "STATUS_BAR_DISABLE_EXPAND"), 4278 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4279 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4280 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4281 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4282 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4283 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4284 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4285 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4286 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4287 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4288 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4289 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4290 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4291 equals = STATUS_BAR_DISABLE_HOME, 4292 name = "STATUS_BAR_DISABLE_HOME"), 4293 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4294 equals = STATUS_BAR_DISABLE_BACK, 4295 name = "STATUS_BAR_DISABLE_BACK"), 4296 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4297 equals = STATUS_BAR_DISABLE_CLOCK, 4298 name = "STATUS_BAR_DISABLE_CLOCK"), 4299 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4300 equals = STATUS_BAR_DISABLE_RECENT, 4301 name = "STATUS_BAR_DISABLE_RECENT"), 4302 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4303 equals = STATUS_BAR_DISABLE_SEARCH, 4304 name = "STATUS_BAR_DISABLE_SEARCH"), 4305 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4306 equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4307 name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") 4308 }, formatToHexString = true) 4309 @SystemUiVisibility 4310 int mSystemUiVisibility; 4311 4312 /** 4313 * @hide 4314 */ 4315 @IntDef(flag = true, prefix = "", value = { 4316 SYSTEM_UI_FLAG_LOW_PROFILE, 4317 SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4318 SYSTEM_UI_FLAG_FULLSCREEN, 4319 SYSTEM_UI_FLAG_LAYOUT_STABLE, 4320 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4321 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4322 SYSTEM_UI_FLAG_IMMERSIVE, 4323 SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4324 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4325 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4326 STATUS_BAR_DISABLE_EXPAND, 4327 STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4328 STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4329 STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4330 STATUS_BAR_DISABLE_SYSTEM_INFO, 4331 STATUS_BAR_DISABLE_HOME, 4332 STATUS_BAR_DISABLE_BACK, 4333 STATUS_BAR_DISABLE_CLOCK, 4334 STATUS_BAR_DISABLE_RECENT, 4335 STATUS_BAR_DISABLE_SEARCH, 4336 STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4337 }) 4338 @Retention(RetentionPolicy.SOURCE) 4339 public @interface SystemUiVisibility {} 4340 4341 /** 4342 * Reference count for transient state. 4343 * @see #setHasTransientState(boolean) 4344 */ 4345 int mTransientStateCount = 0; 4346 4347 /** 4348 * Count of how many windows this view has been attached to. 4349 */ 4350 int mWindowAttachCount; 4351 4352 /** 4353 * The layout parameters associated with this view and used by the parent 4354 * {@link android.view.ViewGroup} to determine how this view should be 4355 * laid out. 4356 * 4357 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4358 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4359 * state correctness of the class. 4360 * {@hide} 4361 */ 4362 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4363 protected ViewGroup.LayoutParams mLayoutParams; 4364 4365 /** 4366 * The view flags hold various views states. 4367 * 4368 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4369 * triggering updates. 4370 * {@hide} 4371 */ 4372 @ViewDebug.ExportedProperty(formatToHexString = true) 4373 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4374 int mViewFlags; 4375 4376 static class TransformationInfo { 4377 /** 4378 * The transform matrix for the View. This transform is calculated internally 4379 * based on the translation, rotation, and scale properties. 4380 * 4381 * Do *not* use this variable directly; instead call getMatrix(), which will 4382 * load the value from the View's RenderNode. 4383 */ 4384 private final Matrix mMatrix = new Matrix(); 4385 4386 /** 4387 * The inverse transform matrix for the View. This transform is calculated 4388 * internally based on the translation, rotation, and scale properties. 4389 * 4390 * Do *not* use this variable directly; instead call getInverseMatrix(), 4391 * which will load the value from the View's RenderNode. 4392 */ 4393 private Matrix mInverseMatrix; 4394 4395 /** 4396 * The opacity of the View. This is a value from 0 to 1, where 0 means 4397 * completely transparent and 1 means completely opaque. 4398 */ 4399 @ViewDebug.ExportedProperty 4400 private float mAlpha = 1f; 4401 4402 /** 4403 * The opacity of the view as manipulated by the Fade transition. This is a 4404 * property only used by transitions, which is composited with the other alpha 4405 * values to calculate the final visual alpha value. 4406 */ 4407 float mTransitionAlpha = 1f; 4408 } 4409 4410 /** @hide */ 4411 @UnsupportedAppUsage 4412 public TransformationInfo mTransformationInfo; 4413 4414 /** 4415 * Current clip bounds. to which all drawing of this view are constrained. 4416 */ 4417 @ViewDebug.ExportedProperty(category = "drawing") 4418 Rect mClipBounds = null; 4419 4420 private boolean mLastIsOpaque; 4421 4422 /** 4423 * The distance in pixels from the left edge of this view's parent 4424 * to the left edge of this view. 4425 * {@hide} 4426 */ 4427 @ViewDebug.ExportedProperty(category = "layout") 4428 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4429 protected int mLeft; 4430 /** 4431 * The distance in pixels from the left edge of this view's parent 4432 * to the right edge of this view. 4433 * {@hide} 4434 */ 4435 @ViewDebug.ExportedProperty(category = "layout") 4436 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4437 protected int mRight; 4438 /** 4439 * The distance in pixels from the top edge of this view's parent 4440 * to the top edge of this view. 4441 * {@hide} 4442 */ 4443 @ViewDebug.ExportedProperty(category = "layout") 4444 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4445 protected int mTop; 4446 /** 4447 * The distance in pixels from the top edge of this view's parent 4448 * to the bottom edge of this view. 4449 * {@hide} 4450 */ 4451 @ViewDebug.ExportedProperty(category = "layout") 4452 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4453 protected int mBottom; 4454 4455 /** 4456 * The offset, in pixels, by which the content of this view is scrolled 4457 * horizontally. 4458 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4459 * accessing these directly. 4460 * {@hide} 4461 */ 4462 @ViewDebug.ExportedProperty(category = "scrolling") 4463 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4464 protected int mScrollX; 4465 /** 4466 * The offset, in pixels, by which the content of this view is scrolled 4467 * vertically. 4468 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4469 * accessing these directly. 4470 * {@hide} 4471 */ 4472 @ViewDebug.ExportedProperty(category = "scrolling") 4473 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4474 protected int mScrollY; 4475 4476 /** 4477 * The final computed left padding in pixels that is used for drawing. This is the distance in 4478 * pixels between the left edge of this view and the left edge of its content. 4479 * {@hide} 4480 */ 4481 @ViewDebug.ExportedProperty(category = "padding") 4482 @UnsupportedAppUsage 4483 protected int mPaddingLeft = 0; 4484 /** 4485 * The final computed right padding in pixels that is used for drawing. This is the distance in 4486 * pixels between the right edge of this view and the right edge of its content. 4487 * {@hide} 4488 */ 4489 @ViewDebug.ExportedProperty(category = "padding") 4490 @UnsupportedAppUsage 4491 protected int mPaddingRight = 0; 4492 /** 4493 * The final computed top padding in pixels that is used for drawing. This is the distance in 4494 * pixels between the top edge of this view and the top edge of its content. 4495 * {@hide} 4496 */ 4497 @ViewDebug.ExportedProperty(category = "padding") 4498 @UnsupportedAppUsage 4499 protected int mPaddingTop; 4500 /** 4501 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4502 * pixels between the bottom edge of this view and the bottom edge of its content. 4503 * {@hide} 4504 */ 4505 @ViewDebug.ExportedProperty(category = "padding") 4506 @UnsupportedAppUsage 4507 protected int mPaddingBottom; 4508 4509 /** 4510 * The layout insets in pixels, that is the distance in pixels between the 4511 * visible edges of this view its bounds. 4512 */ 4513 private Insets mLayoutInsets; 4514 4515 /** 4516 * Briefly describes the state of the view and is primarily used for accessibility support. 4517 */ 4518 private CharSequence mStateDescription; 4519 4520 /** 4521 * Briefly describes the view and is primarily used for accessibility support. 4522 */ 4523 private CharSequence mContentDescription; 4524 4525 /** 4526 * If this view represents a distinct part of the window, it can have a title that labels the 4527 * area. 4528 */ 4529 private CharSequence mAccessibilityPaneTitle; 4530 4531 /** 4532 * Specifies the id of a view for which this view serves as a label for 4533 * accessibility purposes. 4534 */ 4535 private int mLabelForId = View.NO_ID; 4536 4537 /** 4538 * Predicate for matching labeled view id with its label for 4539 * accessibility purposes. 4540 */ 4541 private MatchLabelForPredicate mMatchLabelForPredicate; 4542 4543 /** 4544 * Specifies a view before which this one is visited in accessibility traversal. 4545 */ 4546 private int mAccessibilityTraversalBeforeId = NO_ID; 4547 4548 /** 4549 * Specifies a view after which this one is visited in accessibility traversal. 4550 */ 4551 private int mAccessibilityTraversalAfterId = NO_ID; 4552 4553 /** 4554 * Predicate for matching a view by its id. 4555 */ 4556 private MatchIdPredicate mMatchIdPredicate; 4557 4558 /** 4559 * The right padding after RTL resolution, but before taking account of scroll bars. 4560 * 4561 * @hide 4562 */ 4563 @ViewDebug.ExportedProperty(category = "padding") 4564 protected int mUserPaddingRight; 4565 4566 /** 4567 * The resolved bottom padding before taking account of scroll bars. 4568 * 4569 * @hide 4570 */ 4571 @ViewDebug.ExportedProperty(category = "padding") 4572 protected int mUserPaddingBottom; 4573 4574 /** 4575 * The left padding after RTL resolution, but before taking account of scroll bars. 4576 * 4577 * @hide 4578 */ 4579 @ViewDebug.ExportedProperty(category = "padding") 4580 protected int mUserPaddingLeft; 4581 4582 /** 4583 * Cache the paddingStart set by the user to append to the scrollbar's size. 4584 * 4585 */ 4586 @ViewDebug.ExportedProperty(category = "padding") 4587 int mUserPaddingStart; 4588 4589 /** 4590 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4591 * 4592 */ 4593 @ViewDebug.ExportedProperty(category = "padding") 4594 int mUserPaddingEnd; 4595 4596 /** 4597 * The left padding as set by a setter method, a background's padding, or via XML property 4598 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4599 * 4600 * @hide 4601 */ 4602 int mUserPaddingLeftInitial; 4603 4604 /** 4605 * The right padding as set by a setter method, a background's padding, or via XML property 4606 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4607 * 4608 * @hide 4609 */ 4610 int mUserPaddingRightInitial; 4611 4612 /** 4613 * Default undefined padding 4614 */ 4615 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4616 4617 /** 4618 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4619 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4620 */ 4621 private boolean mLeftPaddingDefined = false; 4622 4623 /** 4624 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4625 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4626 */ 4627 private boolean mRightPaddingDefined = false; 4628 4629 /** 4630 * @hide 4631 */ 4632 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4633 /** 4634 * @hide 4635 */ 4636 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4637 4638 private LongSparseLongArray mMeasureCache; 4639 4640 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4641 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4642 private Drawable mBackground; 4643 private TintInfo mBackgroundTint; 4644 4645 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4646 private ForegroundInfo mForegroundInfo; 4647 4648 private Drawable mScrollIndicatorDrawable; 4649 4650 /** 4651 * RenderNode used for backgrounds. 4652 * <p> 4653 * When non-null and valid, this is expected to contain an up-to-date copy 4654 * of the background drawable. It is cleared on temporary detach, and reset 4655 * on cleanup. 4656 * @hide 4657 */ 4658 RenderNode mBackgroundRenderNode; 4659 4660 @UnsupportedAppUsage 4661 private int mBackgroundResource; 4662 private boolean mBackgroundSizeChanged; 4663 4664 /** The default focus highlight. 4665 * @see #mDefaultFocusHighlightEnabled 4666 * @see Drawable#hasFocusStateSpecified() 4667 */ 4668 private Drawable mDefaultFocusHighlight; 4669 private Drawable mDefaultFocusHighlightCache; 4670 private boolean mDefaultFocusHighlightSizeChanged; 4671 /** 4672 * True if the default focus highlight is needed on the target device. 4673 */ 4674 private static boolean sUseDefaultFocusHighlight; 4675 4676 /** 4677 * True if zero-sized views can be focused. 4678 */ 4679 private static boolean sCanFocusZeroSized; 4680 4681 /** 4682 * Always assign focus if a focusable View is available. 4683 */ 4684 private static boolean sAlwaysAssignFocus; 4685 4686 private String mTransitionName; 4687 4688 static class TintInfo { 4689 ColorStateList mTintList; 4690 BlendMode mBlendMode; 4691 boolean mHasTintMode; 4692 boolean mHasTintList; 4693 } 4694 4695 private static class ForegroundInfo { 4696 private Drawable mDrawable; 4697 private TintInfo mTintInfo; 4698 private int mGravity = Gravity.FILL; 4699 private boolean mInsidePadding = true; 4700 private boolean mBoundsChanged = true; 4701 private final Rect mSelfBounds = new Rect(); 4702 private final Rect mOverlayBounds = new Rect(); 4703 } 4704 4705 static class ListenerInfo { 4706 4707 @UnsupportedAppUsage ListenerInfo()4708 ListenerInfo() { 4709 } 4710 4711 /** 4712 * Listener used to dispatch focus change events. 4713 * This field should be made private, so it is hidden from the SDK. 4714 * {@hide} 4715 */ 4716 @UnsupportedAppUsage 4717 protected OnFocusChangeListener mOnFocusChangeListener; 4718 4719 /** 4720 * Listeners for layout change events. 4721 */ 4722 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4723 4724 protected OnScrollChangeListener mOnScrollChangeListener; 4725 4726 /** 4727 * Listeners for attach events. 4728 */ 4729 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4730 4731 /** 4732 * Listener used to dispatch click events. 4733 * This field should be made private, so it is hidden from the SDK. 4734 * {@hide} 4735 */ 4736 @UnsupportedAppUsage 4737 public OnClickListener mOnClickListener; 4738 4739 /** 4740 * Listener used to dispatch long click events. 4741 * This field should be made private, so it is hidden from the SDK. 4742 * {@hide} 4743 */ 4744 @UnsupportedAppUsage 4745 protected OnLongClickListener mOnLongClickListener; 4746 4747 /** 4748 * Listener used to dispatch context click events. This field should be made private, so it 4749 * is hidden from the SDK. 4750 * {@hide} 4751 */ 4752 protected OnContextClickListener mOnContextClickListener; 4753 4754 /** 4755 * Listener used to build the context menu. 4756 * This field should be made private, so it is hidden from the SDK. 4757 * {@hide} 4758 */ 4759 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4760 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4761 4762 @UnsupportedAppUsage 4763 private OnKeyListener mOnKeyListener; 4764 4765 @UnsupportedAppUsage 4766 private OnTouchListener mOnTouchListener; 4767 4768 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4769 private OnHoverListener mOnHoverListener; 4770 4771 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4772 private OnGenericMotionListener mOnGenericMotionListener; 4773 4774 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4775 private OnDragListener mOnDragListener; 4776 4777 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4778 4779 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4780 4781 OnCapturedPointerListener mOnCapturedPointerListener; 4782 4783 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4784 4785 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 4786 4787 /** 4788 * This lives here since it's only valid for interactive views. This list is null 4789 * until its first use. 4790 */ 4791 private List<Rect> mSystemGestureExclusionRects = null; 4792 private List<Rect> mKeepClearRects = null; 4793 private List<Rect> mUnrestrictedKeepClearRects = null; 4794 private boolean mPreferKeepClear = false; 4795 private Rect mHandwritingArea = null; 4796 4797 /** 4798 * Used to track {@link #mSystemGestureExclusionRects}, {@link #mKeepClearRects} and 4799 * {@link #mHandwritingArea}. 4800 */ 4801 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4802 private Runnable mPositionChangedUpdate; 4803 4804 /** 4805 * Allows the application to implement custom scroll capture support. 4806 */ 4807 ScrollCaptureCallback mScrollCaptureCallback; 4808 4809 @Nullable 4810 private OnReceiveContentListener mOnReceiveContentListener; 4811 } 4812 4813 @UnsupportedAppUsage 4814 ListenerInfo mListenerInfo; 4815 4816 private static class TooltipInfo { 4817 /** 4818 * Text to be displayed in a tooltip popup. 4819 */ 4820 @Nullable 4821 CharSequence mTooltipText; 4822 4823 /** 4824 * View-relative position of the tooltip anchor point. 4825 */ 4826 int mAnchorX; 4827 int mAnchorY; 4828 4829 /** 4830 * The tooltip popup. 4831 */ 4832 @Nullable 4833 TooltipPopup mTooltipPopup; 4834 4835 /** 4836 * Set to true if the tooltip was shown as a result of a long click. 4837 */ 4838 boolean mTooltipFromLongClick; 4839 4840 /** 4841 * Keep these Runnables so that they can be used to reschedule. 4842 */ 4843 Runnable mShowTooltipRunnable; 4844 Runnable mHideTooltipRunnable; 4845 4846 /** 4847 * Hover move is ignored if it is within this distance in pixels from the previous one. 4848 */ 4849 int mHoverSlop; 4850 4851 /** 4852 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4853 * different from the previously stored position. Ignoring insignificant changes 4854 * filters out the jitter which is typical for such input sources as stylus. 4855 * 4856 * @return True if the position has been updated. 4857 */ updateAnchorPos(MotionEvent event)4858 private boolean updateAnchorPos(MotionEvent event) { 4859 final int newAnchorX = (int) event.getX(); 4860 final int newAnchorY = (int) event.getY(); 4861 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4862 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4863 return false; 4864 } 4865 mAnchorX = newAnchorX; 4866 mAnchorY = newAnchorY; 4867 return true; 4868 } 4869 4870 /** 4871 * Clear the anchor position to ensure that the next change is considered significant. 4872 */ clearAnchorPos()4873 private void clearAnchorPos() { 4874 mAnchorX = Integer.MAX_VALUE; 4875 mAnchorY = Integer.MAX_VALUE; 4876 } 4877 } 4878 4879 TooltipInfo mTooltipInfo; 4880 4881 // Temporary values used to hold (x,y) coordinates when delegating from the 4882 // two-arg performLongClick() method to the legacy no-arg version. 4883 private float mLongClickX = Float.NaN; 4884 private float mLongClickY = Float.NaN; 4885 4886 /** 4887 * The application environment this view lives in. 4888 * This field should be made private, so it is hidden from the SDK. 4889 * {@hide} 4890 */ 4891 @ViewDebug.ExportedProperty(deepExport = true) 4892 @UnsupportedAppUsage 4893 @UiContext 4894 protected Context mContext; 4895 4896 @UnsupportedAppUsage 4897 private final Resources mResources; 4898 4899 @UnsupportedAppUsage 4900 private ScrollabilityCache mScrollCache; 4901 4902 private int[] mDrawableState = null; 4903 4904 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4905 4906 /** 4907 * Animator that automatically runs based on state changes. 4908 */ 4909 private StateListAnimator mStateListAnimator; 4910 4911 /** 4912 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4913 * the user may specify which view to go to next. 4914 */ 4915 private int mNextFocusLeftId = View.NO_ID; 4916 4917 /** 4918 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4919 * the user may specify which view to go to next. 4920 */ 4921 private int mNextFocusRightId = View.NO_ID; 4922 4923 /** 4924 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4925 * the user may specify which view to go to next. 4926 */ 4927 private int mNextFocusUpId = View.NO_ID; 4928 4929 /** 4930 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4931 * the user may specify which view to go to next. 4932 */ 4933 private int mNextFocusDownId = View.NO_ID; 4934 4935 /** 4936 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4937 * the user may specify which view to go to next. 4938 */ 4939 int mNextFocusForwardId = View.NO_ID; 4940 4941 /** 4942 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4943 * 4944 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4945 */ 4946 int mNextClusterForwardId = View.NO_ID; 4947 4948 /** 4949 * Whether this View should use a default focus highlight when it gets focused but doesn't 4950 * have {@link android.R.attr#state_focused} defined in its background. 4951 */ 4952 boolean mDefaultFocusHighlightEnabled = true; 4953 4954 private CheckForLongPress mPendingCheckForLongPress; 4955 @UnsupportedAppUsage 4956 private CheckForTap mPendingCheckForTap = null; 4957 private PerformClick mPerformClick; 4958 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4959 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 4960 private UnsetPressedState mUnsetPressedState; 4961 4962 /** 4963 * Whether the long press's action has been invoked. The tap's action is invoked on the 4964 * up event while a long press is invoked as soon as the long press duration is reached, so 4965 * a long press could be performed before the tap is checked, in which case the tap's action 4966 * should not be invoked. 4967 */ 4968 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4969 private boolean mHasPerformedLongPress; 4970 4971 /** 4972 * Whether a context click button is currently pressed down. This is true when the stylus is 4973 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4974 * pressed. This is false once the button is released or if the stylus has been lifted. 4975 */ 4976 private boolean mInContextButtonPress; 4977 4978 /** 4979 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4980 * true after a stylus button press has occured, when the next up event should not be recognized 4981 * as a tap. 4982 */ 4983 private boolean mIgnoreNextUpEvent; 4984 4985 /** 4986 * The minimum height of the view. We'll try our best to have the height 4987 * of this view to at least this amount. 4988 */ 4989 @ViewDebug.ExportedProperty(category = "measurement") 4990 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4991 private int mMinHeight; 4992 4993 /** 4994 * The minimum width of the view. We'll try our best to have the width 4995 * of this view to at least this amount. 4996 */ 4997 @ViewDebug.ExportedProperty(category = "measurement") 4998 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4999 private int mMinWidth; 5000 5001 /** 5002 * The delegate to handle touch events that are physically in this view 5003 * but should be handled by another view. 5004 */ 5005 private TouchDelegate mTouchDelegate = null; 5006 5007 /** 5008 * While touch exploration is in use, set to true when hovering across boundaries and 5009 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 5010 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 5011 * {@link MotionEvent#ACTION_HOVER_EXIT}. 5012 * Note that children of view group are excluded in the touch area. 5013 * @see #dispatchTouchExplorationHoverEvent 5014 */ 5015 private boolean mHoveringTouchDelegate = false; 5016 5017 /** 5018 * Solid color to use as a background when creating the drawing cache. Enables 5019 * the cache to use 16 bit bitmaps instead of 32 bit. 5020 */ 5021 private int mDrawingCacheBackgroundColor = 0; 5022 5023 /** 5024 * Special tree observer used when mAttachInfo is null. 5025 */ 5026 private ViewTreeObserver mFloatingTreeObserver; 5027 5028 /** 5029 * Cache the touch slop from the context that created the view. 5030 */ 5031 private int mTouchSlop; 5032 5033 /** 5034 * Cache the ambiguous gesture multiplier from the context that created the view. 5035 */ 5036 private float mAmbiguousGestureMultiplier; 5037 5038 /** 5039 * Object that handles automatic animation of view properties. 5040 */ 5041 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5042 private ViewPropertyAnimator mAnimator = null; 5043 5044 /** 5045 * List of registered FrameMetricsObservers. 5046 */ 5047 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 5048 5049 /** 5050 * Flag indicating that a drag can cross window boundaries. When 5051 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5052 * with this flag set, all visible applications with targetSdkVersion >= 5053 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 5054 * in the drag operation and receive the dragged content. 5055 * 5056 * <p>If this is the only flag set, then the drag recipient will only have access to text data 5057 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 5058 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 5059 */ 5060 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 5061 5062 /** 5063 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5064 * request read access to the content URI(s) contained in the {@link ClipData} object. 5065 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5066 */ 5067 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5068 5069 /** 5070 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5071 * request write access to the content URI(s) contained in the {@link ClipData} object. 5072 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5073 */ 5074 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5075 5076 /** 5077 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5078 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5079 * reboots until explicitly revoked with 5080 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5081 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5082 */ 5083 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5084 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5085 5086 /** 5087 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5088 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5089 * match against the original granted URI. 5090 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5091 */ 5092 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5093 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5094 5095 /** 5096 * Flag indicating that the drag shadow will be opaque. When 5097 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5098 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5099 */ 5100 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5101 5102 /** 5103 * Flag indicating that the drag was initiated with 5104 * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. When 5105 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called, this 5106 * is used by the system to perform a drag without animations. 5107 */ 5108 public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; 5109 5110 /** 5111 * Flag indicating that the caller desires to take ownership of the drag surface for handling 5112 * the animation associated with an unhandled drag. It is mainly useful if the view starting 5113 * a global drag changes visibility during the gesture and the default animation of animating 5114 * the surface back to the origin is not sufficient. 5115 * 5116 * The calling app must hold the {@link android.Manifest.permission#START_TASKS_FROM_RECENTS} 5117 * permission and will receive the drag surface as a part of 5118 * {@link action.view.DragEvent#ACTION_DRAG_ENDED} only if the drag event's 5119 * {@link action.view.DragEvent#getDragResult()} is {@code false}. The caller is responsible 5120 * for removing the surface after its animation. 5121 * 5122 * This flag has no effect if the system decides that a cancel-drag animation does not need to 5123 * occur. 5124 * @hide 5125 */ 5126 public static final int DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION = 1 << 11; 5127 5128 /** 5129 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5130 */ 5131 private float mVerticalScrollFactor; 5132 5133 /** 5134 * Position of the vertical scroll bar. 5135 */ 5136 @UnsupportedAppUsage 5137 private int mVerticalScrollbarPosition; 5138 5139 /** 5140 * Position the scroll bar at the default position as determined by the system. 5141 */ 5142 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5143 5144 /** 5145 * Position the scroll bar along the left edge. 5146 */ 5147 public static final int SCROLLBAR_POSITION_LEFT = 1; 5148 5149 /** 5150 * Position the scroll bar along the right edge. 5151 */ 5152 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5153 5154 /** 5155 * Indicates that the view does not have a layer. 5156 * 5157 * @see #getLayerType() 5158 * @see #setLayerType(int, android.graphics.Paint) 5159 * @see #LAYER_TYPE_SOFTWARE 5160 * @see #LAYER_TYPE_HARDWARE 5161 */ 5162 public static final int LAYER_TYPE_NONE = 0; 5163 5164 /** 5165 * <p>Indicates that the view has a software layer. A software layer is backed 5166 * by a bitmap and causes the view to be rendered using Android's software 5167 * rendering pipeline, even if hardware acceleration is enabled.</p> 5168 * 5169 * <p>Software layers have various usages:</p> 5170 * <p>When the application is not using hardware acceleration, a software layer 5171 * is useful to apply a specific color filter and/or blending mode and/or 5172 * translucency to a view and all its children.</p> 5173 * <p>When the application is using hardware acceleration, a software layer 5174 * is useful to render drawing primitives not supported by the hardware 5175 * accelerated pipeline. It can also be used to cache a complex view tree 5176 * into a texture and reduce the complexity of drawing operations. For instance, 5177 * when animating a complex view tree with a translation, a software layer can 5178 * be used to render the view tree only once.</p> 5179 * <p>Software layers should be avoided when the affected view tree updates 5180 * often. Every update will require to re-render the software layer, which can 5181 * potentially be slow (particularly when hardware acceleration is turned on 5182 * since the layer will have to be uploaded into a hardware texture after every 5183 * update.)</p> 5184 * 5185 * @see #getLayerType() 5186 * @see #setLayerType(int, android.graphics.Paint) 5187 * @see #LAYER_TYPE_NONE 5188 * @see #LAYER_TYPE_HARDWARE 5189 */ 5190 public static final int LAYER_TYPE_SOFTWARE = 1; 5191 5192 /** 5193 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5194 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5195 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5196 * rendering pipeline, but only if hardware acceleration is turned on for the 5197 * view hierarchy. When hardware acceleration is turned off, hardware layers 5198 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5199 * 5200 * <p>A hardware layer is useful to apply a specific color filter and/or 5201 * blending mode and/or translucency to a view and all its children.</p> 5202 * <p>A hardware layer can be used to cache a complex view tree into a 5203 * texture and reduce the complexity of drawing operations. For instance, 5204 * when animating a complex view tree with a translation, a hardware layer can 5205 * be used to render the view tree only once.</p> 5206 * <p>A hardware layer can also be used to increase the rendering quality when 5207 * rotation transformations are applied on a view. It can also be used to 5208 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5209 * 5210 * @see #getLayerType() 5211 * @see #setLayerType(int, android.graphics.Paint) 5212 * @see #LAYER_TYPE_NONE 5213 * @see #LAYER_TYPE_SOFTWARE 5214 */ 5215 public static final int LAYER_TYPE_HARDWARE = 2; 5216 5217 /** @hide */ 5218 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5219 LAYER_TYPE_NONE, 5220 LAYER_TYPE_SOFTWARE, 5221 LAYER_TYPE_HARDWARE 5222 }) 5223 @Retention(RetentionPolicy.SOURCE) 5224 public @interface LayerType {} 5225 5226 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 5227 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 5228 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 5229 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 5230 }) 5231 int mLayerType = LAYER_TYPE_NONE; 5232 Paint mLayerPaint; 5233 5234 /** 5235 * Set to true when drawing cache is enabled and cannot be created. 5236 * 5237 * @hide 5238 */ 5239 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5240 public boolean mCachingFailed; 5241 @UnsupportedAppUsage 5242 private Bitmap mDrawingCache; 5243 @UnsupportedAppUsage 5244 private Bitmap mUnscaledDrawingCache; 5245 5246 /** 5247 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5248 * <p> 5249 * When non-null and valid, this is expected to contain an up-to-date copy 5250 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5251 * cleanup. 5252 */ 5253 @UnsupportedAppUsage 5254 final RenderNode mRenderNode; 5255 5256 /** 5257 * Set to true when the view is sending hover accessibility events because it 5258 * is the innermost hovered view. 5259 */ 5260 private boolean mSendingHoverAccessibilityEvents; 5261 5262 /** 5263 * Delegate for injecting accessibility functionality. 5264 */ 5265 @UnsupportedAppUsage 5266 AccessibilityDelegate mAccessibilityDelegate; 5267 5268 /** 5269 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5270 * and add/remove objects to/from the overlay directly through the Overlay methods. 5271 */ 5272 ViewOverlay mOverlay; 5273 5274 /** 5275 * The currently active parent view for receiving delegated nested scrolling events. 5276 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5277 * by {@link #stopNestedScroll()} at the same point where we clear 5278 * requestDisallowInterceptTouchEvent. 5279 */ 5280 private ViewParent mNestedScrollingParent; 5281 5282 /** 5283 * Consistency verifier for debugging purposes. 5284 * @hide 5285 */ 5286 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5287 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5288 new InputEventConsistencyVerifier(this, 0) : null; 5289 5290 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5291 5292 private int[] mTempNestedScrollConsumed; 5293 5294 /** 5295 * An overlay is going to draw this View instead of being drawn as part of this 5296 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5297 * when this view is invalidated. 5298 */ 5299 GhostView mGhostView; 5300 5301 /** 5302 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5303 * @hide 5304 */ 5305 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5306 public String[] mAttributes; 5307 5308 /** 5309 * Maps a Resource id to its name. 5310 */ 5311 private static SparseArray<String> mAttributeMap; 5312 5313 /** 5314 * Queue of pending runnables. Used to postpone calls to post() until this 5315 * view is attached and has a handler. 5316 */ 5317 private HandlerActionQueue mRunQueue; 5318 5319 /** 5320 * The pointer icon when the mouse hovers on this view. The default is null. 5321 */ 5322 private PointerIcon mPointerIcon; 5323 5324 /** 5325 * @hide 5326 */ 5327 @UnsupportedAppUsage 5328 String mStartActivityRequestWho; 5329 5330 @Nullable 5331 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5332 5333 /** Used to delay visibility updates sent to the autofill manager */ 5334 private Handler mVisibilityChangeForAutofillHandler; 5335 5336 /** 5337 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5338 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5339 */ 5340 @Nullable 5341 private ContentCaptureSession mContentCaptureSession; 5342 5343 /** 5344 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5345 */ 5346 private boolean mContentCaptureSessionCached; 5347 5348 @LayoutRes 5349 private int mSourceLayoutId = ID_NULL; 5350 5351 @Nullable 5352 private SparseIntArray mAttributeSourceResId; 5353 5354 @Nullable 5355 private SparseArray<int[]> mAttributeResolutionStacks; 5356 5357 @StyleRes 5358 private int mExplicitStyle; 5359 5360 /** 5361 * Specifies which input source classes should provide unbuffered input events to this view 5362 * 5363 * @see View#requestUnbufferedDispatch(int) 5364 */ 5365 @InputSourceClass 5366 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5367 5368 @Nullable 5369 private String[] mReceiveContentMimeTypes; 5370 5371 @Nullable 5372 private ViewTranslationCallback mViewTranslationCallback; 5373 5374 @Nullable 5375 5376 private ViewTranslationResponse mViewTranslationResponse; 5377 5378 /** 5379 * Simple constructor to use when creating a view from code. 5380 * 5381 * @param context The Context the view is running in, through which it can 5382 * access the current theme, resources, etc. 5383 */ View(Context context)5384 public View(Context context) { 5385 mContext = context; 5386 mResources = context != null ? context.getResources() : null; 5387 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5388 // Set some flags defaults 5389 mPrivateFlags2 = 5390 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5391 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5392 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5393 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5394 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5395 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5396 mPrivateFlags4 = PFLAG4_AUTO_HANDWRITING_ENABLED; 5397 5398 final ViewConfiguration configuration = ViewConfiguration.get(context); 5399 mTouchSlop = configuration.getScaledTouchSlop(); 5400 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5401 5402 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5403 mUserPaddingStart = UNDEFINED_PADDING; 5404 mUserPaddingEnd = UNDEFINED_PADDING; 5405 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5406 5407 if (!sCompatibilityDone && context != null) { 5408 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5409 5410 // Older apps may need this compatibility hack for measurement. 5411 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5412 5413 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5414 // of whether a layout was requested on that View. 5415 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 5416 5417 // In M and newer, our widgets can pass a "hint" value in the size 5418 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 5419 // know what the expected parent size is going to be, so e.g. list items can size 5420 // themselves at 1/3 the size of their container. It breaks older apps though, 5421 // specifically apps that use some popular open source libraries. 5422 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 5423 5424 // Old versions of the platform would give different results from 5425 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5426 // modes, so we always need to run an additional EXACTLY pass. 5427 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5428 5429 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5430 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5431 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5432 5433 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5434 // in apps so we target check it to avoid breaking existing apps. 5435 sPreserveMarginParamsInLayoutParamConversion = 5436 targetSdkVersion >= Build.VERSION_CODES.N; 5437 5438 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5439 5440 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5441 5442 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5443 5444 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5445 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5446 5447 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5448 5449 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5450 5451 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5452 5453 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5454 5455 sBrokenInsetsDispatch = targetSdkVersion < Build.VERSION_CODES.R; 5456 5457 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5458 5459 GradientDrawable.sWrapNegativeAngleMeasurements = 5460 targetSdkVersion >= Build.VERSION_CODES.Q; 5461 5462 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5463 5464 sCompatibilityDone = true; 5465 } 5466 } 5467 5468 /** 5469 * Constructor that is called when inflating a view from XML. This is called 5470 * when a view is being constructed from an XML file, supplying attributes 5471 * that were specified in the XML file. This version uses a default style of 5472 * 0, so the only attribute values applied are those in the Context's Theme 5473 * and the given AttributeSet. 5474 * 5475 * <p> 5476 * The method onFinishInflate() will be called after all children have been 5477 * added. 5478 * 5479 * @param context The Context the view is running in, through which it can 5480 * access the current theme, resources, etc. 5481 * @param attrs The attributes of the XML tag that is inflating the view. 5482 * @see #View(Context, AttributeSet, int) 5483 */ 5484 public View(Context context, @Nullable AttributeSet attrs) { 5485 this(context, attrs, 0); 5486 } 5487 5488 /** 5489 * Perform inflation from XML and apply a class-specific base style from a 5490 * theme attribute. This constructor of View allows subclasses to use their 5491 * own base style when they are inflating. For example, a Button class's 5492 * constructor would call this version of the super class constructor and 5493 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5494 * allows the theme's button style to modify all of the base view attributes 5495 * (in particular its background) as well as the Button class's attributes. 5496 * 5497 * @param context The Context the view is running in, through which it can 5498 * access the current theme, resources, etc. 5499 * @param attrs The attributes of the XML tag that is inflating the view. 5500 * @param defStyleAttr An attribute in the current theme that contains a 5501 * reference to a style resource that supplies default values for 5502 * the view. Can be 0 to not look for defaults. 5503 * @see #View(Context, AttributeSet) 5504 */ 5505 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5506 this(context, attrs, defStyleAttr, 0); 5507 } 5508 5509 /** 5510 * Perform inflation from XML and apply a class-specific base style from a 5511 * theme attribute or style resource. This constructor of View allows 5512 * subclasses to use their own base style when they are inflating. 5513 * <p> 5514 * When determining the final value of a particular attribute, there are 5515 * four inputs that come into play: 5516 * <ol> 5517 * <li>Any attribute values in the given AttributeSet. 5518 * <li>The style resource specified in the AttributeSet (named "style"). 5519 * <li>The default style specified by <var>defStyleAttr</var>. 5520 * <li>The default style specified by <var>defStyleRes</var>. 5521 * <li>The base values in this theme. 5522 * </ol> 5523 * <p> 5524 * Each of these inputs is considered in-order, with the first listed taking 5525 * precedence over the following ones. In other words, if in the 5526 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5527 * , then the button's text will <em>always</em> be black, regardless of 5528 * what is specified in any of the styles. 5529 * 5530 * @param context The Context the view is running in, through which it can 5531 * access the current theme, resources, etc. 5532 * @param attrs The attributes of the XML tag that is inflating the view. 5533 * @param defStyleAttr An attribute in the current theme that contains a 5534 * reference to a style resource that supplies default values for 5535 * the view. Can be 0 to not look for defaults. 5536 * @param defStyleRes A resource identifier of a style resource that 5537 * supplies default values for the view, used only if 5538 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5539 * to not look for defaults. 5540 * @see #View(Context, AttributeSet, int) 5541 */ 5542 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5543 this(context); 5544 5545 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5546 5547 final TypedArray a = context.obtainStyledAttributes( 5548 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5549 5550 retrieveExplicitStyle(context.getTheme(), attrs); 5551 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5552 defStyleAttr, defStyleRes); 5553 5554 if (sDebugViewAttributes) { 5555 saveAttributeData(attrs, a); 5556 } 5557 5558 Drawable background = null; 5559 5560 int leftPadding = -1; 5561 int topPadding = -1; 5562 int rightPadding = -1; 5563 int bottomPadding = -1; 5564 int startPadding = UNDEFINED_PADDING; 5565 int endPadding = UNDEFINED_PADDING; 5566 5567 int padding = -1; 5568 int paddingHorizontal = -1; 5569 int paddingVertical = -1; 5570 5571 int viewFlagValues = 0; 5572 int viewFlagMasks = 0; 5573 5574 boolean setScrollContainer = false; 5575 5576 int x = 0; 5577 int y = 0; 5578 5579 float tx = 0; 5580 float ty = 0; 5581 float tz = 0; 5582 float elevation = 0; 5583 float rotation = 0; 5584 float rotationX = 0; 5585 float rotationY = 0; 5586 float sx = 1f; 5587 float sy = 1f; 5588 boolean transformSet = false; 5589 5590 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5591 int overScrollMode = mOverScrollMode; 5592 boolean initializeScrollbars = false; 5593 boolean initializeScrollIndicators = false; 5594 5595 boolean startPaddingDefined = false; 5596 boolean endPaddingDefined = false; 5597 boolean leftPaddingDefined = false; 5598 boolean rightPaddingDefined = false; 5599 5600 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5601 5602 // Set default values. 5603 viewFlagValues |= FOCUSABLE_AUTO; 5604 viewFlagMasks |= FOCUSABLE_AUTO; 5605 5606 final int N = a.getIndexCount(); 5607 for (int i = 0; i < N; i++) { 5608 int attr = a.getIndex(i); 5609 switch (attr) { 5610 case com.android.internal.R.styleable.View_background: 5611 background = a.getDrawable(attr); 5612 break; 5613 case com.android.internal.R.styleable.View_padding: 5614 padding = a.getDimensionPixelSize(attr, -1); 5615 mUserPaddingLeftInitial = padding; 5616 mUserPaddingRightInitial = padding; 5617 leftPaddingDefined = true; 5618 rightPaddingDefined = true; 5619 break; 5620 case com.android.internal.R.styleable.View_paddingHorizontal: 5621 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5622 mUserPaddingLeftInitial = paddingHorizontal; 5623 mUserPaddingRightInitial = paddingHorizontal; 5624 leftPaddingDefined = true; 5625 rightPaddingDefined = true; 5626 break; 5627 case com.android.internal.R.styleable.View_paddingVertical: 5628 paddingVertical = a.getDimensionPixelSize(attr, -1); 5629 break; 5630 case com.android.internal.R.styleable.View_paddingLeft: 5631 leftPadding = a.getDimensionPixelSize(attr, -1); 5632 mUserPaddingLeftInitial = leftPadding; 5633 leftPaddingDefined = true; 5634 break; 5635 case com.android.internal.R.styleable.View_paddingTop: 5636 topPadding = a.getDimensionPixelSize(attr, -1); 5637 break; 5638 case com.android.internal.R.styleable.View_paddingRight: 5639 rightPadding = a.getDimensionPixelSize(attr, -1); 5640 mUserPaddingRightInitial = rightPadding; 5641 rightPaddingDefined = true; 5642 break; 5643 case com.android.internal.R.styleable.View_paddingBottom: 5644 bottomPadding = a.getDimensionPixelSize(attr, -1); 5645 break; 5646 case com.android.internal.R.styleable.View_paddingStart: 5647 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5648 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5649 break; 5650 case com.android.internal.R.styleable.View_paddingEnd: 5651 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5652 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5653 break; 5654 case com.android.internal.R.styleable.View_scrollX: 5655 x = a.getDimensionPixelOffset(attr, 0); 5656 break; 5657 case com.android.internal.R.styleable.View_scrollY: 5658 y = a.getDimensionPixelOffset(attr, 0); 5659 break; 5660 case com.android.internal.R.styleable.View_alpha: 5661 setAlpha(a.getFloat(attr, 1f)); 5662 break; 5663 case com.android.internal.R.styleable.View_transformPivotX: 5664 setPivotX(a.getDimension(attr, 0)); 5665 break; 5666 case com.android.internal.R.styleable.View_transformPivotY: 5667 setPivotY(a.getDimension(attr, 0)); 5668 break; 5669 case com.android.internal.R.styleable.View_translationX: 5670 tx = a.getDimension(attr, 0); 5671 transformSet = true; 5672 break; 5673 case com.android.internal.R.styleable.View_translationY: 5674 ty = a.getDimension(attr, 0); 5675 transformSet = true; 5676 break; 5677 case com.android.internal.R.styleable.View_translationZ: 5678 tz = a.getDimension(attr, 0); 5679 transformSet = true; 5680 break; 5681 case com.android.internal.R.styleable.View_elevation: 5682 elevation = a.getDimension(attr, 0); 5683 transformSet = true; 5684 break; 5685 case com.android.internal.R.styleable.View_rotation: 5686 rotation = a.getFloat(attr, 0); 5687 transformSet = true; 5688 break; 5689 case com.android.internal.R.styleable.View_rotationX: 5690 rotationX = a.getFloat(attr, 0); 5691 transformSet = true; 5692 break; 5693 case com.android.internal.R.styleable.View_rotationY: 5694 rotationY = a.getFloat(attr, 0); 5695 transformSet = true; 5696 break; 5697 case com.android.internal.R.styleable.View_scaleX: 5698 sx = a.getFloat(attr, 1f); 5699 transformSet = true; 5700 break; 5701 case com.android.internal.R.styleable.View_scaleY: 5702 sy = a.getFloat(attr, 1f); 5703 transformSet = true; 5704 break; 5705 case com.android.internal.R.styleable.View_id: 5706 mID = a.getResourceId(attr, NO_ID); 5707 break; 5708 case com.android.internal.R.styleable.View_tag: 5709 mTag = a.getText(attr); 5710 break; 5711 case com.android.internal.R.styleable.View_fitsSystemWindows: 5712 if (a.getBoolean(attr, false)) { 5713 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5714 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5715 } 5716 break; 5717 case com.android.internal.R.styleable.View_focusable: 5718 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5719 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5720 viewFlagMasks |= FOCUSABLE_MASK; 5721 } 5722 break; 5723 case com.android.internal.R.styleable.View_focusableInTouchMode: 5724 if (a.getBoolean(attr, false)) { 5725 // unset auto focus since focusableInTouchMode implies explicit focusable 5726 viewFlagValues &= ~FOCUSABLE_AUTO; 5727 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5728 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5729 } 5730 break; 5731 case com.android.internal.R.styleable.View_clickable: 5732 if (a.getBoolean(attr, false)) { 5733 viewFlagValues |= CLICKABLE; 5734 viewFlagMasks |= CLICKABLE; 5735 } 5736 break; 5737 case com.android.internal.R.styleable.View_allowClickWhenDisabled: 5738 setAllowClickWhenDisabled(a.getBoolean(attr, false)); 5739 break; 5740 case com.android.internal.R.styleable.View_longClickable: 5741 if (a.getBoolean(attr, false)) { 5742 viewFlagValues |= LONG_CLICKABLE; 5743 viewFlagMasks |= LONG_CLICKABLE; 5744 } 5745 break; 5746 case com.android.internal.R.styleable.View_contextClickable: 5747 if (a.getBoolean(attr, false)) { 5748 viewFlagValues |= CONTEXT_CLICKABLE; 5749 viewFlagMasks |= CONTEXT_CLICKABLE; 5750 } 5751 break; 5752 case com.android.internal.R.styleable.View_saveEnabled: 5753 if (!a.getBoolean(attr, true)) { 5754 viewFlagValues |= SAVE_DISABLED; 5755 viewFlagMasks |= SAVE_DISABLED_MASK; 5756 } 5757 break; 5758 case com.android.internal.R.styleable.View_duplicateParentState: 5759 if (a.getBoolean(attr, false)) { 5760 viewFlagValues |= DUPLICATE_PARENT_STATE; 5761 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5762 } 5763 break; 5764 case com.android.internal.R.styleable.View_visibility: 5765 final int visibility = a.getInt(attr, 0); 5766 if (visibility != 0) { 5767 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5768 viewFlagMasks |= VISIBILITY_MASK; 5769 } 5770 break; 5771 case com.android.internal.R.styleable.View_layoutDirection: 5772 // Clear any layout direction flags (included resolved bits) already set 5773 mPrivateFlags2 &= 5774 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5775 // Set the layout direction flags depending on the value of the attribute 5776 final int layoutDirection = a.getInt(attr, -1); 5777 final int value = (layoutDirection != -1) ? 5778 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5779 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5780 break; 5781 case com.android.internal.R.styleable.View_drawingCacheQuality: 5782 final int cacheQuality = a.getInt(attr, 0); 5783 if (cacheQuality != 0) { 5784 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5785 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5786 } 5787 break; 5788 case com.android.internal.R.styleable.View_contentDescription: 5789 setContentDescription(a.getString(attr)); 5790 break; 5791 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5792 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5793 break; 5794 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5795 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5796 break; 5797 case com.android.internal.R.styleable.View_labelFor: 5798 setLabelFor(a.getResourceId(attr, NO_ID)); 5799 break; 5800 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5801 if (!a.getBoolean(attr, true)) { 5802 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5803 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5804 } 5805 break; 5806 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5807 if (!a.getBoolean(attr, true)) { 5808 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5809 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5810 } 5811 break; 5812 case R.styleable.View_scrollbars: 5813 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5814 if (scrollbars != SCROLLBARS_NONE) { 5815 viewFlagValues |= scrollbars; 5816 viewFlagMasks |= SCROLLBARS_MASK; 5817 initializeScrollbars = true; 5818 } 5819 break; 5820 //noinspection deprecation 5821 case R.styleable.View_fadingEdge: 5822 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5823 // Ignore the attribute starting with ICS 5824 break; 5825 } 5826 // With builds < ICS, fall through and apply fading edges 5827 case R.styleable.View_requiresFadingEdge: 5828 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5829 if (fadingEdge != FADING_EDGE_NONE) { 5830 viewFlagValues |= fadingEdge; 5831 viewFlagMasks |= FADING_EDGE_MASK; 5832 initializeFadingEdgeInternal(a); 5833 } 5834 break; 5835 case R.styleable.View_scrollbarStyle: 5836 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5837 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5838 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5839 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5840 } 5841 break; 5842 case R.styleable.View_isScrollContainer: 5843 setScrollContainer = true; 5844 if (a.getBoolean(attr, false)) { 5845 setScrollContainer(true); 5846 } 5847 break; 5848 case com.android.internal.R.styleable.View_keepScreenOn: 5849 if (a.getBoolean(attr, false)) { 5850 viewFlagValues |= KEEP_SCREEN_ON; 5851 viewFlagMasks |= KEEP_SCREEN_ON; 5852 } 5853 break; 5854 case R.styleable.View_filterTouchesWhenObscured: 5855 if (a.getBoolean(attr, false)) { 5856 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5857 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5858 } 5859 break; 5860 case R.styleable.View_nextFocusLeft: 5861 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5862 break; 5863 case R.styleable.View_nextFocusRight: 5864 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5865 break; 5866 case R.styleable.View_nextFocusUp: 5867 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5868 break; 5869 case R.styleable.View_nextFocusDown: 5870 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5871 break; 5872 case R.styleable.View_nextFocusForward: 5873 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5874 break; 5875 case R.styleable.View_nextClusterForward: 5876 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5877 break; 5878 case R.styleable.View_minWidth: 5879 mMinWidth = a.getDimensionPixelSize(attr, 0); 5880 break; 5881 case R.styleable.View_minHeight: 5882 mMinHeight = a.getDimensionPixelSize(attr, 0); 5883 break; 5884 case R.styleable.View_onClick: 5885 if (context.isRestricted()) { 5886 throw new IllegalStateException("The android:onClick attribute cannot " 5887 + "be used within a restricted context"); 5888 } 5889 5890 final String handlerName = a.getString(attr); 5891 if (handlerName != null) { 5892 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5893 } 5894 break; 5895 case R.styleable.View_overScrollMode: 5896 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5897 break; 5898 case R.styleable.View_verticalScrollbarPosition: 5899 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5900 break; 5901 case R.styleable.View_layerType: 5902 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5903 break; 5904 case R.styleable.View_textDirection: 5905 // Clear any text direction flag already set 5906 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5907 // Set the text direction flags depending on the value of the attribute 5908 final int textDirection = a.getInt(attr, -1); 5909 if (textDirection != -1) { 5910 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5911 } 5912 break; 5913 case R.styleable.View_textAlignment: 5914 // Clear any text alignment flag already set 5915 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5916 // Set the text alignment flag depending on the value of the attribute 5917 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5918 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5919 break; 5920 case R.styleable.View_importantForAccessibility: 5921 setImportantForAccessibility(a.getInt(attr, 5922 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5923 break; 5924 case R.styleable.View_accessibilityLiveRegion: 5925 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5926 break; 5927 case R.styleable.View_transitionName: 5928 setTransitionName(a.getString(attr)); 5929 break; 5930 case R.styleable.View_nestedScrollingEnabled: 5931 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5932 break; 5933 case R.styleable.View_stateListAnimator: 5934 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5935 a.getResourceId(attr, 0))); 5936 break; 5937 case R.styleable.View_backgroundTint: 5938 // This will get applied later during setBackground(). 5939 if (mBackgroundTint == null) { 5940 mBackgroundTint = new TintInfo(); 5941 } 5942 mBackgroundTint.mTintList = a.getColorStateList( 5943 R.styleable.View_backgroundTint); 5944 mBackgroundTint.mHasTintList = true; 5945 break; 5946 case R.styleable.View_backgroundTintMode: 5947 // This will get applied later during setBackground(). 5948 if (mBackgroundTint == null) { 5949 mBackgroundTint = new TintInfo(); 5950 } 5951 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 5952 R.styleable.View_backgroundTintMode, -1), null); 5953 mBackgroundTint.mHasTintMode = true; 5954 break; 5955 case R.styleable.View_outlineProvider: 5956 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5957 PROVIDER_BACKGROUND)); 5958 break; 5959 case R.styleable.View_foreground: 5960 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5961 setForeground(a.getDrawable(attr)); 5962 } 5963 break; 5964 case R.styleable.View_foregroundGravity: 5965 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5966 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5967 } 5968 break; 5969 case R.styleable.View_foregroundTintMode: 5970 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5971 setForegroundTintBlendMode( 5972 Drawable.parseBlendMode(a.getInt(attr, -1), 5973 null)); 5974 } 5975 break; 5976 case R.styleable.View_foregroundTint: 5977 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5978 setForegroundTintList(a.getColorStateList(attr)); 5979 } 5980 break; 5981 case R.styleable.View_foregroundInsidePadding: 5982 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5983 if (mForegroundInfo == null) { 5984 mForegroundInfo = new ForegroundInfo(); 5985 } 5986 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5987 mForegroundInfo.mInsidePadding); 5988 } 5989 break; 5990 case R.styleable.View_scrollIndicators: 5991 final int scrollIndicators = 5992 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5993 & SCROLL_INDICATORS_PFLAG3_MASK; 5994 if (scrollIndicators != 0) { 5995 mPrivateFlags3 |= scrollIndicators; 5996 initializeScrollIndicators = true; 5997 } 5998 break; 5999 case R.styleable.View_pointerIcon: 6000 final int resourceId = a.getResourceId(attr, 0); 6001 if (resourceId != 0) { 6002 setPointerIcon(PointerIcon.load( 6003 context.getResources(), resourceId)); 6004 } else { 6005 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 6006 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 6007 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 6008 } 6009 } 6010 break; 6011 case R.styleable.View_forceHasOverlappingRendering: 6012 if (a.peekValue(attr) != null) { 6013 forceHasOverlappingRendering(a.getBoolean(attr, true)); 6014 } 6015 break; 6016 case R.styleable.View_tooltipText: 6017 setTooltipText(a.getText(attr)); 6018 break; 6019 case R.styleable.View_keyboardNavigationCluster: 6020 if (a.peekValue(attr) != null) { 6021 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 6022 } 6023 break; 6024 case R.styleable.View_focusedByDefault: 6025 if (a.peekValue(attr) != null) { 6026 setFocusedByDefault(a.getBoolean(attr, true)); 6027 } 6028 break; 6029 case R.styleable.View_autofillHints: 6030 if (a.peekValue(attr) != null) { 6031 CharSequence[] rawHints = null; 6032 String rawString = null; 6033 6034 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 6035 int resId = a.getResourceId(attr, 0); 6036 6037 try { 6038 rawHints = a.getTextArray(attr); 6039 } catch (Resources.NotFoundException e) { 6040 rawString = getResources().getString(resId); 6041 } 6042 } else { 6043 rawString = a.getString(attr); 6044 } 6045 6046 if (rawHints == null) { 6047 if (rawString == null) { 6048 throw new IllegalArgumentException( 6049 "Could not resolve autofillHints"); 6050 } else { 6051 rawHints = rawString.split(","); 6052 } 6053 } 6054 6055 String[] hints = new String[rawHints.length]; 6056 6057 int numHints = rawHints.length; 6058 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 6059 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 6060 } 6061 setAutofillHints(hints); 6062 } 6063 break; 6064 case R.styleable.View_importantForAutofill: 6065 if (a.peekValue(attr) != null) { 6066 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 6067 } 6068 break; 6069 case R.styleable.View_importantForContentCapture: 6070 if (a.peekValue(attr) != null) { 6071 setImportantForContentCapture(a.getInt(attr, 6072 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 6073 } 6074 case R.styleable.View_defaultFocusHighlightEnabled: 6075 if (a.peekValue(attr) != null) { 6076 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 6077 } 6078 break; 6079 case R.styleable.View_screenReaderFocusable: 6080 if (a.peekValue(attr) != null) { 6081 setScreenReaderFocusable(a.getBoolean(attr, false)); 6082 } 6083 break; 6084 case R.styleable.View_accessibilityPaneTitle: 6085 if (a.peekValue(attr) != null) { 6086 setAccessibilityPaneTitle(a.getString(attr)); 6087 } 6088 break; 6089 case R.styleable.View_outlineSpotShadowColor: 6090 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6091 break; 6092 case R.styleable.View_outlineAmbientShadowColor: 6093 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6094 break; 6095 case com.android.internal.R.styleable.View_accessibilityHeading: 6096 setAccessibilityHeading(a.getBoolean(attr, false)); 6097 break; 6098 case R.styleable.View_forceDarkAllowed: 6099 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6100 break; 6101 case R.styleable.View_scrollCaptureHint: 6102 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6103 break; 6104 case R.styleable.View_clipToOutline: 6105 setClipToOutline(a.getBoolean(attr, false)); 6106 break; 6107 case R.styleable.View_preferKeepClear: 6108 setPreferKeepClear(a.getBoolean(attr, false)); 6109 break; 6110 case R.styleable.View_autoHandwritingEnabled: 6111 setAutoHandwritingEnabled(a.getBoolean(attr, true)); 6112 break; 6113 } 6114 } 6115 6116 setOverScrollMode(overScrollMode); 6117 6118 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6119 // the resolved layout direction). Those cached values will be used later during padding 6120 // resolution. 6121 mUserPaddingStart = startPadding; 6122 mUserPaddingEnd = endPadding; 6123 6124 if (background != null) { 6125 setBackground(background); 6126 } 6127 6128 // setBackground above will record that padding is currently provided by the background. 6129 // If we have padding specified via xml, record that here instead and use it. 6130 mLeftPaddingDefined = leftPaddingDefined; 6131 mRightPaddingDefined = rightPaddingDefined; 6132 6133 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6134 // bottomPadding, and padding set by background. Valid padding beats everything. 6135 if (padding >= 0) { 6136 leftPadding = padding; 6137 topPadding = padding; 6138 rightPadding = padding; 6139 bottomPadding = padding; 6140 mUserPaddingLeftInitial = padding; 6141 mUserPaddingRightInitial = padding; 6142 } else { 6143 if (paddingHorizontal >= 0) { 6144 leftPadding = paddingHorizontal; 6145 rightPadding = paddingHorizontal; 6146 mUserPaddingLeftInitial = paddingHorizontal; 6147 mUserPaddingRightInitial = paddingHorizontal; 6148 } 6149 if (paddingVertical >= 0) { 6150 topPadding = paddingVertical; 6151 bottomPadding = paddingVertical; 6152 } 6153 } 6154 6155 if (isRtlCompatibilityMode()) { 6156 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6157 // left / right padding are used if defined (meaning here nothing to do). If they are not 6158 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6159 // start / end and resolve them as left / right (layout direction is not taken into account). 6160 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6161 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6162 // defined. 6163 if (!mLeftPaddingDefined && startPaddingDefined) { 6164 leftPadding = startPadding; 6165 } 6166 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6167 if (!mRightPaddingDefined && endPaddingDefined) { 6168 rightPadding = endPadding; 6169 } 6170 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6171 } else { 6172 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6173 // values defined. Otherwise, left /right values are used. 6174 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6175 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6176 // defined. 6177 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6178 6179 if (mLeftPaddingDefined && !hasRelativePadding) { 6180 mUserPaddingLeftInitial = leftPadding; 6181 } 6182 if (mRightPaddingDefined && !hasRelativePadding) { 6183 mUserPaddingRightInitial = rightPadding; 6184 } 6185 } 6186 6187 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6188 // them on if topPadding or bottomPadding are not valid. 6189 internalSetPadding( 6190 mUserPaddingLeftInitial, 6191 topPadding >= 0 ? topPadding : mPaddingTop, 6192 mUserPaddingRightInitial, 6193 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6194 6195 if (viewFlagMasks != 0) { 6196 setFlags(viewFlagValues, viewFlagMasks); 6197 } 6198 6199 if (initializeScrollbars) { 6200 initializeScrollbarsInternal(a); 6201 } 6202 6203 if (initializeScrollIndicators) { 6204 initializeScrollIndicatorsInternal(); 6205 } 6206 6207 a.recycle(); 6208 6209 // Needs to be called after mViewFlags is set 6210 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6211 recomputePadding(); 6212 } 6213 6214 if (x != 0 || y != 0) { 6215 scrollTo(x, y); 6216 } 6217 6218 if (transformSet) { 6219 setTranslationX(tx); 6220 setTranslationY(ty); 6221 setTranslationZ(tz); 6222 setElevation(elevation); 6223 setRotation(rotation); 6224 setRotationX(rotationX); 6225 setRotationY(rotationY); 6226 setScaleX(sx); 6227 setScaleY(sy); 6228 } 6229 6230 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6231 setScrollContainer(true); 6232 } 6233 6234 computeOpaqueFlags(); 6235 } 6236 6237 /** 6238 * Returns the ordered list of resource ID that are considered when resolving attribute values 6239 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6240 * XML. It will also include a set of explicit styles if specified in XML using 6241 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6242 * 6243 * <p> 6244 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6245 * is enabled in Android developer options. 6246 * 6247 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6248 * @return ordered list of resource ID that are considered when resolving attribute values for 6249 * this {@link View}. 6250 */ 6251 @NonNull 6252 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6253 if (!sDebugViewAttributes 6254 || mAttributeResolutionStacks == null 6255 || mAttributeResolutionStacks.get(attribute) == null) { 6256 return new int[0]; 6257 } 6258 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6259 int stackSize = attributeResolutionStack.length; 6260 if (mSourceLayoutId != ID_NULL) { 6261 stackSize++; 6262 } 6263 6264 int currentIndex = 0; 6265 int[] stack = new int[stackSize]; 6266 6267 if (mSourceLayoutId != ID_NULL) { 6268 stack[currentIndex] = mSourceLayoutId; 6269 currentIndex++; 6270 } 6271 for (int i = 0; i < attributeResolutionStack.length; i++) { 6272 stack[currentIndex] = attributeResolutionStack[i]; 6273 currentIndex++; 6274 } 6275 return stack; 6276 } 6277 6278 /** 6279 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6280 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6281 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6282 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6283 * 6284 * <p> 6285 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6286 * is enabled in Android developer options. 6287 * 6288 * @return mapping of attribute resource ID to source resource ID where the attribute value 6289 * was set. 6290 */ 6291 @NonNull 6292 @SuppressWarnings("AndroidFrameworkEfficientCollections") 6293 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6294 HashMap<Integer, Integer> map = new HashMap<>(); 6295 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6296 return map; 6297 } 6298 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6299 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6300 } 6301 return map; 6302 } 6303 6304 /** 6305 * Returns the resource ID for the style specified using {@code style="..."} in the 6306 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6307 * specified or otherwise not applicable. 6308 * <p> 6309 * Each {@link View} can have an explicit style specified in the layout file. 6310 * This style is used first during the {@link View} attribute resolution, then if an attribute 6311 * is not defined there the resource system looks at default style and theme as fallbacks. 6312 * 6313 * <p> 6314 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6315 * is enabled in Android developer options. 6316 * 6317 * @return The resource ID for the style specified using {@code style="..."} in the 6318 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6319 * if not specified or otherwise not applicable. 6320 */ 6321 @StyleRes 6322 public int getExplicitStyle() { 6323 if (!sDebugViewAttributes) { 6324 return ID_NULL; 6325 } 6326 return mExplicitStyle; 6327 } 6328 6329 /** 6330 * An implementation of OnClickListener that attempts to lazily load a 6331 * named click handling method from a parent or ancestor context. 6332 */ 6333 private static class DeclaredOnClickListener implements OnClickListener { 6334 private final View mHostView; 6335 private final String mMethodName; 6336 6337 private Method mResolvedMethod; 6338 private Context mResolvedContext; 6339 6340 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6341 mHostView = hostView; 6342 mMethodName = methodName; 6343 } 6344 6345 @Override 6346 public void onClick(@NonNull View v) { 6347 if (mResolvedMethod == null) { 6348 resolveMethod(mHostView.getContext(), mMethodName); 6349 } 6350 6351 try { 6352 mResolvedMethod.invoke(mResolvedContext, v); 6353 } catch (IllegalAccessException e) { 6354 throw new IllegalStateException( 6355 "Could not execute non-public method for android:onClick", e); 6356 } catch (InvocationTargetException e) { 6357 throw new IllegalStateException( 6358 "Could not execute method for android:onClick", e); 6359 } 6360 } 6361 6362 @NonNull 6363 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6364 while (context != null) { 6365 try { 6366 if (!context.isRestricted()) { 6367 final Method method = context.getClass().getMethod(mMethodName, View.class); 6368 if (method != null) { 6369 mResolvedMethod = method; 6370 mResolvedContext = context; 6371 return; 6372 } 6373 } 6374 } catch (NoSuchMethodException e) { 6375 // Failed to find method, keep searching up the hierarchy. 6376 } 6377 6378 if (context instanceof ContextWrapper) { 6379 context = ((ContextWrapper) context).getBaseContext(); 6380 } else { 6381 // Can't search up the hierarchy, null out and fail. 6382 context = null; 6383 } 6384 } 6385 6386 final int id = mHostView.getId(); 6387 final String idText = id == NO_ID ? "" : " with id '" 6388 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6389 throw new IllegalStateException("Could not find method " + mMethodName 6390 + "(View) in a parent or ancestor Context for android:onClick " 6391 + "attribute defined on view " + mHostView.getClass() + idText); 6392 } 6393 } 6394 6395 /** 6396 * Non-public constructor for use in testing 6397 */ 6398 @UnsupportedAppUsage 6399 View() { 6400 mResources = null; 6401 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6402 } 6403 6404 /** 6405 * Returns {@code true} when the View is attached and the system developer setting to show 6406 * the layout bounds is enabled or {@code false} otherwise. 6407 */ 6408 public final boolean isShowingLayoutBounds() { 6409 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6410 } 6411 6412 /** 6413 * Used to test isShowingLayoutBounds(). This sets the local value used 6414 * by that function. This method does nothing if the layout isn't attached. 6415 * 6416 * @hide 6417 */ 6418 @TestApi 6419 public final void setShowingLayoutBounds(boolean debugLayout) { 6420 if (mAttachInfo != null) { 6421 mAttachInfo.mDebugLayout = debugLayout; 6422 } 6423 } 6424 6425 private static SparseArray<String> getAttributeMap() { 6426 if (mAttributeMap == null) { 6427 mAttributeMap = new SparseArray<>(); 6428 } 6429 return mAttributeMap; 6430 } 6431 6432 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6433 @Nullable AttributeSet attrs) { 6434 if (!sDebugViewAttributes) { 6435 return; 6436 } 6437 mExplicitStyle = theme.getExplicitStyle(attrs); 6438 } 6439 6440 /** 6441 * Stores debugging information about attributes. This should be called in a constructor by 6442 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6443 * then the custom attributes used by this view will not be visible in layout inspection tools. 6444 * 6445 * @param context Context under which this view is created. 6446 * @param styleable A reference to styleable array R.styleable.Foo 6447 * @param attrs AttributeSet used to construct this view. 6448 * @param t Resolved {@link TypedArray} returned by a call to 6449 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6450 * @param defStyleAttr Default style attribute passed into the view constructor. 6451 * @param defStyleRes Default style resource passed into the view constructor. 6452 */ 6453 public final void saveAttributeDataForStyleable(@NonNull Context context, 6454 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6455 int defStyleAttr, int defStyleRes) { 6456 if (!sDebugViewAttributes) { 6457 return; 6458 } 6459 6460 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6461 defStyleAttr, defStyleRes, mExplicitStyle); 6462 6463 if (mAttributeResolutionStacks == null) { 6464 mAttributeResolutionStacks = new SparseArray<>(); 6465 } 6466 6467 if (mAttributeSourceResId == null) { 6468 mAttributeSourceResId = new SparseIntArray(); 6469 } 6470 6471 final int indexCount = t.getIndexCount(); 6472 for (int j = 0; j < indexCount; ++j) { 6473 final int index = t.getIndex(j); 6474 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6475 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6476 } 6477 } 6478 6479 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6480 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6481 final int indexCount = t.getIndexCount(); 6482 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6483 6484 int i = 0; 6485 6486 // Store raw XML attributes. 6487 for (int j = 0; j < attrsCount; ++j) { 6488 attributes[i] = attrs.getAttributeName(j); 6489 attributes[i + 1] = attrs.getAttributeValue(j); 6490 i += 2; 6491 } 6492 6493 // Store resolved styleable attributes. 6494 final Resources res = t.getResources(); 6495 final SparseArray<String> attributeMap = getAttributeMap(); 6496 for (int j = 0; j < indexCount; ++j) { 6497 final int index = t.getIndex(j); 6498 if (!t.hasValueOrEmpty(index)) { 6499 // Value is undefined. Skip it. 6500 continue; 6501 } 6502 6503 final int resourceId = t.getResourceId(index, 0); 6504 if (resourceId == 0) { 6505 // Value is not a reference. Skip it. 6506 continue; 6507 } 6508 6509 String resourceName = attributeMap.get(resourceId); 6510 if (resourceName == null) { 6511 try { 6512 resourceName = res.getResourceName(resourceId); 6513 } catch (Resources.NotFoundException e) { 6514 resourceName = "0x" + Integer.toHexString(resourceId); 6515 } 6516 attributeMap.put(resourceId, resourceName); 6517 } 6518 6519 attributes[i] = resourceName; 6520 attributes[i + 1] = t.getString(index); 6521 i += 2; 6522 } 6523 6524 // Trim to fit contents. 6525 final String[] trimmed = new String[i]; 6526 System.arraycopy(attributes, 0, trimmed, 0, i); 6527 mAttributes = trimmed; 6528 } 6529 6530 @Override 6531 public String toString() { 6532 StringBuilder out = new StringBuilder(256); 6533 out.append(getClass().getName()); 6534 out.append('{'); 6535 out.append(Integer.toHexString(System.identityHashCode(this))); 6536 out.append(' '); 6537 switch (mViewFlags&VISIBILITY_MASK) { 6538 case VISIBLE: out.append('V'); break; 6539 case INVISIBLE: out.append('I'); break; 6540 case GONE: out.append('G'); break; 6541 default: out.append('.'); break; 6542 } 6543 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6544 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6545 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6546 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6547 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6548 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6549 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6550 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6551 out.append(' '); 6552 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6553 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6554 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6555 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6556 out.append('p'); 6557 } else { 6558 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6559 } 6560 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6561 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6562 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6563 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6564 out.append(' '); 6565 out.append(mLeft); 6566 out.append(','); 6567 out.append(mTop); 6568 out.append('-'); 6569 out.append(mRight); 6570 out.append(','); 6571 out.append(mBottom); 6572 appendId(out); 6573 if (mAutofillId != null) { 6574 out.append(" aid="); out.append(mAutofillId); 6575 } 6576 out.append("}"); 6577 return out.toString(); 6578 } 6579 6580 void appendId(StringBuilder out) { 6581 final int id = getId(); 6582 if (id != NO_ID) { 6583 out.append(" #"); 6584 out.append(Integer.toHexString(id)); 6585 final Resources r = mResources; 6586 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6587 try { 6588 String pkgname; 6589 switch (id&0xff000000) { 6590 case 0x7f000000: 6591 pkgname="app"; 6592 break; 6593 case 0x01000000: 6594 pkgname="android"; 6595 break; 6596 default: 6597 pkgname = r.getResourcePackageName(id); 6598 break; 6599 } 6600 String typename = r.getResourceTypeName(id); 6601 String entryname = r.getResourceEntryName(id); 6602 out.append(" "); 6603 out.append(pkgname); 6604 out.append(":"); 6605 out.append(typename); 6606 out.append("/"); 6607 out.append(entryname); 6608 } catch (Resources.NotFoundException e) { 6609 } 6610 } 6611 } 6612 } 6613 6614 /** 6615 * <p> 6616 * Initializes the fading edges from a given set of styled attributes. This 6617 * method should be called by subclasses that need fading edges and when an 6618 * instance of these subclasses is created programmatically rather than 6619 * being inflated from XML. This method is automatically called when the XML 6620 * is inflated. 6621 * </p> 6622 * 6623 * @param a the styled attributes set to initialize the fading edges from 6624 * 6625 * @removed 6626 */ 6627 protected void initializeFadingEdge(TypedArray a) { 6628 // This method probably shouldn't have been included in the SDK to begin with. 6629 // It relies on 'a' having been initialized using an attribute filter array that is 6630 // not publicly available to the SDK. The old method has been renamed 6631 // to initializeFadingEdgeInternal and hidden for framework use only; 6632 // this one initializes using defaults to make it safe to call for apps. 6633 6634 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6635 6636 initializeFadingEdgeInternal(arr); 6637 6638 arr.recycle(); 6639 } 6640 6641 /** 6642 * <p> 6643 * Initializes the fading edges from a given set of styled attributes. This 6644 * method should be called by subclasses that need fading edges and when an 6645 * instance of these subclasses is created programmatically rather than 6646 * being inflated from XML. This method is automatically called when the XML 6647 * is inflated. 6648 * </p> 6649 * 6650 * @param a the styled attributes set to initialize the fading edges from 6651 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6652 */ 6653 protected void initializeFadingEdgeInternal(TypedArray a) { 6654 initScrollCache(); 6655 6656 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6657 R.styleable.View_fadingEdgeLength, 6658 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6659 } 6660 6661 /** 6662 * Returns the size of the vertical faded edges used to indicate that more 6663 * content in this view is visible. 6664 * 6665 * @return The size in pixels of the vertical faded edge or 0 if vertical 6666 * faded edges are not enabled for this view. 6667 * @attr ref android.R.styleable#View_fadingEdgeLength 6668 */ 6669 public int getVerticalFadingEdgeLength() { 6670 if (isVerticalFadingEdgeEnabled()) { 6671 ScrollabilityCache cache = mScrollCache; 6672 if (cache != null) { 6673 return cache.fadingEdgeLength; 6674 } 6675 } 6676 return 0; 6677 } 6678 6679 /** 6680 * Set the size of the faded edge used to indicate that more content in this 6681 * view is available. Will not change whether the fading edge is enabled; use 6682 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6683 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6684 * for the vertical or horizontal fading edges. 6685 * 6686 * @param length The size in pixels of the faded edge used to indicate that more 6687 * content in this view is visible. 6688 */ 6689 public void setFadingEdgeLength(int length) { 6690 initScrollCache(); 6691 mScrollCache.fadingEdgeLength = length; 6692 } 6693 6694 /** 6695 * Returns the size of the horizontal faded edges used to indicate that more 6696 * content in this view is visible. 6697 * 6698 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6699 * faded edges are not enabled for this view. 6700 * @attr ref android.R.styleable#View_fadingEdgeLength 6701 */ 6702 public int getHorizontalFadingEdgeLength() { 6703 if (isHorizontalFadingEdgeEnabled()) { 6704 ScrollabilityCache cache = mScrollCache; 6705 if (cache != null) { 6706 return cache.fadingEdgeLength; 6707 } 6708 } 6709 return 0; 6710 } 6711 6712 /** 6713 * Returns the width of the vertical scrollbar. 6714 * 6715 * @return The width in pixels of the vertical scrollbar or 0 if there 6716 * is no vertical scrollbar. 6717 */ 6718 public int getVerticalScrollbarWidth() { 6719 ScrollabilityCache cache = mScrollCache; 6720 if (cache != null) { 6721 ScrollBarDrawable scrollBar = cache.scrollBar; 6722 if (scrollBar != null) { 6723 int size = scrollBar.getSize(true); 6724 if (size <= 0) { 6725 size = cache.scrollBarSize; 6726 } 6727 return size; 6728 } 6729 return 0; 6730 } 6731 return 0; 6732 } 6733 6734 /** 6735 * Returns the height of the horizontal scrollbar. 6736 * 6737 * @return The height in pixels of the horizontal scrollbar or 0 if 6738 * there is no horizontal scrollbar. 6739 */ 6740 protected int getHorizontalScrollbarHeight() { 6741 ScrollabilityCache cache = mScrollCache; 6742 if (cache != null) { 6743 ScrollBarDrawable scrollBar = cache.scrollBar; 6744 if (scrollBar != null) { 6745 int size = scrollBar.getSize(false); 6746 if (size <= 0) { 6747 size = cache.scrollBarSize; 6748 } 6749 return size; 6750 } 6751 return 0; 6752 } 6753 return 0; 6754 } 6755 6756 /** 6757 * <p> 6758 * Initializes the scrollbars from a given set of styled attributes. This 6759 * method should be called by subclasses that need scrollbars and when an 6760 * instance of these subclasses is created programmatically rather than 6761 * being inflated from XML. This method is automatically called when the XML 6762 * is inflated. 6763 * </p> 6764 * 6765 * @param a the styled attributes set to initialize the scrollbars from 6766 * 6767 * @removed 6768 */ 6769 protected void initializeScrollbars(TypedArray a) { 6770 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6771 // using the View filter array which is not available to the SDK. As such, internal 6772 // framework usage now uses initializeScrollbarsInternal and we grab a default 6773 // TypedArray with the right filter instead here. 6774 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6775 6776 initializeScrollbarsInternal(arr); 6777 6778 // We ignored the method parameter. Recycle the one we actually did use. 6779 arr.recycle(); 6780 } 6781 6782 private void initializeScrollBarDrawable() { 6783 initScrollCache(); 6784 6785 if (mScrollCache.scrollBar == null) { 6786 mScrollCache.scrollBar = new ScrollBarDrawable(); 6787 mScrollCache.scrollBar.setState(getDrawableState()); 6788 mScrollCache.scrollBar.setCallback(this); 6789 } 6790 } 6791 6792 /** 6793 * <p> 6794 * Initializes the scrollbars from a given set of styled attributes. This 6795 * method should be called by subclasses that need scrollbars and when an 6796 * instance of these subclasses is created programmatically rather than 6797 * being inflated from XML. This method is automatically called when the XML 6798 * is inflated. 6799 * </p> 6800 * 6801 * @param a the styled attributes set to initialize the scrollbars from 6802 * @hide 6803 */ 6804 @UnsupportedAppUsage 6805 protected void initializeScrollbarsInternal(TypedArray a) { 6806 initScrollCache(); 6807 6808 final ScrollabilityCache scrollabilityCache = mScrollCache; 6809 6810 if (scrollabilityCache.scrollBar == null) { 6811 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6812 scrollabilityCache.scrollBar.setState(getDrawableState()); 6813 scrollabilityCache.scrollBar.setCallback(this); 6814 } 6815 6816 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6817 6818 if (!fadeScrollbars) { 6819 scrollabilityCache.state = ScrollabilityCache.ON; 6820 } 6821 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6822 6823 6824 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6825 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6826 .getScrollBarFadeDuration()); 6827 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6828 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6829 ViewConfiguration.getScrollDefaultDelay()); 6830 6831 6832 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6833 com.android.internal.R.styleable.View_scrollbarSize, 6834 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6835 6836 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6837 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6838 6839 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6840 if (thumb != null) { 6841 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6842 } 6843 6844 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6845 false); 6846 if (alwaysDraw) { 6847 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6848 } 6849 6850 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6851 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6852 6853 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6854 if (thumb != null) { 6855 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6856 } 6857 6858 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6859 false); 6860 if (alwaysDraw) { 6861 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6862 } 6863 6864 // Apply layout direction to the new Drawables if needed 6865 final int layoutDirection = getLayoutDirection(); 6866 if (track != null) { 6867 track.setLayoutDirection(layoutDirection); 6868 } 6869 if (thumb != null) { 6870 thumb.setLayoutDirection(layoutDirection); 6871 } 6872 6873 // Re-apply user/background padding so that scrollbar(s) get added 6874 resolvePadding(); 6875 } 6876 6877 /** 6878 * Defines the vertical scrollbar thumb drawable 6879 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6880 * 6881 * @see #awakenScrollBars(int) 6882 * @see #isVerticalScrollBarEnabled() 6883 * @see #setVerticalScrollBarEnabled(boolean) 6884 */ 6885 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6886 initializeScrollBarDrawable(); 6887 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 6888 } 6889 6890 /** 6891 * Defines the vertical scrollbar track drawable 6892 * @attr ref android.R.styleable#View_scrollbarTrackVertical 6893 * 6894 * @see #awakenScrollBars(int) 6895 * @see #isVerticalScrollBarEnabled() 6896 * @see #setVerticalScrollBarEnabled(boolean) 6897 */ 6898 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6899 initializeScrollBarDrawable(); 6900 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 6901 } 6902 6903 /** 6904 * Defines the horizontal thumb drawable 6905 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 6906 * 6907 * @see #awakenScrollBars(int) 6908 * @see #isHorizontalScrollBarEnabled() 6909 * @see #setHorizontalScrollBarEnabled(boolean) 6910 */ 6911 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6912 initializeScrollBarDrawable(); 6913 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 6914 } 6915 6916 /** 6917 * Defines the horizontal track drawable 6918 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 6919 * 6920 * @see #awakenScrollBars(int) 6921 * @see #isHorizontalScrollBarEnabled() 6922 * @see #setHorizontalScrollBarEnabled(boolean) 6923 */ 6924 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6925 initializeScrollBarDrawable(); 6926 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 6927 } 6928 6929 /** 6930 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 6931 * exists, null otherwise. 6932 * 6933 * @see #awakenScrollBars(int) 6934 * @see #isVerticalScrollBarEnabled() 6935 * @see #setVerticalScrollBarEnabled(boolean) 6936 */ 6937 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 6938 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 6939 } 6940 6941 /** 6942 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 6943 * exists, null otherwise. 6944 * 6945 * @see #awakenScrollBars(int) 6946 * @see #isVerticalScrollBarEnabled() 6947 * @see #setVerticalScrollBarEnabled(boolean) 6948 */ 6949 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 6950 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 6951 } 6952 6953 /** 6954 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 6955 * exists, null otherwise. 6956 * 6957 * @see #awakenScrollBars(int) 6958 * @see #isHorizontalScrollBarEnabled() 6959 * @see #setHorizontalScrollBarEnabled(boolean) 6960 */ 6961 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 6962 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 6963 } 6964 6965 /** 6966 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 6967 * exists, null otherwise. 6968 * 6969 * @see #awakenScrollBars(int) 6970 * @see #isHorizontalScrollBarEnabled() 6971 * @see #setHorizontalScrollBarEnabled(boolean) 6972 */ 6973 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 6974 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 6975 } 6976 6977 private void initializeScrollIndicatorsInternal() { 6978 // Some day maybe we'll break this into top/left/start/etc. and let the 6979 // client control it. Until then, you can have any scroll indicator you 6980 // want as long as it's a 1dp foreground-colored rectangle. 6981 if (mScrollIndicatorDrawable == null) { 6982 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6983 } 6984 } 6985 6986 /** 6987 * <p> 6988 * Initalizes the scrollability cache if necessary. 6989 * </p> 6990 */ 6991 private void initScrollCache() { 6992 if (mScrollCache == null) { 6993 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6994 } 6995 } 6996 6997 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 6998 private ScrollabilityCache getScrollCache() { 6999 initScrollCache(); 7000 return mScrollCache; 7001 } 7002 7003 /** 7004 * Set the position of the vertical scroll bar. Should be one of 7005 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 7006 * {@link #SCROLLBAR_POSITION_RIGHT}. 7007 * 7008 * @param position Where the vertical scroll bar should be positioned. 7009 */ 7010 public void setVerticalScrollbarPosition(int position) { 7011 if (mVerticalScrollbarPosition != position) { 7012 mVerticalScrollbarPosition = position; 7013 computeOpaqueFlags(); 7014 resolvePadding(); 7015 } 7016 } 7017 7018 /** 7019 * @return The position where the vertical scroll bar will show, if applicable. 7020 * @see #setVerticalScrollbarPosition(int) 7021 */ 7022 public int getVerticalScrollbarPosition() { 7023 return mVerticalScrollbarPosition; 7024 } 7025 7026 boolean isOnScrollbar(float x, float y) { 7027 if (mScrollCache == null) { 7028 return false; 7029 } 7030 x += getScrollX(); 7031 y += getScrollY(); 7032 final boolean canScrollVertically = 7033 computeVerticalScrollRange() > computeVerticalScrollExtent(); 7034 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 7035 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7036 getVerticalScrollBarBounds(null, touchBounds); 7037 if (touchBounds.contains((int) x, (int) y)) { 7038 return true; 7039 } 7040 } 7041 final boolean canScrollHorizontally = 7042 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 7043 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 7044 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7045 getHorizontalScrollBarBounds(null, touchBounds); 7046 if (touchBounds.contains((int) x, (int) y)) { 7047 return true; 7048 } 7049 } 7050 return false; 7051 } 7052 7053 @UnsupportedAppUsage 7054 boolean isOnScrollbarThumb(float x, float y) { 7055 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 7056 } 7057 7058 private boolean isOnVerticalScrollbarThumb(float x, float y) { 7059 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 7060 return false; 7061 } 7062 final int range = computeVerticalScrollRange(); 7063 final int extent = computeVerticalScrollExtent(); 7064 if (range > extent) { 7065 x += getScrollX(); 7066 y += getScrollY(); 7067 final Rect bounds = mScrollCache.mScrollBarBounds; 7068 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7069 getVerticalScrollBarBounds(bounds, touchBounds); 7070 final int offset = computeVerticalScrollOffset(); 7071 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 7072 extent, range); 7073 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 7074 extent, range, offset); 7075 final int thumbTop = bounds.top + thumbOffset; 7076 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7077 if (x >= touchBounds.left && x <= touchBounds.right 7078 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 7079 return true; 7080 } 7081 } 7082 return false; 7083 } 7084 7085 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 7086 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 7087 return false; 7088 } 7089 final int range = computeHorizontalScrollRange(); 7090 final int extent = computeHorizontalScrollExtent(); 7091 if (range > extent) { 7092 x += getScrollX(); 7093 y += getScrollY(); 7094 final Rect bounds = mScrollCache.mScrollBarBounds; 7095 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7096 getHorizontalScrollBarBounds(bounds, touchBounds); 7097 final int offset = computeHorizontalScrollOffset(); 7098 7099 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 7100 extent, range); 7101 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7102 extent, range, offset); 7103 final int thumbLeft = bounds.left + thumbOffset; 7104 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7105 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7106 && y >= touchBounds.top && y <= touchBounds.bottom) { 7107 return true; 7108 } 7109 } 7110 return false; 7111 } 7112 7113 @UnsupportedAppUsage 7114 boolean isDraggingScrollBar() { 7115 return mScrollCache != null 7116 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7117 } 7118 7119 /** 7120 * Sets the state of all scroll indicators. 7121 * <p> 7122 * See {@link #setScrollIndicators(int, int)} for usage information. 7123 * 7124 * @param indicators a bitmask of indicators that should be enabled, or 7125 * {@code 0} to disable all indicators 7126 * @see #setScrollIndicators(int, int) 7127 * @see #getScrollIndicators() 7128 * @attr ref android.R.styleable#View_scrollIndicators 7129 */ 7130 @RemotableViewMethod 7131 public void setScrollIndicators(@ScrollIndicators int indicators) { 7132 setScrollIndicators(indicators, 7133 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7134 } 7135 7136 /** 7137 * Sets the state of the scroll indicators specified by the mask. To change 7138 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7139 * <p> 7140 * When a scroll indicator is enabled, it will be displayed if the view 7141 * can scroll in the direction of the indicator. 7142 * <p> 7143 * Multiple indicator types may be enabled or disabled by passing the 7144 * logical OR of the desired types. If multiple types are specified, they 7145 * will all be set to the same enabled state. 7146 * <p> 7147 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7148 * 7149 * @param indicators the indicator direction, or the logical OR of multiple 7150 * indicator directions. One or more of: 7151 * <ul> 7152 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7153 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7154 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7155 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7156 * <li>{@link #SCROLL_INDICATOR_START}</li> 7157 * <li>{@link #SCROLL_INDICATOR_END}</li> 7158 * </ul> 7159 * @see #setScrollIndicators(int) 7160 * @see #getScrollIndicators() 7161 * @attr ref android.R.styleable#View_scrollIndicators 7162 */ 7163 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7164 // Shift and sanitize mask. 7165 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7166 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7167 7168 // Shift and mask indicators. 7169 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7170 indicators &= mask; 7171 7172 // Merge with non-masked flags. 7173 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7174 7175 if (mPrivateFlags3 != updatedFlags) { 7176 mPrivateFlags3 = updatedFlags; 7177 7178 if (indicators != 0) { 7179 initializeScrollIndicatorsInternal(); 7180 } 7181 invalidate(); 7182 } 7183 } 7184 7185 /** 7186 * Returns a bitmask representing the enabled scroll indicators. 7187 * <p> 7188 * For example, if the top and left scroll indicators are enabled and all 7189 * other indicators are disabled, the return value will be 7190 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7191 * <p> 7192 * To check whether the bottom scroll indicator is enabled, use the value 7193 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7194 * 7195 * @return a bitmask representing the enabled scroll indicators 7196 */ 7197 @InspectableProperty(flagMapping = { 7198 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7199 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7200 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7201 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7202 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7203 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7204 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7205 }) 7206 @ScrollIndicators 7207 public int getScrollIndicators() { 7208 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7209 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7210 } 7211 7212 @UnsupportedAppUsage 7213 ListenerInfo getListenerInfo() { 7214 if (mListenerInfo != null) { 7215 return mListenerInfo; 7216 } 7217 mListenerInfo = new ListenerInfo(); 7218 return mListenerInfo; 7219 } 7220 7221 /** 7222 * Register a callback to be invoked when the scroll X or Y positions of 7223 * this view change. 7224 * <p> 7225 * <b>Note:</b> Some views handle scrolling independently from View and may 7226 * have their own separate listeners for scroll-type events. For example, 7227 * {@link android.widget.ListView ListView} allows clients to register an 7228 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7229 * to listen for changes in list scroll position. 7230 * 7231 * @param l The listener to notify when the scroll X or Y position changes. 7232 * @see android.view.View#getScrollX() 7233 * @see android.view.View#getScrollY() 7234 */ 7235 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7236 getListenerInfo().mOnScrollChangeListener = l; 7237 } 7238 7239 /** 7240 * Register a callback to be invoked when focus of this view changed. 7241 * 7242 * @param l The callback that will run. 7243 */ 7244 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7245 getListenerInfo().mOnFocusChangeListener = l; 7246 } 7247 7248 /** 7249 * Add a listener that will be called when the bounds of the view change due to 7250 * layout processing. 7251 * 7252 * @param listener The listener that will be called when layout bounds change. 7253 */ 7254 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7255 ListenerInfo li = getListenerInfo(); 7256 if (li.mOnLayoutChangeListeners == null) { 7257 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7258 } 7259 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7260 li.mOnLayoutChangeListeners.add(listener); 7261 } 7262 } 7263 7264 /** 7265 * Remove a listener for layout changes. 7266 * 7267 * @param listener The listener for layout bounds change. 7268 */ 7269 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7270 ListenerInfo li = mListenerInfo; 7271 if (li == null || li.mOnLayoutChangeListeners == null) { 7272 return; 7273 } 7274 li.mOnLayoutChangeListeners.remove(listener); 7275 } 7276 7277 /** 7278 * Add a listener for attach state changes. 7279 * 7280 * This listener will be called whenever this view is attached or detached 7281 * from a window. Remove the listener using 7282 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7283 * 7284 * @param listener Listener to attach 7285 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7286 */ 7287 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7288 ListenerInfo li = getListenerInfo(); 7289 if (li.mOnAttachStateChangeListeners == null) { 7290 li.mOnAttachStateChangeListeners 7291 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7292 } 7293 li.mOnAttachStateChangeListeners.add(listener); 7294 } 7295 7296 /** 7297 * Remove a listener for attach state changes. The listener will receive no further 7298 * notification of window attach/detach events. 7299 * 7300 * @param listener Listener to remove 7301 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7302 */ 7303 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7304 ListenerInfo li = mListenerInfo; 7305 if (li == null || li.mOnAttachStateChangeListeners == null) { 7306 return; 7307 } 7308 li.mOnAttachStateChangeListeners.remove(listener); 7309 } 7310 7311 /** 7312 * Returns the focus-change callback registered for this view. 7313 * 7314 * @return The callback, or null if one is not registered. 7315 */ 7316 public OnFocusChangeListener getOnFocusChangeListener() { 7317 ListenerInfo li = mListenerInfo; 7318 return li != null ? li.mOnFocusChangeListener : null; 7319 } 7320 7321 /** 7322 * Register a callback to be invoked when this view is clicked. If this view is not 7323 * clickable, it becomes clickable. 7324 * 7325 * @param l The callback that will run 7326 * 7327 * @see #setClickable(boolean) 7328 */ 7329 public void setOnClickListener(@Nullable OnClickListener l) { 7330 if (!isClickable()) { 7331 setClickable(true); 7332 } 7333 getListenerInfo().mOnClickListener = l; 7334 } 7335 7336 /** 7337 * Return whether this view has an attached OnClickListener. Returns 7338 * true if there is a listener, false if there is none. 7339 */ 7340 public boolean hasOnClickListeners() { 7341 ListenerInfo li = mListenerInfo; 7342 return (li != null && li.mOnClickListener != null); 7343 } 7344 7345 /** 7346 * Register a callback to be invoked when this view is clicked and held. If this view is not 7347 * long clickable, it becomes long clickable. 7348 * 7349 * @param l The callback that will run 7350 * 7351 * @see #setLongClickable(boolean) 7352 */ 7353 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7354 if (!isLongClickable()) { 7355 setLongClickable(true); 7356 } 7357 getListenerInfo().mOnLongClickListener = l; 7358 } 7359 7360 /** 7361 * Return whether this view has an attached OnLongClickListener. Returns 7362 * true if there is a listener, false if there is none. 7363 */ 7364 public boolean hasOnLongClickListeners() { 7365 ListenerInfo li = mListenerInfo; 7366 return (li != null && li.mOnLongClickListener != null); 7367 } 7368 7369 /** 7370 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7371 * @hide 7372 */ 7373 @Nullable 7374 public OnLongClickListener getOnLongClickListener() { 7375 ListenerInfo li = mListenerInfo; 7376 return (li != null) ? li.mOnLongClickListener : null; 7377 } 7378 7379 /** 7380 * Register a callback to be invoked when this view is context clicked. If the view is not 7381 * context clickable, it becomes context clickable. 7382 * 7383 * @param l The callback that will run 7384 * @see #setContextClickable(boolean) 7385 */ 7386 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7387 if (!isContextClickable()) { 7388 setContextClickable(true); 7389 } 7390 getListenerInfo().mOnContextClickListener = l; 7391 } 7392 7393 /** 7394 * Register a callback to be invoked when the context menu for this view is 7395 * being built. If this view is not long clickable, it becomes long clickable. 7396 * 7397 * @param l The callback that will run 7398 * 7399 */ 7400 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7401 if (!isLongClickable()) { 7402 setLongClickable(true); 7403 } 7404 getListenerInfo().mOnCreateContextMenuListener = l; 7405 } 7406 7407 /** 7408 * Set an observer to collect stats for each frame rendered for this view. 7409 * 7410 * @hide 7411 */ 7412 public void addFrameMetricsListener(Window window, 7413 Window.OnFrameMetricsAvailableListener listener, 7414 Handler handler) { 7415 if (mAttachInfo != null) { 7416 if (mAttachInfo.mThreadedRenderer != null) { 7417 if (mFrameMetricsObservers == null) { 7418 mFrameMetricsObservers = new ArrayList<>(); 7419 } 7420 7421 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7422 mFrameMetricsObservers.add(fmo); 7423 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7424 } else { 7425 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7426 } 7427 } else { 7428 if (mFrameMetricsObservers == null) { 7429 mFrameMetricsObservers = new ArrayList<>(); 7430 } 7431 7432 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7433 mFrameMetricsObservers.add(fmo); 7434 } 7435 } 7436 7437 /** 7438 * Remove observer configured to collect frame stats for this view. 7439 * 7440 * @hide 7441 */ 7442 public void removeFrameMetricsListener( 7443 Window.OnFrameMetricsAvailableListener listener) { 7444 ThreadedRenderer renderer = getThreadedRenderer(); 7445 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7446 if (fmo == null) { 7447 throw new IllegalArgumentException( 7448 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7449 } 7450 7451 if (mFrameMetricsObservers != null) { 7452 mFrameMetricsObservers.remove(fmo); 7453 if (renderer != null) { 7454 renderer.removeObserver(fmo.getRendererObserver()); 7455 } 7456 } 7457 } 7458 7459 private void registerPendingFrameMetricsObservers() { 7460 if (mFrameMetricsObservers != null) { 7461 ThreadedRenderer renderer = getThreadedRenderer(); 7462 if (renderer != null) { 7463 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7464 renderer.addObserver(fmo.getRendererObserver()); 7465 } 7466 } else { 7467 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7468 } 7469 } 7470 } 7471 7472 private FrameMetricsObserver findFrameMetricsObserver( 7473 Window.OnFrameMetricsAvailableListener listener) { 7474 if (mFrameMetricsObservers != null) { 7475 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7476 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7477 if (observer.mListener == listener) { 7478 return observer; 7479 } 7480 } 7481 } 7482 7483 return null; 7484 } 7485 7486 /** @hide */ 7487 public void setNotifyAutofillManagerOnClick(boolean notify) { 7488 if (notify) { 7489 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7490 } else { 7491 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7492 } 7493 } 7494 7495 private void notifyAutofillManagerOnClick() { 7496 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7497 try { 7498 getAutofillManager().notifyViewClicked(this); 7499 } finally { 7500 // Set it to already called so it's not called twice when called by 7501 // performClickInternal() 7502 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7503 } 7504 } 7505 } 7506 7507 /** 7508 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7509 * {@code performClick()} directly to make sure the autofill manager is notified when 7510 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7511 * method). 7512 */ 7513 private boolean performClickInternal() { 7514 // Must notify autofill manager before performing the click actions to avoid scenarios where 7515 // the app has a click listener that changes the state of views the autofill service might 7516 // be interested on. 7517 notifyAutofillManagerOnClick(); 7518 7519 return performClick(); 7520 } 7521 7522 /** 7523 * Call this view's OnClickListener, if it is defined. Performs all normal 7524 * actions associated with clicking: reporting accessibility event, playing 7525 * a sound, etc. 7526 * 7527 * @return True there was an assigned OnClickListener that was called, false 7528 * otherwise is returned. 7529 */ 7530 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7531 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7532 // could extend this method without calling super.performClick()). 7533 public boolean performClick() { 7534 // We still need to call this method to handle the cases where performClick() was called 7535 // externally, instead of through performClickInternal() 7536 notifyAutofillManagerOnClick(); 7537 7538 final boolean result; 7539 final ListenerInfo li = mListenerInfo; 7540 if (li != null && li.mOnClickListener != null) { 7541 playSoundEffect(SoundEffectConstants.CLICK); 7542 li.mOnClickListener.onClick(this); 7543 result = true; 7544 } else { 7545 result = false; 7546 } 7547 7548 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7549 7550 notifyEnterOrExitForAutoFillIfNeeded(true); 7551 7552 return result; 7553 } 7554 7555 /** 7556 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7557 * this only calls the listener, and does not do any associated clicking 7558 * actions like reporting an accessibility event. 7559 * 7560 * @return True there was an assigned OnClickListener that was called, false 7561 * otherwise is returned. 7562 */ 7563 public boolean callOnClick() { 7564 ListenerInfo li = mListenerInfo; 7565 if (li != null && li.mOnClickListener != null) { 7566 li.mOnClickListener.onClick(this); 7567 return true; 7568 } 7569 return false; 7570 } 7571 7572 /** 7573 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7574 * context menu if the OnLongClickListener did not consume the event. 7575 * 7576 * @return {@code true} if one of the above receivers consumed the event, 7577 * {@code false} otherwise 7578 */ 7579 public boolean performLongClick() { 7580 return performLongClickInternal(mLongClickX, mLongClickY); 7581 } 7582 7583 /** 7584 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7585 * context menu if the OnLongClickListener did not consume the event, 7586 * anchoring it to an (x,y) coordinate. 7587 * 7588 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7589 * to disable anchoring 7590 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7591 * to disable anchoring 7592 * @return {@code true} if one of the above receivers consumed the event, 7593 * {@code false} otherwise 7594 */ 7595 public boolean performLongClick(float x, float y) { 7596 mLongClickX = x; 7597 mLongClickY = y; 7598 final boolean handled = performLongClick(); 7599 mLongClickX = Float.NaN; 7600 mLongClickY = Float.NaN; 7601 return handled; 7602 } 7603 7604 /** 7605 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7606 * context menu if the OnLongClickListener did not consume the event, 7607 * optionally anchoring it to an (x,y) coordinate. 7608 * 7609 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7610 * to disable anchoring 7611 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7612 * to disable anchoring 7613 * @return {@code true} if one of the above receivers consumed the event, 7614 * {@code false} otherwise 7615 */ 7616 private boolean performLongClickInternal(float x, float y) { 7617 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7618 7619 boolean handled = false; 7620 final ListenerInfo li = mListenerInfo; 7621 if (li != null && li.mOnLongClickListener != null) { 7622 handled = li.mOnLongClickListener.onLongClick(View.this); 7623 } 7624 if (!handled) { 7625 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7626 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7627 } 7628 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7629 if (!handled) { 7630 handled = showLongClickTooltip((int) x, (int) y); 7631 } 7632 } 7633 if (handled) { 7634 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7635 } 7636 return handled; 7637 } 7638 7639 /** 7640 * Call this view's OnContextClickListener, if it is defined. 7641 * 7642 * @param x the x coordinate of the context click 7643 * @param y the y coordinate of the context click 7644 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7645 * otherwise. 7646 */ 7647 public boolean performContextClick(float x, float y) { 7648 return performContextClick(); 7649 } 7650 7651 /** 7652 * Call this view's OnContextClickListener, if it is defined. 7653 * 7654 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7655 * otherwise. 7656 */ 7657 public boolean performContextClick() { 7658 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7659 7660 boolean handled = false; 7661 ListenerInfo li = mListenerInfo; 7662 if (li != null && li.mOnContextClickListener != null) { 7663 handled = li.mOnContextClickListener.onContextClick(View.this); 7664 } 7665 if (handled) { 7666 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7667 } 7668 return handled; 7669 } 7670 7671 /** 7672 * Performs button-related actions during a touch down event. 7673 * 7674 * @param event The event. 7675 * @return True if the down was consumed. 7676 * 7677 * @hide 7678 */ 7679 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7680 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7681 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7682 showContextMenu(event.getX(), event.getY()); 7683 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7684 return true; 7685 } 7686 return false; 7687 } 7688 7689 /** 7690 * Shows the context menu for this view. 7691 * 7692 * @return {@code true} if the context menu was shown, {@code false} 7693 * otherwise 7694 * @see #showContextMenu(float, float) 7695 */ 7696 public boolean showContextMenu() { 7697 return getParent().showContextMenuForChild(this); 7698 } 7699 7700 /** 7701 * Shows the context menu for this view anchored to the specified 7702 * view-relative coordinate. 7703 * 7704 * @param x the X coordinate in pixels relative to the view to which the 7705 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7706 * @param y the Y coordinate in pixels relative to the view to which the 7707 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7708 * @return {@code true} if the context menu was shown, {@code false} 7709 * otherwise 7710 */ 7711 public boolean showContextMenu(float x, float y) { 7712 return getParent().showContextMenuForChild(this, x, y); 7713 } 7714 7715 /** 7716 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7717 * 7718 * @param callback Callback that will control the lifecycle of the action mode 7719 * @return The new action mode if it is started, null otherwise 7720 * 7721 * @see ActionMode 7722 * @see #startActionMode(android.view.ActionMode.Callback, int) 7723 */ 7724 public ActionMode startActionMode(ActionMode.Callback callback) { 7725 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7726 } 7727 7728 /** 7729 * Start an action mode with the given type. 7730 * 7731 * @param callback Callback that will control the lifecycle of the action mode 7732 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7733 * @return The new action mode if it is started, null otherwise 7734 * 7735 * @see ActionMode 7736 */ 7737 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7738 ViewParent parent = getParent(); 7739 if (parent == null) return null; 7740 try { 7741 return parent.startActionModeForChild(this, callback, type); 7742 } catch (AbstractMethodError ame) { 7743 // Older implementations of custom views might not implement this. 7744 return parent.startActionModeForChild(this, callback); 7745 } 7746 } 7747 7748 /** 7749 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7750 * Context, creating a unique View identifier to retrieve the result. 7751 * 7752 * @param intent The Intent to be started. 7753 * @param requestCode The request code to use. 7754 * @hide 7755 */ 7756 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7757 public void startActivityForResult(Intent intent, int requestCode) { 7758 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7759 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7760 } 7761 7762 /** 7763 * If this View corresponds to the calling who, dispatches the activity result. 7764 * @param who The identifier for the targeted View to receive the result. 7765 * @param requestCode The integer request code originally supplied to 7766 * startActivityForResult(), allowing you to identify who this 7767 * result came from. 7768 * @param resultCode The integer result code returned by the child activity 7769 * through its setResult(). 7770 * @param data An Intent, which can return result data to the caller 7771 * (various data can be attached to Intent "extras"). 7772 * @return {@code true} if the activity result was dispatched. 7773 * @hide 7774 */ 7775 public boolean dispatchActivityResult( 7776 String who, int requestCode, int resultCode, Intent data) { 7777 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7778 onActivityResult(requestCode, resultCode, data); 7779 mStartActivityRequestWho = null; 7780 return true; 7781 } 7782 return false; 7783 } 7784 7785 /** 7786 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7787 * 7788 * @param requestCode The integer request code originally supplied to 7789 * startActivityForResult(), allowing you to identify who this 7790 * result came from. 7791 * @param resultCode The integer result code returned by the child activity 7792 * through its setResult(). 7793 * @param data An Intent, which can return result data to the caller 7794 * (various data can be attached to Intent "extras"). 7795 * @hide 7796 */ 7797 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7798 // Do nothing. 7799 } 7800 7801 /** 7802 * Register a callback to be invoked when a hardware key is pressed in this view. 7803 * Key presses in software input methods will generally not trigger the methods of 7804 * this listener. 7805 * @param l the key listener to attach to this view 7806 */ 7807 public void setOnKeyListener(OnKeyListener l) { 7808 getListenerInfo().mOnKeyListener = l; 7809 } 7810 7811 /** 7812 * Register a callback to be invoked when a touch event is sent to this view. 7813 * @param l the touch listener to attach to this view 7814 */ 7815 public void setOnTouchListener(OnTouchListener l) { 7816 getListenerInfo().mOnTouchListener = l; 7817 } 7818 7819 /** 7820 * Register a callback to be invoked when a generic motion event is sent to this view. 7821 * @param l the generic motion listener to attach to this view 7822 */ 7823 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7824 getListenerInfo().mOnGenericMotionListener = l; 7825 } 7826 7827 /** 7828 * Register a callback to be invoked when a hover event is sent to this view. 7829 * @param l the hover listener to attach to this view 7830 */ 7831 public void setOnHoverListener(OnHoverListener l) { 7832 getListenerInfo().mOnHoverListener = l; 7833 } 7834 7835 /** 7836 * Register a drag event listener callback object for this View. The parameter is 7837 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7838 * View, the system calls the 7839 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7840 * @param l An implementation of {@link android.view.View.OnDragListener}. 7841 */ 7842 public void setOnDragListener(OnDragListener l) { 7843 getListenerInfo().mOnDragListener = l; 7844 } 7845 7846 /** 7847 * Give this view focus. This will cause 7848 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7849 * 7850 * Note: this does not check whether this {@link View} should get focus, it just 7851 * gives it focus no matter what. It should only be called internally by framework 7852 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7853 * 7854 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7855 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7856 * focus moved when requestFocus() is called. It may not always 7857 * apply, in which case use the default View.FOCUS_DOWN. 7858 * @param previouslyFocusedRect The rectangle of the view that had focus 7859 * prior in this View's coordinate system. 7860 */ 7861 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7862 if (DBG) { 7863 System.out.println(this + " requestFocus()"); 7864 } 7865 7866 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7867 mPrivateFlags |= PFLAG_FOCUSED; 7868 7869 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7870 7871 if (mParent != null) { 7872 mParent.requestChildFocus(this, this); 7873 updateFocusedInCluster(oldFocus, direction); 7874 } 7875 7876 if (mAttachInfo != null) { 7877 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 7878 } 7879 7880 onFocusChanged(true, direction, previouslyFocusedRect); 7881 refreshDrawableState(); 7882 } 7883 } 7884 7885 /** 7886 * Sets this view's preference for reveal behavior when it gains focus. 7887 * 7888 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 7889 * this view would prefer to be brought fully into view when it gains focus. 7890 * For example, a text field that a user is meant to type into. Other views such 7891 * as scrolling containers may prefer to opt-out of this behavior.</p> 7892 * 7893 * <p>The default value for views is true, though subclasses may change this 7894 * based on their preferred behavior.</p> 7895 * 7896 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 7897 * 7898 * @see #getRevealOnFocusHint() 7899 */ 7900 public final void setRevealOnFocusHint(boolean revealOnFocus) { 7901 if (revealOnFocus) { 7902 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 7903 } else { 7904 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 7905 } 7906 } 7907 7908 /** 7909 * Returns this view's preference for reveal behavior when it gains focus. 7910 * 7911 * <p>When this method returns true for a child view requesting focus, ancestor 7912 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 7913 * should make a best effort to make the newly focused child fully visible to the user. 7914 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 7915 * other properties affecting visibility to the user as part of the focus change.</p> 7916 * 7917 * @return true if this view would prefer to become fully visible when it gains focus, 7918 * false if it would prefer not to disrupt scroll positioning 7919 * 7920 * @see #setRevealOnFocusHint(boolean) 7921 */ 7922 public final boolean getRevealOnFocusHint() { 7923 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 7924 } 7925 7926 /** 7927 * Populates <code>outRect</code> with the hotspot bounds. By default, 7928 * the hotspot bounds are identical to the screen bounds. 7929 * 7930 * @param outRect rect to populate with hotspot bounds 7931 * @hide Only for internal use by views and widgets. 7932 */ 7933 public void getHotspotBounds(Rect outRect) { 7934 final Drawable background = getBackground(); 7935 if (background != null) { 7936 background.getHotspotBounds(outRect); 7937 } else { 7938 getBoundsOnScreen(outRect); 7939 } 7940 } 7941 7942 /** 7943 * Request that a rectangle of this view be visible on the screen, 7944 * scrolling if necessary just enough. 7945 * 7946 * <p>A View should call this if it maintains some notion of which part 7947 * of its content is interesting. For example, a text editing view 7948 * should call this when its cursor moves. 7949 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7950 * It should not be affected by which part of the View is currently visible or its scroll 7951 * position. 7952 * 7953 * @param rectangle The rectangle in the View's content coordinate space 7954 * @return Whether any parent scrolled. 7955 */ 7956 public boolean requestRectangleOnScreen(Rect rectangle) { 7957 return requestRectangleOnScreen(rectangle, false); 7958 } 7959 7960 /** 7961 * Request that a rectangle of this view be visible on the screen, 7962 * scrolling if necessary just enough. 7963 * 7964 * <p>A View should call this if it maintains some notion of which part 7965 * of its content is interesting. For example, a text editing view 7966 * should call this when its cursor moves. 7967 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7968 * It should not be affected by which part of the View is currently visible or its scroll 7969 * position. 7970 * <p>When <code>immediate</code> is set to true, scrolling will not be 7971 * animated. 7972 * 7973 * @param rectangle The rectangle in the View's content coordinate space 7974 * @param immediate True to forbid animated scrolling, false otherwise 7975 * @return Whether any parent scrolled. 7976 */ 7977 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7978 if (mParent == null) { 7979 return false; 7980 } 7981 7982 View child = this; 7983 7984 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7985 position.set(rectangle); 7986 7987 ViewParent parent = mParent; 7988 boolean scrolled = false; 7989 while (parent != null) { 7990 rectangle.set((int) position.left, (int) position.top, 7991 (int) position.right, (int) position.bottom); 7992 7993 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7994 7995 if (!(parent instanceof View)) { 7996 break; 7997 } 7998 7999 // move it from child's content coordinate space to parent's content coordinate space 8000 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 8001 8002 child = (View) parent; 8003 parent = child.getParent(); 8004 } 8005 8006 return scrolled; 8007 } 8008 8009 /** 8010 * Called when this view wants to give up focus. If focus is cleared 8011 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 8012 * <p> 8013 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 8014 * to the first focusable View from the top after focus is cleared. Hence, if this 8015 * View is the first from the top that can take focus, then all callbacks 8016 * related to clearing focus will be invoked after which the framework will 8017 * give focus to this view. 8018 * </p> 8019 */ 8020 public void clearFocus() { 8021 if (DBG) { 8022 System.out.println(this + " clearFocus()"); 8023 } 8024 8025 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 8026 clearFocusInternal(null, true, refocus); 8027 } 8028 8029 /** 8030 * Clears focus from the view, optionally propagating the change up through 8031 * the parent hierarchy and requesting that the root view place new focus. 8032 * 8033 * @param propagate whether to propagate the change up through the parent 8034 * hierarchy 8035 * @param refocus when propagate is true, specifies whether to request the 8036 * root view place new focus 8037 */ 8038 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 8039 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 8040 mPrivateFlags &= ~PFLAG_FOCUSED; 8041 clearParentsWantFocus(); 8042 8043 if (propagate && mParent != null) { 8044 mParent.clearChildFocus(this); 8045 } 8046 8047 onFocusChanged(false, 0, null); 8048 refreshDrawableState(); 8049 8050 if (propagate && (!refocus || !rootViewRequestFocus())) { 8051 notifyGlobalFocusCleared(this); 8052 } 8053 } 8054 } 8055 8056 void notifyGlobalFocusCleared(View oldFocus) { 8057 if (oldFocus != null && mAttachInfo != null) { 8058 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 8059 } 8060 } 8061 8062 boolean rootViewRequestFocus() { 8063 final View root = getRootView(); 8064 return root != null && root.requestFocus(); 8065 } 8066 8067 /** 8068 * Called internally by the view system when a new view is getting focus. 8069 * This is what clears the old focus. 8070 * <p> 8071 * <b>NOTE:</b> The parent view's focused child must be updated manually 8072 * after calling this method. Otherwise, the view hierarchy may be left in 8073 * an inconstent state. 8074 */ 8075 void unFocus(View focused) { 8076 if (DBG) { 8077 System.out.println(this + " unFocus()"); 8078 } 8079 8080 clearFocusInternal(focused, false, false); 8081 } 8082 8083 /** 8084 * Returns true if this view has focus itself, or is the ancestor of the 8085 * view that has focus. 8086 * 8087 * @return True if this view has or contains focus, false otherwise. 8088 */ 8089 @ViewDebug.ExportedProperty(category = "focus") 8090 public boolean hasFocus() { 8091 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8092 } 8093 8094 /** 8095 * Returns true if this view is focusable or if it contains a reachable View 8096 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 8097 * is a view whose parents do not block descendants focus. 8098 * Only {@link #VISIBLE} views are considered focusable. 8099 * 8100 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8101 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8102 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8103 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8104 * {@code false} for views not explicitly marked as focusable. 8105 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8106 * behavior.</p> 8107 * 8108 * @return {@code true} if the view is focusable or if the view contains a focusable 8109 * view, {@code false} otherwise 8110 * 8111 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8112 * @see ViewGroup#getTouchscreenBlocksFocus() 8113 * @see #hasExplicitFocusable() 8114 */ 8115 public boolean hasFocusable() { 8116 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8117 } 8118 8119 /** 8120 * Returns true if this view is focusable or if it contains a reachable View 8121 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8122 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8123 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8124 * {@link #FOCUSABLE} are considered focusable. 8125 * 8126 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8127 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8128 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8129 * to focusable will not.</p> 8130 * 8131 * @return {@code true} if the view is focusable or if the view contains a focusable 8132 * view, {@code false} otherwise 8133 * 8134 * @see #hasFocusable() 8135 */ 8136 public boolean hasExplicitFocusable() { 8137 return hasFocusable(false, true); 8138 } 8139 8140 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8141 if (!isFocusableInTouchMode()) { 8142 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8143 final ViewGroup g = (ViewGroup) p; 8144 if (g.shouldBlockFocusForTouchscreen()) { 8145 return false; 8146 } 8147 } 8148 } 8149 8150 // Invisible, gone, or disabled views are never focusable. 8151 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8152 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8153 return false; 8154 } 8155 8156 // Only use effective focusable value when allowed. 8157 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8158 return true; 8159 } 8160 8161 return false; 8162 } 8163 8164 /** 8165 * Called by the view system when the focus state of this view changes. 8166 * When the focus change event is caused by directional navigation, direction 8167 * and previouslyFocusedRect provide insight into where the focus is coming from. 8168 * When overriding, be sure to call up through to the super class so that 8169 * the standard focus handling will occur. 8170 * 8171 * @param gainFocus True if the View has focus; false otherwise. 8172 * @param direction The direction focus has moved when requestFocus() 8173 * is called to give this view focus. Values are 8174 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8175 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8176 * It may not always apply, in which case use the default. 8177 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8178 * system, of the previously focused view. If applicable, this will be 8179 * passed in as finer grained information about where the focus is coming 8180 * from (in addition to direction). Will be <code>null</code> otherwise. 8181 */ 8182 @CallSuper 8183 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8184 @Nullable Rect previouslyFocusedRect) { 8185 if (gainFocus) { 8186 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8187 } else { 8188 notifyViewAccessibilityStateChangedIfNeeded( 8189 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8190 } 8191 8192 // Here we check whether we still need the default focus highlight, and switch it on/off. 8193 switchDefaultFocusHighlight(); 8194 8195 if (!gainFocus) { 8196 if (isPressed()) { 8197 setPressed(false); 8198 } 8199 if (hasWindowFocus()) { 8200 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8201 } 8202 onFocusLost(); 8203 } else if (hasWindowFocus()) { 8204 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8205 } 8206 8207 invalidate(true); 8208 ListenerInfo li = mListenerInfo; 8209 if (li != null && li.mOnFocusChangeListener != null) { 8210 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8211 } 8212 8213 if (mAttachInfo != null) { 8214 mAttachInfo.mKeyDispatchState.reset(this); 8215 } 8216 8217 if (mParent != null) { 8218 mParent.onDescendantUnbufferedRequested(); 8219 } 8220 8221 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8222 updatePreferKeepClearForFocus(); 8223 } 8224 8225 /** 8226 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8227 * 8228 * @param hasFocus {@code true} when the {@link View} is being focused. 8229 */ 8230 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8231 if (mAttachInfo == null) { 8232 return; 8233 } 8234 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8235 } 8236 8237 /** @hide */ 8238 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8239 if (canNotifyAutofillEnterExitEvent()) { 8240 AutofillManager afm = getAutofillManager(); 8241 if (afm != null) { 8242 if (enter) { 8243 // We have not been laid out yet, hence cannot evaluate 8244 // whether this view is visible to the user, we will do 8245 // the evaluation once layout is complete. 8246 // Sometimes, views are already laid out, but it's still 8247 // not visible to the user, we also do the evaluation once 8248 // the view is visible. ex: There is a fade-in animation 8249 // for the activity, the view will be laid out when the 8250 // animation beginning. On the time, the view is not visible 8251 // to the user. And then as the animation progresses, the view 8252 // becomes visible to the user. 8253 if (!isLaidOut() || !isVisibleToUser()) { 8254 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8255 } else if (isVisibleToUser()) { 8256 if (isFocused()) { 8257 // TODO This is a potential problem that View gets focus before it's 8258 // visible to User. Ideally View should handle the event when 8259 // isVisibleToUser() becomes true where it should issue 8260 // notifyViewEntered(). 8261 afm.notifyViewEntered(this); 8262 } else { 8263 afm.notifyViewEnteredForFillDialog(this); 8264 } 8265 } 8266 } else if (!isFocused()) { 8267 afm.notifyViewExited(this); 8268 } 8269 } 8270 } 8271 } 8272 8273 /** 8274 * Visually distinct portion of a window with window-like semantics are considered panes for 8275 * accessibility purposes. One example is the content view of a fragment that is replaced. 8276 * In order for accessibility services to understand a pane's window-like behavior, panes 8277 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 8278 * when they appear, disappear, or change title. 8279 * 8280 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8281 * View is not a pane. 8282 * 8283 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8284 * 8285 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8286 */ 8287 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8288 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8289 boolean currentPaneTitleEmpty = mAccessibilityPaneTitle == null; 8290 boolean newPaneTitleEmpty = accessibilityPaneTitle == null; 8291 mAccessibilityPaneTitle = accessibilityPaneTitle; 8292 // Make explicitly important as nulled titles need to be important for DISAPPEARED 8293 // events. 8294 if (mAccessibilityPaneTitle != null 8295 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8296 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8297 } 8298 if (currentPaneTitleEmpty) { 8299 notifyViewAccessibilityStateChangedIfNeeded( 8300 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED); 8301 } else if (newPaneTitleEmpty) { 8302 notifyViewAccessibilityStateChangedIfNeeded( 8303 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 8304 } else { 8305 notifyViewAccessibilityStateChangedIfNeeded( 8306 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8307 } 8308 } 8309 } 8310 8311 /** 8312 * Get the title of the pane for purposes of accessibility. 8313 * 8314 * @return The current pane title. 8315 * 8316 * {@see #setAccessibilityPaneTitle}. 8317 * 8318 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8319 */ 8320 @InspectableProperty 8321 @Nullable 8322 public CharSequence getAccessibilityPaneTitle() { 8323 return mAccessibilityPaneTitle; 8324 } 8325 8326 private boolean isAccessibilityPane() { 8327 return mAccessibilityPaneTitle != null; 8328 } 8329 8330 /** 8331 * Sends an accessibility event of the given type. If accessibility is 8332 * not enabled this method has no effect. The default implementation calls 8333 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8334 * to populate information about the event source (this View), then calls 8335 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8336 * populate the text content of the event source including its descendants, 8337 * then for events type {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} 8338 * and {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} with 8339 * subtype {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}, 8340 * throttle the events, and last calls 8341 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8342 * on its parent to request sending of the event to interested parties. 8343 * <p> 8344 * If an {@link AccessibilityDelegate} has been specified via calling 8345 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8346 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8347 * responsible for handling this call. 8348 * </p> 8349 * <p> 8350 * If this view uses {@link AccessibilityNodeProvider} to provide virtual view hierarchy rooted 8351 * at this view, this method should not be called to send events from virtual children because 8352 * it will populate the events with wrong information and the events should be throttled per 8353 * child instead at the virtual root level. To send events from virtual children, call 8354 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} on the view's 8355 * parent to request sending of the event to interested parties. 8356 * </p> 8357 * 8358 * @param eventType The type of the event to send, as defined by several types from 8359 * {@link AccessibilityEvent}, such as 8360 * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} or 8361 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8362 * 8363 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8364 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8365 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8366 * @see AccessibilityDelegate 8367 */ 8368 public void sendAccessibilityEvent(int eventType) { 8369 if (mAccessibilityDelegate != null) { 8370 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8371 } else { 8372 sendAccessibilityEventInternal(eventType); 8373 } 8374 } 8375 8376 /** 8377 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8378 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8379 * specified text to its users. 8380 * <p> 8381 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8382 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8383 * accurately supplying the semantics of their UI. 8384 * They should not need to specify what exactly is announced to users. 8385 * 8386 * @param text The announcement text. 8387 */ 8388 public void announceForAccessibility(CharSequence text) { 8389 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8390 AccessibilityEvent event = AccessibilityEvent.obtain( 8391 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8392 onInitializeAccessibilityEvent(event); 8393 event.getText().add(text); 8394 event.setContentDescription(null); 8395 mParent.requestSendAccessibilityEvent(this, event); 8396 } 8397 } 8398 8399 /** 8400 * @see #sendAccessibilityEvent(int) 8401 * 8402 * Note: Called from the default {@link AccessibilityDelegate}. 8403 * 8404 * @hide 8405 */ 8406 public void sendAccessibilityEventInternal(int eventType) { 8407 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8408 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8409 } 8410 } 8411 8412 /** 8413 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8414 * takes as an argument an empty {@link AccessibilityEvent} and does not 8415 * perform a check whether accessibility is enabled. 8416 * <p> 8417 * If an {@link AccessibilityDelegate} has been specified via calling 8418 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8419 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8420 * is responsible for handling this call. 8421 * </p> 8422 * 8423 * @param event The event to send. 8424 * 8425 * @see #sendAccessibilityEvent(int) 8426 */ 8427 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8428 if (mAccessibilityDelegate != null) { 8429 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8430 } else { 8431 sendAccessibilityEventUncheckedInternal(event); 8432 } 8433 } 8434 8435 /** 8436 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8437 * 8438 * Note: Called from the default {@link AccessibilityDelegate}. 8439 * 8440 * @hide 8441 */ 8442 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8443 // Panes disappearing are relevant even if though the view is no longer visible. 8444 boolean isWindowStateChanged = 8445 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8446 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8447 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8448 boolean detached = detached(); 8449 if (!isShown() && !isWindowDisappearedEvent && !detached) { 8450 return; 8451 } 8452 onInitializeAccessibilityEvent(event); 8453 // Only a subset of accessibility events populates text content. 8454 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8455 dispatchPopulateAccessibilityEvent(event); 8456 } 8457 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 8458 if (throttle != null) { 8459 throttle.post(event); 8460 } else if (!isWindowDisappearedEvent && detached) { 8461 // Views could be attached soon later. Accessibility events during this temporarily 8462 // detached period should be sent too. 8463 postDelayed(() -> { 8464 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 8465 requestParentSendAccessibilityEvent(event); 8466 } 8467 }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 8468 } else { 8469 requestParentSendAccessibilityEvent(event); 8470 } 8471 } 8472 8473 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 8474 ViewParent parent = getParent(); 8475 if (parent != null) { 8476 getParent().requestSendAccessibilityEvent(this, event); 8477 } 8478 } 8479 8480 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 8481 AccessibilityEvent event) { 8482 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 8483 if (mSendViewScrolledAccessibilityEvent == null) { 8484 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 8485 } 8486 return mSendViewScrolledAccessibilityEvent; 8487 } 8488 boolean isStateContentChanged = (event.getContentChangeTypes() 8489 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 8490 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 8491 && isStateContentChanged) { 8492 if (mSendStateChangedAccessibilityEvent == null) { 8493 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 8494 } 8495 return mSendStateChangedAccessibilityEvent; 8496 } 8497 return null; 8498 } 8499 8500 private void clearAccessibilityThrottles() { 8501 cancel(mSendViewScrolledAccessibilityEvent); 8502 cancel(mSendStateChangedAccessibilityEvent); 8503 } 8504 8505 /** 8506 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8507 * to its children for adding their text content to the event. Note that the 8508 * event text is populated in a separate dispatch path since we add to the 8509 * event not only the text of the source but also the text of all its descendants. 8510 * A typical implementation will call 8511 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8512 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8513 * on each child. Override this method if custom population of the event text 8514 * content is required. 8515 * <p> 8516 * If an {@link AccessibilityDelegate} has been specified via calling 8517 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8518 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8519 * is responsible for handling this call. 8520 * </p> 8521 * <p> 8522 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8523 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8524 * </p> 8525 * 8526 * @param event The event. 8527 * 8528 * @return True if the event population was completed. 8529 */ 8530 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8531 if (mAccessibilityDelegate != null) { 8532 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8533 } else { 8534 return dispatchPopulateAccessibilityEventInternal(event); 8535 } 8536 } 8537 8538 /** 8539 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8540 * 8541 * Note: Called from the default {@link AccessibilityDelegate}. 8542 * 8543 * @hide 8544 */ 8545 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8546 onPopulateAccessibilityEvent(event); 8547 return false; 8548 } 8549 8550 /** 8551 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8552 * giving a chance to this View to populate the accessibility event with its 8553 * text content. While this method is free to modify event 8554 * attributes other than text content, doing so should normally be performed in 8555 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8556 * <p> 8557 * Example: Adding formatted date string to an accessibility event in addition 8558 * to the text added by the super implementation: 8559 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8560 * super.onPopulateAccessibilityEvent(event); 8561 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8562 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8563 * mCurrentDate.getTimeInMillis(), flags); 8564 * event.getText().add(selectedDateUtterance); 8565 * }</pre> 8566 * <p> 8567 * If an {@link AccessibilityDelegate} has been specified via calling 8568 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8569 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8570 * is responsible for handling this call. 8571 * </p> 8572 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8573 * information to the event, in case the default implementation has basic information to add. 8574 * </p> 8575 * 8576 * @param event The accessibility event which to populate. 8577 * 8578 * @see #sendAccessibilityEvent(int) 8579 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8580 */ 8581 @CallSuper 8582 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8583 if (mAccessibilityDelegate != null) { 8584 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8585 } else { 8586 onPopulateAccessibilityEventInternal(event); 8587 } 8588 } 8589 8590 /** 8591 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8592 * 8593 * Note: Called from the default {@link AccessibilityDelegate}. 8594 * 8595 * @hide 8596 */ 8597 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8598 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8599 && isAccessibilityPane()) { 8600 event.getText().add(getAccessibilityPaneTitle()); 8601 } 8602 } 8603 8604 /** 8605 * Initializes an {@link AccessibilityEvent} with information about 8606 * this View which is the event source. In other words, the source of 8607 * an accessibility event is the view whose state change triggered firing 8608 * the event. 8609 * <p> 8610 * Example: Setting the password property of an event in addition 8611 * to properties set by the super implementation: 8612 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8613 * super.onInitializeAccessibilityEvent(event); 8614 * event.setPassword(true); 8615 * }</pre> 8616 * <p> 8617 * If an {@link AccessibilityDelegate} has been specified via calling 8618 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8619 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8620 * is responsible for handling this call. 8621 * </p> 8622 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8623 * information to the event, in case the default implementation has basic information to add. 8624 * </p> 8625 * @param event The event to initialize. 8626 * 8627 * @see #sendAccessibilityEvent(int) 8628 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8629 */ 8630 @CallSuper 8631 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8632 if (mAccessibilityDelegate != null) { 8633 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8634 } else { 8635 onInitializeAccessibilityEventInternal(event); 8636 } 8637 } 8638 8639 /** 8640 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8641 * 8642 * Note: Called from the default {@link AccessibilityDelegate}. 8643 * 8644 * @hide 8645 */ 8646 @UnsupportedAppUsage 8647 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8648 event.setSource(this); 8649 event.setClassName(getAccessibilityClassName()); 8650 event.setPackageName(getContext().getPackageName()); 8651 event.setEnabled(isEnabled()); 8652 event.setContentDescription(mContentDescription); 8653 event.setScrollX(getScrollX()); 8654 event.setScrollY(getScrollY()); 8655 8656 switch (event.getEventType()) { 8657 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8658 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8659 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8660 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8661 event.setItemCount(focusablesTempList.size()); 8662 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8663 if (mAttachInfo != null) { 8664 focusablesTempList.clear(); 8665 } 8666 } break; 8667 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8668 CharSequence text = getIterableTextForAccessibility(); 8669 if (text != null && text.length() > 0) { 8670 event.setFromIndex(getAccessibilitySelectionStart()); 8671 event.setToIndex(getAccessibilitySelectionEnd()); 8672 event.setItemCount(text.length()); 8673 } 8674 } break; 8675 } 8676 } 8677 8678 /** 8679 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8680 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8681 * This method is responsible for obtaining an accessibility node info from a 8682 * pool of reusable instances and calling 8683 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8684 * initialize the former. 8685 * <p> 8686 * Note: The client is responsible for recycling the obtained instance by calling 8687 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8688 * </p> 8689 * 8690 * @return A populated {@link AccessibilityNodeInfo}. 8691 * 8692 * @see AccessibilityNodeInfo 8693 */ 8694 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8695 if (mAccessibilityDelegate != null) { 8696 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8697 } else { 8698 return createAccessibilityNodeInfoInternal(); 8699 } 8700 } 8701 8702 /** 8703 * @see #createAccessibilityNodeInfo() 8704 * 8705 * @hide 8706 */ 8707 public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8708 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8709 if (provider != null) { 8710 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8711 } else { 8712 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8713 onInitializeAccessibilityNodeInfo(info); 8714 return info; 8715 } 8716 } 8717 8718 /** 8719 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8720 * The base implementation sets: 8721 * <ul> 8722 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8723 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8724 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8725 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8726 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8727 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8728 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8729 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8730 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8731 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8732 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8733 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8734 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8735 * </ul> 8736 * <p> 8737 * Subclasses should override this method, call the super implementation, 8738 * and set additional attributes. 8739 * </p> 8740 * <p> 8741 * If an {@link AccessibilityDelegate} has been specified via calling 8742 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8743 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8744 * is responsible for handling this call. 8745 * </p> 8746 * 8747 * @param info The instance to initialize. 8748 */ 8749 @CallSuper 8750 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8751 if (mAccessibilityDelegate != null) { 8752 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8753 } else { 8754 onInitializeAccessibilityNodeInfoInternal(info); 8755 } 8756 } 8757 8758 /** 8759 * Gets the location of this view in screen coordinates. 8760 * 8761 * @param outRect The output location 8762 * @hide 8763 */ 8764 @UnsupportedAppUsage 8765 public void getBoundsOnScreen(Rect outRect) { 8766 getBoundsOnScreen(outRect, false); 8767 } 8768 8769 /** 8770 * Gets the location of this view in screen coordinates. 8771 * 8772 * @param outRect The output location 8773 * @param clipToParent Whether to clip child bounds to the parent ones. 8774 * @hide 8775 */ 8776 @UnsupportedAppUsage 8777 @TestApi 8778 public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { 8779 if (mAttachInfo == null) { 8780 return; 8781 } 8782 RectF position = mAttachInfo.mTmpTransformRect; 8783 getBoundsToScreenInternal(position, clipToParent); 8784 outRect.set(Math.round(position.left), Math.round(position.top), 8785 Math.round(position.right), Math.round(position.bottom)); 8786 // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded 8787 // will sandbox outRect within window bounds. 8788 mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); 8789 } 8790 8791 /** 8792 * Gets the location of this view in screen coordinates. 8793 * 8794 * @param outRect The output location 8795 * @param clipToParent Whether to clip child bounds to the parent ones. 8796 * @hide 8797 */ 8798 public void getBoundsOnScreen(RectF outRect, boolean clipToParent) { 8799 if (mAttachInfo == null) { 8800 return; 8801 } 8802 RectF position = mAttachInfo.mTmpTransformRect; 8803 getBoundsToScreenInternal(position, clipToParent); 8804 outRect.set(position.left, position.top, position.right, position.bottom); 8805 } 8806 8807 private void getBoundsToScreenInternal(RectF position, boolean clipToParent) { 8808 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8809 mapRectFromViewToScreenCoords(position, clipToParent); 8810 } 8811 8812 /** 8813 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8814 * 8815 * @param rect The rectangle to be mapped 8816 * @param clipToParent Whether to clip child bounds to the parent ones. 8817 * @hide 8818 */ 8819 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8820 if (!hasIdentityMatrix()) { 8821 getMatrix().mapRect(rect); 8822 } 8823 8824 rect.offset(mLeft, mTop); 8825 8826 ViewParent parent = mParent; 8827 while (parent instanceof View) { 8828 View parentView = (View) parent; 8829 8830 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 8831 8832 if (clipToParent) { 8833 rect.left = Math.max(rect.left, 0); 8834 rect.top = Math.max(rect.top, 0); 8835 rect.right = Math.min(rect.right, parentView.getWidth()); 8836 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 8837 } 8838 8839 if (!parentView.hasIdentityMatrix()) { 8840 parentView.getMatrix().mapRect(rect); 8841 } 8842 8843 rect.offset(parentView.mLeft, parentView.mTop); 8844 8845 parent = parentView.mParent; 8846 } 8847 8848 if (parent instanceof ViewRootImpl) { 8849 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 8850 rect.offset(0, -viewRootImpl.mCurScrollY); 8851 } 8852 8853 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8854 } 8855 8856 /** 8857 * Return the class name of this object to be used for accessibility purposes. 8858 * Subclasses should only override this if they are implementing something that 8859 * should be seen as a completely new class of view when used by accessibility, 8860 * unrelated to the class it is deriving from. This is used to fill in 8861 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 8862 */ 8863 public CharSequence getAccessibilityClassName() { 8864 return View.class.getName(); 8865 } 8866 8867 /** 8868 * Called when assist structure is being retrieved from a view as part of 8869 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 8870 * @param structure Fill in with structured view data. The default implementation 8871 * fills in all data that can be inferred from the view itself. 8872 */ 8873 public void onProvideStructure(ViewStructure structure) { 8874 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 8875 } 8876 8877 /** 8878 * Populates a {@link ViewStructure} to fullfil an autofill request. 8879 * 8880 * <p>The structure should contain at least the following properties: 8881 * <ul> 8882 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 8883 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 8884 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 8885 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 8886 * </ul> 8887 * 8888 * <p>It's also recommended to set the following properties - the more properties the structure 8889 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 8890 * using the structure: 8891 * 8892 * <ul> 8893 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 8894 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 8895 * view can only be filled with predefined values (typically used when the autofill type 8896 * is {@link #AUTOFILL_TYPE_LIST}). 8897 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 8898 * <li>Class name ({@link ViewStructure#setClassName(String)}). 8899 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 8900 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 8901 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 8902 * opacity ({@link ViewStructure#setOpaque(boolean)}). 8903 * <li>For views representing text fields, text properties such as the text itself 8904 * ({@link ViewStructure#setText(CharSequence)}), text hints 8905 * ({@link ViewStructure#setHint(CharSequence)}, input type 8906 * ({@link ViewStructure#setInputType(int)}), 8907 * <li>For views representing HTML nodes, its web domain 8908 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 8909 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 8910 * </ul> 8911 * 8912 * <p>The default implementation of this method already sets most of these properties based on 8913 * related {@link View} methods (for example, the autofill id is set using 8914 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 8915 * and views in the standard Android widgets library also override it to set their 8916 * relevant properties (for example, {@link android.widget.TextView} already sets the text 8917 * properties), so it's recommended to only override this method 8918 * (and call {@code super.onProvideAutofillStructure()}) when: 8919 * 8920 * <ul> 8921 * <li>The view contents does not include PII (Personally Identifiable Information), so it 8922 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 8923 * <li>The view can only be autofilled with predefined options, so it can call 8924 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 8925 * </ul> 8926 * 8927 * <p><b>Note:</b> The {@code left} and {@code top} values set in 8928 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 8929 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 8930 * 8931 * <p>Views support the Autofill Framework mainly by: 8932 * <ul> 8933 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8934 * <li>Notifying the Android System when the view value changed by calling 8935 * {@link AutofillManager#notifyValueChanged(View)}. 8936 * <li>Implementing the methods that autofill the view. 8937 * </ul> 8938 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 8939 * for the latter. 8940 * 8941 * @param structure fill in with structured view data for autofill purposes. 8942 * @param flags optional flags. 8943 * 8944 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8945 */ 8946 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 8947 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 8948 } 8949 8950 /** 8951 * Populates a {@link ViewStructure} for content capture. 8952 * 8953 * <p>This method is called after a view that is eligible for content capture 8954 * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is 8955 * enabled for the user, and the activity rendering the view is enabled for content capture) 8956 * is laid out and is visible. The populated structure is then passed to the service through 8957 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 8958 * 8959 * <p>The default implementation of this method sets the most relevant properties based on 8960 * related {@link View} methods, and views in the standard Android widgets library also 8961 * override it to set their relevant properties. Therefore, if overriding this method, it 8962 * is recommended to call {@code super.onProvideContentCaptureStructure()}. 8963 * 8964 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 8965 * the node representing this view and return right away, then asynchronously report (not 8966 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 8967 * changed by calling 8968 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 8969 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 8970 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 8971 * respectively. The structure for a child must be created using 8972 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 8973 * {@code autofillId} for a child can be obtained either through 8974 * {@code childStructure.getAutofillId()} or 8975 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 8976 * 8977 * <p>When the virtual view hierarchy represents a web page, you should also: 8978 * 8979 * <ul> 8980 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 8981 * capture events should be generate for that URL. 8982 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 8983 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 8984 * that subtree. 8985 * </ul> 8986 * 8987 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 8988 * <ul> 8989 * <li>{@link ViewStructure#setChildCount(int)} 8990 * <li>{@link ViewStructure#addChildCount(int)} 8991 * <li>{@link ViewStructure#getChildCount()} 8992 * <li>{@link ViewStructure#newChild(int)} 8993 * <li>{@link ViewStructure#asyncNewChild(int)} 8994 * <li>{@link ViewStructure#asyncCommit()} 8995 * <li>{@link ViewStructure#setWebDomain(String)} 8996 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 8997 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 8998 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 8999 * <li>{@link ViewStructure#setAlpha(float)} 9000 * <li>{@link ViewStructure#setElevation(float)} 9001 * <li>{@link ViewStructure#setTransformation(Matrix)} 9002 * 9003 * </ul> 9004 */ 9005 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 9006 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 9007 } 9008 9009 /** @hide */ 9010 protected void onProvideStructure(@NonNull ViewStructure structure, 9011 @ViewStructureType int viewFor, int flags) { 9012 final int id = mID; 9013 if (id != NO_ID && !isViewIdGenerated(id)) { 9014 String pkg, type, entry; 9015 try { 9016 final Resources res = getResources(); 9017 entry = res.getResourceEntryName(id); 9018 type = res.getResourceTypeName(id); 9019 pkg = res.getResourcePackageName(id); 9020 } catch (Resources.NotFoundException e) { 9021 entry = type = pkg = null; 9022 } 9023 structure.setId(id, pkg, type, entry); 9024 } else { 9025 structure.setId(id, null, null, null); 9026 } 9027 9028 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9029 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 9030 final @AutofillType int autofillType = getAutofillType(); 9031 // Don't need to fill autofill info if view does not support it. 9032 // For example, only TextViews that are editable support autofill 9033 if (autofillType != AUTOFILL_TYPE_NONE) { 9034 structure.setAutofillType(autofillType); 9035 structure.setAutofillHints(getAutofillHints()); 9036 structure.setAutofillValue(getAutofillValue()); 9037 } 9038 structure.setImportantForAutofill(getImportantForAutofill()); 9039 structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); 9040 } 9041 9042 int ignoredParentLeft = 0; 9043 int ignoredParentTop = 0; 9044 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9045 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 9046 View parentGroup = null; 9047 9048 ViewParent viewParent = getParent(); 9049 if (viewParent instanceof View) { 9050 parentGroup = (View) viewParent; 9051 } 9052 9053 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 9054 ignoredParentLeft += parentGroup.mLeft; 9055 ignoredParentTop += parentGroup.mTop; 9056 9057 viewParent = parentGroup.getParent(); 9058 if (viewParent instanceof View) { 9059 parentGroup = (View) viewParent; 9060 } else { 9061 break; 9062 } 9063 } 9064 } 9065 9066 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 9067 mRight - mLeft, mBottom - mTop); 9068 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 9069 if (!hasIdentityMatrix()) { 9070 structure.setTransformation(getMatrix()); 9071 } 9072 structure.setElevation(getZ()); 9073 } 9074 structure.setVisibility(getVisibility()); 9075 structure.setEnabled(isEnabled()); 9076 if (isClickable()) { 9077 structure.setClickable(true); 9078 } 9079 if (isFocusable()) { 9080 structure.setFocusable(true); 9081 } 9082 if (isFocused()) { 9083 structure.setFocused(true); 9084 } 9085 if (isAccessibilityFocused()) { 9086 structure.setAccessibilityFocused(true); 9087 } 9088 if (isSelected()) { 9089 structure.setSelected(true); 9090 } 9091 if (isActivated()) { 9092 structure.setActivated(true); 9093 } 9094 if (isLongClickable()) { 9095 structure.setLongClickable(true); 9096 } 9097 if (this instanceof Checkable) { 9098 structure.setCheckable(true); 9099 if (((Checkable)this).isChecked()) { 9100 structure.setChecked(true); 9101 } 9102 } 9103 if (isOpaque()) { 9104 structure.setOpaque(true); 9105 } 9106 if (isContextClickable()) { 9107 structure.setContextClickable(true); 9108 } 9109 structure.setClassName(getAccessibilityClassName().toString()); 9110 structure.setContentDescription(getContentDescription()); 9111 } 9112 9113 /** 9114 * Called when assist structure is being retrieved from a view as part of 9115 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 9116 * generate additional virtual structure under this view. The default implementation 9117 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 9118 * view's virtual accessibility nodes, if any. You can override this for a more 9119 * optimal implementation providing this data. 9120 */ 9121 public void onProvideVirtualStructure(ViewStructure structure) { 9122 onProvideVirtualStructureCompat(structure, false); 9123 } 9124 9125 /** 9126 * Fallback implementation to populate a ViewStructure from accessibility state. 9127 * 9128 * @param structure The structure to populate. 9129 * @param forAutofill Whether the structure is needed for autofill. 9130 */ 9131 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 9132 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9133 if (provider != null) { 9134 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9135 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 9136 } 9137 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 9138 structure.setChildCount(1); 9139 final ViewStructure root = structure.newChild(0); 9140 populateVirtualStructure(root, provider, info, forAutofill); 9141 info.recycle(); 9142 } 9143 } 9144 9145 /** 9146 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 9147 * request. 9148 * 9149 * <p>This method should be used when the view manages a virtual structure under this view. For 9150 * example, a view that draws input fields using {@link #draw(Canvas)}. 9151 * 9152 * <p>When implementing this method, subclasses must follow the rules below: 9153 * 9154 * <ul> 9155 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 9156 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 9157 * identifying the children in the virtual structure. 9158 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 9159 * exclude intermediate levels that are irrelevant for autofill; that would improve the 9160 * autofill performance. 9161 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 9162 * children. 9163 * <li>Set the autofill properties of the child structure as defined by 9164 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 9165 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 9166 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 9167 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 9168 * when the focused virtual child changed. 9169 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9170 * whether a given virtual view is visible to the user in order to support triggering 9171 * save when all views of interest go away. 9172 * <li>Call 9173 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9174 * when the value of a virtual child changed. 9175 * <li>Call {@link 9176 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9177 * when the visibility of a virtual child changed. 9178 * <li>Call 9179 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9180 * child is clicked. 9181 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9182 * changed and the current context should be committed (for example, when the user tapped 9183 * a {@code SUBMIT} button in an HTML page). 9184 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9185 * changed and the current context should be canceled (for example, when the user tapped 9186 * a {@code CANCEL} button in an HTML page). 9187 * <li>Provide ways for users to manually request autofill by calling 9188 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9189 * <li>The {@code left} and {@code top} values set in 9190 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9191 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9192 * structure. 9193 * </ul> 9194 * 9195 * <p>Views with virtual children support the Autofill Framework mainly by: 9196 * <ul> 9197 * <li>Providing the metadata defining what the virtual children mean and how they can be 9198 * autofilled. 9199 * <li>Implementing the methods that autofill the virtual children. 9200 * </ul> 9201 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9202 * for the latter. 9203 * 9204 * @param structure fill in with virtual children data for autofill purposes. 9205 * @param flags optional flags. 9206 * 9207 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9208 */ 9209 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9210 if (mContext.isAutofillCompatibilityEnabled()) { 9211 onProvideVirtualStructureCompat(structure, true); 9212 } 9213 } 9214 9215 /** 9216 * Sets the listener to be {@link #performReceiveContent used} to handle insertion of 9217 * content into this view. 9218 * 9219 * <p>Depending on the type of view, this listener may be invoked for different scenarios. For 9220 * example, for an editable {@link android.widget.TextView}, this listener will be invoked for 9221 * the following scenarios: 9222 * <ol> 9223 * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the 9224 * insertion/selection menu) 9225 * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent}) 9226 * <li>Drag and drop (drop events from {@link #onDragEvent}) 9227 * <li>Autofill 9228 * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT} 9229 * </ol> 9230 * 9231 * <p>When setting a listener, clients must also declare the accepted MIME types. 9232 * The listener will still be invoked even if the MIME type of the content is not one of the 9233 * declared MIME types (e.g. if the user pastes content whose type is not one of the declared 9234 * MIME types). 9235 * In that case, the listener may reject the content (defer to the default platform behavior) 9236 * or execute some other fallback logic (e.g. show an appropriate message to the user). 9237 * The declared MIME types serve as a hint to allow different features to optionally alter 9238 * their behavior. For example, a soft keyboard may optionally choose to hide its UI for 9239 * inserting GIFs for a particular input field if the MIME types set here for that field 9240 * don't include "image/gif" or "image/*". 9241 * 9242 * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC 9243 * MIME types. As a result, you should always write your MIME types with lowercase letters, 9244 * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9245 * lowercase. 9246 * 9247 * @param mimeTypes The MIME types accepted by the given listener. These may use patterns 9248 * such as "image/*", but may not start with a wildcard. This argument must 9249 * not be null or empty if a non-null listener is passed in. 9250 * @param listener The listener to use. This can be null to reset to the default behavior. 9251 */ 9252 public void setOnReceiveContentListener( 9253 @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, 9254 @Nullable OnReceiveContentListener listener) { 9255 if (listener != null) { 9256 Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, 9257 "When the listener is set, MIME types must also be set"); 9258 } 9259 if (mimeTypes != null) { 9260 Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")), 9261 "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes)); 9262 } 9263 mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; 9264 getListenerInfo().mOnReceiveContentListener = listener; 9265 } 9266 9267 /** 9268 * Receives the given content. If no listener is set, invokes {@link #onReceiveContent}. If a 9269 * listener is {@link #setOnReceiveContentListener set}, invokes the listener instead; if the 9270 * listener returns a non-null result, invokes {@link #onReceiveContent} to handle it. 9271 * 9272 * @param payload The content to insert and related metadata. 9273 * 9274 * @return The portion of the passed-in content that was not accepted (may be all, some, or none 9275 * of the passed-in content). 9276 */ 9277 @Nullable performReceiveContent(@onNull ContentInfo payload)9278 public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { 9279 final OnReceiveContentListener listener = (mListenerInfo == null) ? null 9280 : getListenerInfo().mOnReceiveContentListener; 9281 if (listener != null) { 9282 final ContentInfo remaining = listener.onReceiveContent(this, payload); 9283 return (remaining == null) ? null : onReceiveContent(remaining); 9284 } 9285 return onReceiveContent(payload); 9286 } 9287 9288 /** 9289 * Implements the default behavior for receiving content for this type of view. The default 9290 * view implementation is a no-op (returns the passed-in content without acting on it). 9291 * 9292 * <p>Widgets should override this method to define their default behavior for receiving 9293 * content. Apps should {@link #setOnReceiveContentListener set a listener} to provide 9294 * app-specific handling for receiving content. 9295 * 9296 * <p>See {@link #setOnReceiveContentListener} and {@link #performReceiveContent} for more info. 9297 * 9298 * @param payload The content to insert and related metadata. 9299 * 9300 * @return The portion of the passed-in content that was not handled (may be all, some, or none 9301 * of the passed-in content). 9302 */ 9303 @Nullable onReceiveContent(@onNull ContentInfo payload)9304 public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { 9305 return payload; 9306 } 9307 9308 /** 9309 * Returns the MIME types accepted by {@link #performReceiveContent} for this view, as 9310 * configured via {@link #setOnReceiveContentListener}. By default returns null. 9311 * 9312 * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft 9313 * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For 9314 * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular 9315 * input field if the MIME types returned here for that field don't include "image/gif" or 9316 * "image/*". 9317 * 9318 * <p>Note: Comparisons of MIME types should be performed using utilities such as 9319 * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to 9320 * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching 9321 * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result, 9322 * you should always write your MIME types with lowercase letters, or use 9323 * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9324 * lowercase. 9325 * 9326 * @return The MIME types accepted by {@link #performReceiveContent} for this view (may 9327 * include patterns such as "image/*"). 9328 */ 9329 @SuppressLint("NullableCollection") 9330 @Nullable getReceiveContentMimeTypes()9331 public String[] getReceiveContentMimeTypes() { 9332 return mReceiveContentMimeTypes; 9333 } 9334 9335 /** 9336 * Automatically fills the content of this view with the {@code value}. 9337 * 9338 * <p>Views support the Autofill Framework mainly by: 9339 * <ul> 9340 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9341 * <li>Implementing the methods that autofill the view. 9342 * </ul> 9343 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 9344 * this method is responsible for latter. 9345 * 9346 * <p>This method does nothing by default, but when overridden it typically: 9347 * <ol> 9348 * <li>Checks if the provided value matches the expected type (which is defined by 9349 * {@link #getAutofillType()}). 9350 * <li>Checks if the view is editable - if it isn't, it should return right away. 9351 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 9352 * <li>Pass the actual value to the equivalent setter in the view. 9353 * </ol> 9354 * 9355 * <p>For example, a text-field view could implement the method this way: 9356 * 9357 * <pre class="prettyprint"> 9358 * @Override 9359 * public void autofill(AutofillValue value) { 9360 * if (!value.isText() || !this.isEditable()) { 9361 * return; 9362 * } 9363 * CharSequence text = value.getTextValue(); 9364 * if (text != null) { 9365 * this.setText(text); 9366 * } 9367 * } 9368 * </pre> 9369 * 9370 * <p>If the value is updated asynchronously, the next call to 9371 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 9372 * changed to the autofilled value. If not, the view will not be considered autofilled. 9373 * 9374 * <p><b>Note:</b> After this method is called, the value returned by 9375 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 9376 * view will not be highlighted as autofilled. 9377 * 9378 * @param value value to be autofilled. 9379 */ autofill(@uppressWarnings"unused") AutofillValue value)9380 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 9381 } 9382 9383 /** 9384 * Automatically fills the content of the virtual children within this view. 9385 * 9386 * <p>Views with virtual children support the Autofill Framework mainly by: 9387 * <ul> 9388 * <li>Providing the metadata defining what the virtual children mean and how they can be 9389 * autofilled. 9390 * <li>Implementing the methods that autofill the virtual children. 9391 * </ul> 9392 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 9393 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 9394 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 9395 * 9396 * <p>If a child value is updated asynchronously, the next call to 9397 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 9398 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 9399 * considered autofilled. 9400 * 9401 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 9402 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 9403 * changes. 9404 * 9405 * @param values map of values to be autofilled, keyed by virtual child id. 9406 * 9407 * @attr ref android.R.styleable#Theme_autofilledHighlight 9408 */ autofill(@onNull @uppressWarnings"unused") SparseArray<AutofillValue> values)9409 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 9410 if (!mContext.isAutofillCompatibilityEnabled()) { 9411 return; 9412 } 9413 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9414 if (provider == null) { 9415 return; 9416 } 9417 final int valueCount = values.size(); 9418 for (int i = 0; i < valueCount; i++) { 9419 final AutofillValue value = values.valueAt(i); 9420 if (value.isText()) { 9421 final int virtualId = values.keyAt(i); 9422 final CharSequence text = value.getTextValue(); 9423 final Bundle arguments = new Bundle(); 9424 arguments.putCharSequence( 9425 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 9426 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 9427 } 9428 } 9429 } 9430 9431 /** 9432 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 9433 * 9434 * <p>The autofill id is created on demand, unless it is explicitly set by 9435 * {@link #setAutofillId(AutofillId)}. 9436 * 9437 * <p>See {@link #setAutofillId(AutofillId)} for more info. 9438 * 9439 * @return The View's autofill id. 9440 */ getAutofillId()9441 public final AutofillId getAutofillId() { 9442 if (mAutofillId == null) { 9443 // The autofill id needs to be unique, but its value doesn't matter, 9444 // so it's better to reuse the accessibility id to save space. 9445 mAutofillId = new AutofillId(getAutofillViewId()); 9446 } 9447 return mAutofillId; 9448 } 9449 9450 /** 9451 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 9452 * 9453 * <p>The autofill id is created on demand, and this method should only be called when a view is 9454 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 9455 * that method creates a snapshot of the view that is passed along to the autofill service. 9456 * 9457 * <p>This method is typically used when view subtrees are recycled to represent different 9458 * content* —in this case, the autofill id can be saved before the view content is swapped 9459 * out, and restored later when it's swapped back in. For example: 9460 * 9461 * <pre> 9462 * EditText reusableView = ...; 9463 * ViewGroup parentView = ...; 9464 * AutofillManager afm = ...; 9465 * 9466 * // Swap out the view and change its contents 9467 * AutofillId oldId = reusableView.getAutofillId(); 9468 * CharSequence oldText = reusableView.getText(); 9469 * parentView.removeView(reusableView); 9470 * AutofillId newId = afm.getNextAutofillId(); 9471 * reusableView.setText("New I am"); 9472 * reusableView.setAutofillId(newId); 9473 * parentView.addView(reusableView); 9474 * 9475 * // Later, swap the old content back in 9476 * parentView.removeView(reusableView); 9477 * reusableView.setAutofillId(oldId); 9478 * reusableView.setText(oldText); 9479 * parentView.addView(reusableView); 9480 * </pre> 9481 * 9482 * <p>NOTE: If this view is a descendant of an {@link android.widget.AdapterView}, the system 9483 * may reset its autofill id when this view is recycled. If the autofill ids need to be stable, 9484 * they should be set again in 9485 * {@link android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)}. 9486 * 9487 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 9488 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 9489 * obtained through {@link #getAutofillId()}), or a new value obtained through 9490 * {@link AutofillManager#getNextAutofillId()}. 9491 * 9492 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 9493 * a window}. 9494 * 9495 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 9496 */ setAutofillId(@ullable AutofillId id)9497 public void setAutofillId(@Nullable AutofillId id) { 9498 // TODO(b/37566627): add unit / CTS test for all possible combinations below 9499 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9500 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 9501 } 9502 if (isAttachedToWindow()) { 9503 throw new IllegalStateException("Cannot set autofill id when view is attached"); 9504 } 9505 if (id != null && !id.isNonVirtual()) { 9506 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 9507 } 9508 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 9509 // Ignore reset because it was never explicitly set before. 9510 return; 9511 } 9512 mAutofillId = id; 9513 if (id != null) { 9514 mAutofillViewId = id.getViewId(); 9515 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9516 } else { 9517 mAutofillViewId = NO_ID; 9518 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9519 } 9520 } 9521 9522 /** 9523 * Forces a reset of the autofill ids of the subtree rooted at this view. Like calling 9524 * {@link #setAutofillId(AutofillId) setAutofillId(null)} for each view, but works even if the 9525 * views are attached to a window. 9526 * 9527 * <p>This is useful if the views are being recycled, since an autofill id should uniquely 9528 * identify a particular piece of content. 9529 * 9530 * @hide 9531 */ resetSubtreeAutofillIds()9532 public void resetSubtreeAutofillIds() { 9533 if (mAutofillViewId == NO_ID) { 9534 return; 9535 } 9536 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9537 Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9538 } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9539 Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9540 } 9541 mAutofillId = null; 9542 mAutofillViewId = NO_ID; 9543 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9544 } 9545 9546 /** 9547 * Describes the autofill type of this view, so an 9548 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 9549 * when autofilling the view. 9550 * 9551 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 9552 * support the Autofill Framework. 9553 * 9554 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 9555 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 9556 * 9557 * @see #onProvideAutofillStructure(ViewStructure, int) 9558 * @see #autofill(AutofillValue) 9559 */ getAutofillType()9560 public @AutofillType int getAutofillType() { 9561 return AUTOFILL_TYPE_NONE; 9562 } 9563 9564 /** 9565 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 9566 * to autofill the view with the user's data. 9567 * 9568 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 9569 * 9570 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 9571 * {@code null} if no hints were set. 9572 * 9573 * @attr ref android.R.styleable#View_autofillHints 9574 */ 9575 @ViewDebug.ExportedProperty() 9576 @InspectableProperty getAutofillHints()9577 @Nullable public String[] getAutofillHints() { 9578 return mAutofillHints; 9579 } 9580 9581 /** 9582 * @hide 9583 */ 9584 @TestApi isAutofilled()9585 public boolean isAutofilled() { 9586 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 9587 } 9588 9589 /** 9590 * @hide 9591 */ hideAutofillHighlight()9592 public boolean hideAutofillHighlight() { 9593 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 9594 } 9595 9596 /** 9597 * Gets the {@link View}'s current autofill value. 9598 * 9599 * <p>By default returns {@code null}, but subclasses should override it and return an 9600 * appropriate value to properly support the Autofill Framework. 9601 * 9602 * @see #onProvideAutofillStructure(ViewStructure, int) 9603 * @see #autofill(AutofillValue) 9604 */ 9605 @Nullable getAutofillValue()9606 public AutofillValue getAutofillValue() { 9607 return null; 9608 } 9609 9610 /** 9611 * Gets the mode for determining whether this view is important for autofill. 9612 * 9613 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 9614 * info about this mode. 9615 * 9616 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 9617 * {@link #setImportantForAutofill(int)}. 9618 * 9619 * @attr ref android.R.styleable#View_importantForAutofill 9620 */ 9621 @ViewDebug.ExportedProperty(mapping = { 9622 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 9623 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 9624 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 9625 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9626 to = "yesExcludeDescendants"), 9627 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9628 to = "noExcludeDescendants")}) 9629 @InspectableProperty(enumMapping = { 9630 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 9631 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 9632 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 9633 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9634 name = "yesExcludeDescendants"), 9635 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9636 name = "noExcludeDescendants"), 9637 }) getImportantForAutofill()9638 public @AutofillImportance int getImportantForAutofill() { 9639 return (mPrivateFlags3 9640 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 9641 } 9642 9643 /** 9644 * Sets the mode for determining whether this view is considered important for autofill. 9645 * 9646 * <p>The platform determines the importance for autofill automatically but you 9647 * can use this method to customize the behavior. For example: 9648 * 9649 * <ol> 9650 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 9651 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 9652 * <li>When both the view and its children are irrelevant for autofill (for example, the root 9653 * view of an activity containing a spreadhseet editor), it should be 9654 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9655 * <li>When the view content is relevant for autofill but its children aren't (for example, 9656 * a credit card expiration date represented by a custom view that overrides the proper 9657 * autofill methods and has 2 children representing the month and year), it should 9658 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 9659 * </ol> 9660 * 9661 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9662 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 9663 * children) will be always be considered not important; for example, when the user explicitly 9664 * makes an autofill request, all views are considered important. See 9665 * {@link #isImportantForAutofill()} for more details about how the View's importance for 9666 * autofill is used. 9667 * 9668 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 9669 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 9670 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9671 * 9672 * @attr ref android.R.styleable#View_importantForAutofill 9673 */ setImportantForAutofill(@utofillImportance int mode)9674 public void setImportantForAutofill(@AutofillImportance int mode) { 9675 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9676 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 9677 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9678 } 9679 9680 /** 9681 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 9682 * associated with this view is considered important for autofill purposes. 9683 * 9684 * <p>Generally speaking, a view is important for autofill if: 9685 * <ol> 9686 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 9687 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 9688 * determine how other views can be autofilled. 9689 * <ol> 9690 * 9691 * <p>For example, view containers should typically return {@code false} for performance reasons 9692 * (since the important info is provided by their children), but if its properties have relevant 9693 * information (for example, a resource id called {@code credentials}, it should return 9694 * {@code true}. On the other hand, views representing labels or editable fields should 9695 * typically return {@code true}, but in some cases they could return {@code false} 9696 * (for example, if they're part of a "Captcha" mechanism). 9697 * 9698 * <p>The value returned by this method depends on the value returned by 9699 * {@link #getImportantForAutofill()}: 9700 * 9701 * <ol> 9702 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 9703 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 9704 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9705 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 9706 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 9707 * that can return {@code true} in some cases (like a container with a resource id), 9708 * but {@code false} in most. 9709 * <li>otherwise, it returns {@code false}. 9710 * </ol> 9711 * 9712 * <p>When a view is considered important for autofill: 9713 * <ul> 9714 * <li>The view might automatically trigger an autofill request when focused on. 9715 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 9716 * request. 9717 * </ul> 9718 * 9719 * <p>On the other hand, when a view is considered not important for autofill: 9720 * <ul> 9721 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 9722 * request through {@link AutofillManager#requestAutofill(View)}. 9723 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 9724 * autofill request, unless the request has the 9725 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9726 * </ul> 9727 * 9728 * @return whether the view is considered important for autofill. 9729 * 9730 * @see #setImportantForAutofill(int) 9731 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9732 * @see #IMPORTANT_FOR_AUTOFILL_YES 9733 * @see #IMPORTANT_FOR_AUTOFILL_NO 9734 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9735 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9736 * @see AutofillManager#requestAutofill(View) 9737 */ isImportantForAutofill()9738 public final boolean isImportantForAutofill() { 9739 // Check parent mode to ensure we're not hidden. 9740 ViewParent parent = mParent; 9741 while (parent instanceof View) { 9742 final int parentImportance = ((View) parent).getImportantForAutofill(); 9743 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9744 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9745 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9746 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9747 + "because parent " + parent + "'s importance is " + parentImportance); 9748 } 9749 return false; 9750 } 9751 parent = parent.getParent(); 9752 } 9753 9754 final int importance = getImportantForAutofill(); 9755 9756 // First, check the explicit states. 9757 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9758 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9759 return true; 9760 } 9761 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9762 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9763 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9764 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9765 + "because its importance is " + importance); 9766 } 9767 return false; 9768 } 9769 9770 // Then use some heuristics to handle AUTO. 9771 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9772 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9773 + this); 9774 return false; 9775 } 9776 9777 // Always include views that have an explicit resource id. 9778 final int id = mID; 9779 if (id != NO_ID && !isViewIdGenerated(id)) { 9780 final Resources res = getResources(); 9781 String entry = null; 9782 String pkg = null; 9783 try { 9784 entry = res.getResourceEntryName(id); 9785 pkg = res.getResourcePackageName(id); 9786 } catch (Resources.NotFoundException e) { 9787 // ignore 9788 } 9789 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9790 return true; 9791 } 9792 } 9793 9794 // If the app developer explicitly set hints for it, it's important. 9795 if (getAutofillHints() != null) { 9796 return true; 9797 } 9798 9799 // Otherwise, assume it's not important... 9800 return false; 9801 } 9802 9803 /** 9804 * Gets the mode for determining whether this view is important for content capture. 9805 * 9806 * <p>See {@link #setImportantForContentCapture(int)} and 9807 * {@link #isImportantForContentCapture()} for more info about this mode. 9808 * 9809 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 9810 * {@link #setImportantForContentCapture(int)}. 9811 * 9812 * @attr ref android.R.styleable#View_importantForContentCapture 9813 */ 9814 @ViewDebug.ExportedProperty(mapping = { 9815 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 9816 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 9817 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 9818 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9819 to = "yesExcludeDescendants"), 9820 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9821 to = "noExcludeDescendants")}) 9822 @InspectableProperty(enumMapping = { 9823 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 9824 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 9825 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 9826 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9827 name = "yesExcludeDescendants"), 9828 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9829 name = "noExcludeDescendants"), 9830 }) getImportantForContentCapture()9831 public @ContentCaptureImportance int getImportantForContentCapture() { 9832 // NOTE: the important for content capture values were the first flags added and are set in 9833 // the rightmost position, so we don't need to shift them 9834 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9835 } 9836 9837 /** 9838 * Sets the mode for determining whether this view is considered important for content capture. 9839 * 9840 * <p>The platform determines the importance for autofill automatically but you 9841 * can use this method to customize the behavior. Typically, a view that provides text should 9842 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 9843 * 9844 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 9845 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 9846 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 9847 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 9848 * 9849 * @attr ref android.R.styleable#View_importantForContentCapture 9850 */ setImportantForContentCapture(@ontentCaptureImportance int mode)9851 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 9852 // Reset first 9853 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9854 // Then set again 9855 // NOTE: the important for content capture values were the first flags added and are set in 9856 // the rightmost position, so we don't need to shift them 9857 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 9858 } 9859 9860 /** 9861 * Hints the Android System whether this view is considered important for content capture, based 9862 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 9863 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 9864 * 9865 * <p>See {@link ContentCaptureManager} for more info about content capture. 9866 * 9867 * @return whether the view is considered important for content capture. 9868 * 9869 * @see #setImportantForContentCapture(int) 9870 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 9871 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 9872 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 9873 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9874 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9875 */ isImportantForContentCapture()9876 public final boolean isImportantForContentCapture() { 9877 boolean isImportant; 9878 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 9879 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 9880 return isImportant; 9881 } 9882 9883 isImportant = calculateIsImportantForContentCapture(); 9884 9885 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9886 if (isImportant) { 9887 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9888 } 9889 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 9890 return isImportant; 9891 } 9892 9893 /** 9894 * Calculates whether the flag is important for content capture so it can be used by 9895 * {@link #isImportantForContentCapture()} while the tree is traversed. 9896 */ calculateIsImportantForContentCapture()9897 private boolean calculateIsImportantForContentCapture() { 9898 // Check parent mode to ensure we're important 9899 ViewParent parent = mParent; 9900 while (parent instanceof View) { 9901 final int parentImportance = ((View) parent).getImportantForContentCapture(); 9902 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9903 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 9904 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9905 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 9906 + "content capture because parent " + parent + "'s importance is " 9907 + parentImportance); 9908 } 9909 return false; 9910 } 9911 parent = parent.getParent(); 9912 } 9913 9914 final int importance = getImportantForContentCapture(); 9915 9916 // First, check the explicit states. 9917 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9918 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 9919 return true; 9920 } 9921 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9922 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 9923 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9924 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 9925 + "capture because its importance is " + importance); 9926 } 9927 return false; 9928 } 9929 9930 // Then use some heuristics to handle AUTO. 9931 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 9932 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 9933 + " on view " + this); 9934 return false; 9935 } 9936 9937 // View group is important if at least one children also is 9938 if (this instanceof ViewGroup) { 9939 final ViewGroup group = (ViewGroup) this; 9940 for (int i = 0; i < group.getChildCount(); i++) { 9941 final View child = group.getChildAt(i); 9942 if (child.isImportantForContentCapture()) { 9943 return true; 9944 } 9945 } 9946 } 9947 9948 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 9949 if (getAutofillHints() != null) { 9950 return true; 9951 } 9952 9953 // Otherwise, assume it's not important... 9954 return false; 9955 } 9956 9957 /** 9958 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 9959 * added, based on whether it's laid out and visible, and without knowing if the parent removed 9960 * it from the view hierarchy. 9961 * 9962 * <p>This method is called from many places (visibility changed, view laid out, view attached 9963 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 9964 * described below: 9965 * 9966 * <ol> 9967 * <li>It should only be called when content capture is enabled for the view. 9968 * <li>It must call viewAppeared() before viewDisappeared() 9969 * <li>viewAppeared() can only be called when the view is visible and laid out 9970 * <li>It should not call the same event twice. 9971 * </ol> 9972 */ notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared)9973 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 9974 AttachInfo ai = mAttachInfo; 9975 // Skip it while the view is being laid out for the first time 9976 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 9977 9978 // First check if context has client, so it saves a service lookup when it doesn't 9979 if (mContext.getContentCaptureOptions() == null) return; 9980 9981 if (appeared) { 9982 // The appeared event stops sending to AiAi. 9983 // 1. The view is hidden. 9984 // 2. The same event was sent. 9985 // 3. The view is not laid out, and it will be laid out in the future. 9986 // Some recycled views cached its layout and a relayout is unnecessary. In this case, 9987 // system still needs to notify content capture the view appeared. When a view is 9988 // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED. 9989 final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() 9990 && getVisibility() == VISIBLE 9991 && !isLayoutRequested(); 9992 if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() 9993 || !(isLaidOut() || isRecycledWithoutRelayout)) { 9994 if (DEBUG_CONTENT_CAPTURE) { 9995 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 9996 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9997 + ", visible=" + (getVisibility() == VISIBLE) 9998 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 9999 + ", alreadyNotifiedDisappeared=" 10000 + getNotifiedContentCaptureDisappeared()); 10001 } 10002 return; 10003 } 10004 } else { 10005 if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { 10006 if (DEBUG_CONTENT_CAPTURE) { 10007 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 10008 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10009 + ", visible=" + (getVisibility() == VISIBLE) 10010 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10011 + ", alreadyNotifiedDisappeared=" 10012 + getNotifiedContentCaptureDisappeared()); 10013 } 10014 return; 10015 } 10016 } 10017 10018 ContentCaptureSession session = getContentCaptureSession(); 10019 if (session == null) return; 10020 10021 // ... and finally at the view level 10022 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 10023 if (!isImportantForContentCapture()) return; 10024 10025 if (appeared) { 10026 setNotifiedContentCaptureAppeared(); 10027 10028 if (ai != null) { 10029 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10030 } else { 10031 if (DEBUG_CONTENT_CAPTURE) { 10032 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 10033 } 10034 } 10035 } else { 10036 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10037 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10038 10039 if (ai != null) { 10040 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10041 } else { 10042 if (DEBUG_CONTENT_CAPTURE) { 10043 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 10044 } 10045 } 10046 10047 // We reset any translation state as views may be re-used (e.g., as in ListView and 10048 // RecyclerView). We only need to do this for views important for content capture since 10049 // views unimportant for content capture won't be translated anyway. 10050 if (!isTemporarilyDetached()) { 10051 clearTranslationState(); 10052 } 10053 } 10054 } 10055 setNotifiedContentCaptureAppeared()10056 private void setNotifiedContentCaptureAppeared() { 10057 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10058 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10059 } 10060 10061 /** @hide */ getNotifiedContentCaptureAppeared()10062 protected boolean getNotifiedContentCaptureAppeared() { 10063 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 10064 } 10065 10066 getNotifiedContentCaptureDisappeared()10067 private boolean getNotifiedContentCaptureDisappeared() { 10068 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; 10069 } 10070 10071 /** 10072 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 10073 * 10074 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 10075 * the content capture events associated with this view or its view hierarchy (if it's a 10076 * {@link ViewGroup}). 10077 * 10078 * <p>For example, if your activity is associated with a web domain, first you would need to 10079 * set the context for the main DOM: 10080 * 10081 * <pre> 10082 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 10083 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 10084 * </pre> 10085 * 10086 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 10087 * 10088 * <pre> 10089 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 10090 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 10091 * iframeView.setContentCaptureSession(iframeSession); 10092 * </pre> 10093 * 10094 * @param contentCaptureSession a session created by 10095 * {@link ContentCaptureSession#createContentCaptureSession( 10096 * android.view.contentcapture.ContentCaptureContext)}. 10097 */ setContentCaptureSession(@ullable ContentCaptureSession contentCaptureSession)10098 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 10099 mContentCaptureSession = contentCaptureSession; 10100 } 10101 10102 /** 10103 * Gets the session used to notify content capture events. 10104 * 10105 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 10106 * inherited by ancestors, default session or {@code null} if content capture is disabled for 10107 * this view. 10108 */ 10109 @Nullable getContentCaptureSession()10110 public final ContentCaptureSession getContentCaptureSession() { 10111 if (mContentCaptureSessionCached) { 10112 return mContentCaptureSession; 10113 } 10114 10115 mContentCaptureSession = getAndCacheContentCaptureSession(); 10116 mContentCaptureSessionCached = true; 10117 return mContentCaptureSession; 10118 } 10119 10120 @Nullable getAndCacheContentCaptureSession()10121 private ContentCaptureSession getAndCacheContentCaptureSession() { 10122 // First try the session explicitly set by setContentCaptureSession() 10123 if (mContentCaptureSession != null) { 10124 return mContentCaptureSession; 10125 } 10126 10127 // Then the session explicitly set in an ancestor 10128 ContentCaptureSession session = null; 10129 if (mParent instanceof View) { 10130 session = ((View) mParent).getContentCaptureSession(); 10131 } 10132 10133 // Finally, if no session was explicitly set, use the context's default session. 10134 if (session == null) { 10135 final ContentCaptureManager ccm = mContext 10136 .getSystemService(ContentCaptureManager.class); 10137 return ccm == null ? null : ccm.getMainContentCaptureSession(); 10138 } 10139 return session; 10140 } 10141 10142 @Nullable getAutofillManager()10143 private AutofillManager getAutofillManager() { 10144 return mContext.getSystemService(AutofillManager.class); 10145 } 10146 isAutofillable()10147 private boolean isAutofillable() { 10148 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 10149 10150 if (!isImportantForAutofill()) { 10151 // View is not important for "regular" autofill, so we must check if Augmented Autofill 10152 // is enabled for the activity 10153 final AutofillOptions options = mContext.getAutofillOptions(); 10154 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 10155 return false; 10156 } 10157 final AutofillManager afm = getAutofillManager(); 10158 if (afm == null) return false; 10159 afm.notifyViewEnteredForAugmentedAutofill(this); 10160 } 10161 10162 return getAutofillViewId() > LAST_APP_AUTOFILL_ID; 10163 } 10164 10165 /** @hide */ canNotifyAutofillEnterExitEvent()10166 public boolean canNotifyAutofillEnterExitEvent() { 10167 return isAutofillable() && isAttachedToWindow(); 10168 } 10169 populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutofill)10170 private void populateVirtualStructure(ViewStructure structure, 10171 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 10172 boolean forAutofill) { 10173 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 10174 null, null, info.getViewIdResourceName()); 10175 Rect rect = structure.getTempRect(); 10176 info.getBoundsInParent(rect); 10177 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 10178 structure.setVisibility(VISIBLE); 10179 structure.setEnabled(info.isEnabled()); 10180 if (info.isClickable()) { 10181 structure.setClickable(true); 10182 } 10183 if (info.isFocusable()) { 10184 structure.setFocusable(true); 10185 } 10186 if (info.isFocused()) { 10187 structure.setFocused(true); 10188 } 10189 if (info.isAccessibilityFocused()) { 10190 structure.setAccessibilityFocused(true); 10191 } 10192 if (info.isSelected()) { 10193 structure.setSelected(true); 10194 } 10195 if (info.isLongClickable()) { 10196 structure.setLongClickable(true); 10197 } 10198 if (info.isCheckable()) { 10199 structure.setCheckable(true); 10200 if (info.isChecked()) { 10201 structure.setChecked(true); 10202 } 10203 } 10204 if (info.isContextClickable()) { 10205 structure.setContextClickable(true); 10206 } 10207 if (forAutofill) { 10208 structure.setAutofillId(new AutofillId(getAutofillId(), 10209 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 10210 } 10211 CharSequence cname = info.getClassName(); 10212 structure.setClassName(cname != null ? cname.toString() : null); 10213 structure.setContentDescription(info.getContentDescription()); 10214 if (forAutofill) { 10215 final int maxTextLength = info.getMaxTextLength(); 10216 if (maxTextLength != -1) { 10217 structure.setMaxTextLength(maxTextLength); 10218 } 10219 structure.setHint(info.getHintText()); 10220 } 10221 CharSequence text = info.getText(); 10222 boolean hasText = text != null || info.getError() != null; 10223 if (hasText) { 10224 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 10225 } 10226 if (forAutofill) { 10227 if (info.isEditable()) { 10228 structure.setDataIsSensitive(true); 10229 if (hasText) { 10230 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 10231 structure.setAutofillValue(AutofillValue.forText(text)); 10232 } 10233 int inputType = info.getInputType(); 10234 if (inputType == 0 && info.isPassword()) { 10235 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 10236 } 10237 structure.setInputType(inputType); 10238 } else { 10239 structure.setDataIsSensitive(false); 10240 } 10241 } 10242 final int NCHILDREN = info.getChildCount(); 10243 if (NCHILDREN > 0) { 10244 structure.setChildCount(NCHILDREN); 10245 for (int i=0; i<NCHILDREN; i++) { 10246 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 10247 == AccessibilityNodeProvider.HOST_VIEW_ID) { 10248 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 10249 continue; 10250 } 10251 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 10252 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 10253 if (cinfo != null) { 10254 ViewStructure child = structure.newChild(i); 10255 populateVirtualStructure(child, provider, cinfo, forAutofill); 10256 cinfo.recycle(); 10257 } 10258 } 10259 } 10260 } 10261 10262 /** 10263 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 10264 * implementation calls {@link #onProvideStructure} and 10265 * {@link #onProvideVirtualStructure}. 10266 */ dispatchProvideStructure(ViewStructure structure)10267 public void dispatchProvideStructure(ViewStructure structure) { 10268 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 10269 } 10270 10271 /** 10272 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 10273 * when an Assist structure is being created as part of an autofill request. 10274 * 10275 * <p>The default implementation does the following: 10276 * <ul> 10277 * <li>Sets the {@link AutofillId} in the structure. 10278 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 10279 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 10280 * </ul> 10281 * 10282 * <p>Typically, this method should only be overridden by subclasses that provide a view 10283 * hierarchy (such as {@link ViewGroup}) - other classes should override 10284 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 10285 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 10286 * 10287 * <p>When overridden, it must: 10288 * 10289 * <ul> 10290 * <li>Either call 10291 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 10292 * set the {@link AutofillId} in the structure (for example, by calling 10293 * {@code structure.setAutofillId(getAutofillId())}). 10294 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 10295 * set, all views in the structure should be considered important for autofill, 10296 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 10297 * respect this flag to provide a better user experience - this flag is typically used 10298 * when an user explicitly requested autofill. If the flag is not set, 10299 * then only views marked as important for autofill should be included in the 10300 * structure - skipping non-important views optimizes the overall autofill performance. 10301 * </ul> 10302 * 10303 * @param structure fill in with structured view data for autofill purposes. 10304 * @param flags optional flags. 10305 * 10306 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 10307 */ dispatchProvideAutofillStructure(@onNull ViewStructure structure, @AutofillFlags int flags)10308 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 10309 @AutofillFlags int flags) { 10310 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 10311 } 10312 dispatchProvideStructure(@onNull ViewStructure structure, @ViewStructureType int viewFor, @AutofillFlags int flags)10313 private void dispatchProvideStructure(@NonNull ViewStructure structure, 10314 @ViewStructureType int viewFor, @AutofillFlags int flags) { 10315 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 10316 structure.setAutofillId(getAutofillId()); 10317 onProvideAutofillStructure(structure, flags); 10318 onProvideAutofillVirtualStructure(structure, flags); 10319 } else if (!isAssistBlocked()) { 10320 onProvideStructure(structure); 10321 onProvideVirtualStructure(structure); 10322 } else { 10323 structure.setClassName(getAccessibilityClassName().toString()); 10324 structure.setAssistBlocked(true); 10325 } 10326 } 10327 10328 /** 10329 * Dispatches the initial content capture events for a view structure. 10330 * 10331 * @hide 10332 */ dispatchInitialProvideContentCaptureStructure()10333 public void dispatchInitialProvideContentCaptureStructure() { 10334 AttachInfo ai = mAttachInfo; 10335 if (ai == null) { 10336 Log.w(CONTENT_CAPTURE_LOG_TAG, 10337 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 10338 return; 10339 } 10340 ContentCaptureManager ccm = ai.mContentCaptureManager; 10341 if (ccm == null) { 10342 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 10343 + "no ContentCaptureManager for " + this); 10344 return; 10345 } 10346 10347 // We must set it before checkign if the view itself is important, because it might 10348 // initially not be (for example, if it's empty), although that might change later (for 10349 // example, if important views are added) 10350 ai.mReadyForContentCaptureUpdates = true; 10351 10352 if (!isImportantForContentCapture()) { 10353 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10354 Log.d(CONTENT_CAPTURE_LOG_TAG, 10355 "dispatchProvideContentCaptureStructure(): decorView is not important"); 10356 } 10357 return; 10358 } 10359 10360 ai.mContentCaptureManager = ccm; 10361 10362 ContentCaptureSession session = getContentCaptureSession(); 10363 if (session == null) { 10364 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10365 Log.d(CONTENT_CAPTURE_LOG_TAG, 10366 "dispatchProvideContentCaptureStructure(): no session for " + this); 10367 } 10368 return; 10369 } 10370 10371 session.internalNotifyViewTreeEvent(/* started= */ true); 10372 try { 10373 dispatchProvideContentCaptureStructure(); 10374 } finally { 10375 session.internalNotifyViewTreeEvent(/* started= */ false); 10376 } 10377 } 10378 10379 /** @hide */ dispatchProvideContentCaptureStructure()10380 void dispatchProvideContentCaptureStructure() { 10381 ContentCaptureSession session = getContentCaptureSession(); 10382 if (session != null) { 10383 ViewStructure structure = session.newViewStructure(this); 10384 onProvideContentCaptureStructure(structure, /* flags= */ 0); 10385 setNotifiedContentCaptureAppeared(); 10386 session.notifyViewAppeared(structure); 10387 } 10388 } 10389 10390 /** 10391 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 10392 * 10393 * Note: Called from the default {@link AccessibilityDelegate}. 10394 * 10395 * @hide 10396 */ onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)10397 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 10398 if (mAttachInfo == null) { 10399 return; 10400 } 10401 10402 Rect bounds = mAttachInfo.mTmpInvalRect; 10403 10404 getDrawingRect(bounds); 10405 info.setBoundsInParent(bounds); 10406 10407 getBoundsOnScreen(bounds, true); 10408 info.setBoundsInScreen(bounds); 10409 10410 ViewParent parent = getParentForAccessibility(); 10411 if (parent instanceof View) { 10412 info.setParent((View) parent); 10413 } 10414 10415 if (mID != View.NO_ID) { 10416 View rootView = getRootView(); 10417 if (rootView == null) { 10418 rootView = this; 10419 } 10420 10421 View label = rootView.findLabelForView(this, mID); 10422 if (label != null) { 10423 info.setLabeledBy(label); 10424 } 10425 10426 if ((mAttachInfo.mAccessibilityFetchFlags 10427 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 10428 && Resources.resourceHasPackage(mID)) { 10429 try { 10430 String viewId = getResources().getResourceName(mID); 10431 info.setViewIdResourceName(viewId); 10432 } catch (Resources.NotFoundException nfe) { 10433 /* ignore */ 10434 } 10435 } 10436 } 10437 10438 if (mLabelForId != View.NO_ID) { 10439 View rootView = getRootView(); 10440 if (rootView == null) { 10441 rootView = this; 10442 } 10443 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 10444 if (labeled != null) { 10445 info.setLabelFor(labeled); 10446 } 10447 } 10448 10449 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 10450 View rootView = getRootView(); 10451 if (rootView == null) { 10452 rootView = this; 10453 } 10454 View next = rootView.findViewInsideOutShouldExist(this, 10455 mAccessibilityTraversalBeforeId); 10456 if (next != null && next.includeForAccessibility()) { 10457 info.setTraversalBefore(next); 10458 } 10459 } 10460 10461 if (mAccessibilityTraversalAfterId != View.NO_ID) { 10462 View rootView = getRootView(); 10463 if (rootView == null) { 10464 rootView = this; 10465 } 10466 View next = rootView.findViewInsideOutShouldExist(this, 10467 mAccessibilityTraversalAfterId); 10468 if (next != null && next.includeForAccessibility()) { 10469 info.setTraversalAfter(next); 10470 } 10471 } 10472 10473 info.setVisibleToUser(isVisibleToUser()); 10474 10475 info.setImportantForAccessibility(isImportantForAccessibility()); 10476 info.setPackageName(mContext.getPackageName()); 10477 info.setClassName(getAccessibilityClassName()); 10478 info.setStateDescription(getStateDescription()); 10479 info.setContentDescription(getContentDescription()); 10480 10481 info.setEnabled(isEnabled()); 10482 info.setClickable(isClickable()); 10483 info.setFocusable(isFocusable()); 10484 info.setScreenReaderFocusable(isScreenReaderFocusable()); 10485 info.setFocused(isFocused()); 10486 info.setAccessibilityFocused(isAccessibilityFocused()); 10487 info.setSelected(isSelected()); 10488 info.setLongClickable(isLongClickable()); 10489 info.setContextClickable(isContextClickable()); 10490 info.setLiveRegion(getAccessibilityLiveRegion()); 10491 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 10492 info.setTooltipText(mTooltipInfo.mTooltipText); 10493 info.addAction((mTooltipInfo.mTooltipPopup == null) 10494 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 10495 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 10496 } 10497 10498 // TODO: These make sense only if we are in an AdapterView but all 10499 // views can be selected. Maybe from accessibility perspective 10500 // we should report as selectable view in an AdapterView. 10501 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 10502 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 10503 10504 if (isFocusable()) { 10505 if (isFocused()) { 10506 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 10507 } else { 10508 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 10509 } 10510 } 10511 10512 if (!isAccessibilityFocused()) { 10513 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 10514 } else { 10515 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 10516 } 10517 10518 if (isClickable() && isEnabled()) { 10519 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 10520 } 10521 10522 if (isLongClickable() && isEnabled()) { 10523 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 10524 } 10525 10526 if (isContextClickable() && isEnabled()) { 10527 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 10528 } 10529 10530 CharSequence text = getIterableTextForAccessibility(); 10531 if (text != null && text.length() > 0) { 10532 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 10533 10534 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 10535 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 10536 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 10537 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 10538 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 10539 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 10540 } 10541 10542 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 10543 populateAccessibilityNodeInfoDrawingOrderInParent(info); 10544 info.setPaneTitle(mAccessibilityPaneTitle); 10545 info.setHeading(isAccessibilityHeading()); 10546 10547 if (mTouchDelegate != null) { 10548 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 10549 } 10550 10551 if (startedSystemDragForAccessibility()) { 10552 info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); 10553 } 10554 10555 if (canAcceptAccessibilityDrop()) { 10556 info.addAction(AccessibilityAction.ACTION_DRAG_DROP); 10557 } 10558 } 10559 10560 10561 /** 10562 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 10563 * additional data. 10564 * <p> 10565 * This method only needs overloading if the node is marked as having extra data available. 10566 * </p> 10567 * 10568 * @param info The info to which to add the extra data. Never {@code null}. 10569 * @param extraDataKey A key specifying the type of extra data to add to the info. The 10570 * extra data should be added to the {@link Bundle} returned by 10571 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 10572 * {@code null}. 10573 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 10574 * {@code null} if the service provided no arguments. 10575 * 10576 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 10577 */ addExtraDataToAccessibilityNodeInfo( @onNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)10578 public void addExtraDataToAccessibilityNodeInfo( 10579 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 10580 @Nullable Bundle arguments) { 10581 } 10582 10583 /** 10584 * Determine the order in which this view will be drawn relative to its siblings for a11y 10585 * 10586 * @param info The info whose drawing order should be populated 10587 */ populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info)10588 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 10589 /* 10590 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 10591 * drawing order may not be well-defined, and some Views with custom drawing order may 10592 * not be initialized sufficiently to respond properly getChildDrawingOrder. 10593 */ 10594 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 10595 info.setDrawingOrder(0); 10596 return; 10597 } 10598 int drawingOrderInParent = 1; 10599 // Iterate up the hierarchy if parents are not important for a11y 10600 View viewAtDrawingLevel = this; 10601 final ViewParent parent = getParentForAccessibility(); 10602 while (viewAtDrawingLevel != parent) { 10603 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 10604 if (!(currentParent instanceof ViewGroup)) { 10605 // Should only happen for the Decor 10606 drawingOrderInParent = 0; 10607 break; 10608 } else { 10609 final ViewGroup parentGroup = (ViewGroup) currentParent; 10610 final int childCount = parentGroup.getChildCount(); 10611 if (childCount > 1) { 10612 List<View> preorderedList = parentGroup.buildOrderedChildList(); 10613 if (preorderedList != null) { 10614 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 10615 for (int i = 0; i < childDrawIndex; i++) { 10616 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 10617 } 10618 preorderedList.clear(); 10619 } else { 10620 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 10621 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 10622 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 10623 .getChildDrawingOrder(childCount, childIndex) : childIndex; 10624 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 10625 if (childDrawIndex != 0) { 10626 for (int i = 0; i < numChildrenToIterate; i++) { 10627 final int otherDrawIndex = (customOrder ? 10628 parentGroup.getChildDrawingOrder(childCount, i) : i); 10629 if (otherDrawIndex < childDrawIndex) { 10630 drawingOrderInParent += 10631 numViewsForAccessibility(parentGroup.getChildAt(i)); 10632 } 10633 } 10634 } 10635 } 10636 } 10637 } 10638 viewAtDrawingLevel = (View) currentParent; 10639 } 10640 info.setDrawingOrder(drawingOrderInParent); 10641 } 10642 numViewsForAccessibility(View view)10643 private static int numViewsForAccessibility(View view) { 10644 if (view != null) { 10645 if (view.includeForAccessibility()) { 10646 return 1; 10647 } else if (view instanceof ViewGroup) { 10648 return ((ViewGroup) view).getNumChildrenForAccessibility(); 10649 } 10650 } 10651 return 0; 10652 } 10653 findLabelForView(View view, int labeledId)10654 private View findLabelForView(View view, int labeledId) { 10655 if (mMatchLabelForPredicate == null) { 10656 mMatchLabelForPredicate = new MatchLabelForPredicate(); 10657 } 10658 mMatchLabelForPredicate.mLabeledId = labeledId; 10659 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 10660 } 10661 10662 /** 10663 * Computes whether this virtual autofill view is visible to the user. 10664 * 10665 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 10666 * view must override it. 10667 * 10668 * @return Whether the view is visible on the screen. 10669 */ isVisibleToUserForAutofill(int virtualId)10670 public boolean isVisibleToUserForAutofill(int virtualId) { 10671 if (mContext.isAutofillCompatibilityEnabled()) { 10672 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10673 if (provider != null) { 10674 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 10675 if (node != null) { 10676 return node.isVisibleToUser(); 10677 } 10678 // if node is null, assume it's not visible anymore 10679 } else { 10680 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 10681 } 10682 return false; 10683 } 10684 return true; 10685 } 10686 10687 /** 10688 * Computes whether this view is visible to the user. Such a view is 10689 * attached, visible, all its predecessors are visible, it is not clipped 10690 * entirely by its predecessors, and has an alpha greater than zero. 10691 * 10692 * @return Whether the view is visible on the screen. 10693 * 10694 * @hide 10695 */ 10696 @UnsupportedAppUsage isVisibleToUser()10697 public boolean isVisibleToUser() { 10698 return isVisibleToUser(null); 10699 } 10700 10701 /** 10702 * Computes whether the given portion of this view is visible to the user. 10703 * Such a view is attached, visible, all its predecessors are visible, 10704 * has an alpha greater than zero, and the specified portion is not 10705 * clipped entirely by its predecessors. 10706 * 10707 * @param boundInView the portion of the view to test; coordinates should be relative; may be 10708 * <code>null</code>, and the entire view will be tested in this case. 10709 * When <code>true</code> is returned by the function, the actual visible 10710 * region will be stored in this parameter; that is, if boundInView is fully 10711 * contained within the view, no modification will be made, otherwise regions 10712 * outside of the visible area of the view will be clipped. 10713 * 10714 * @return Whether the specified portion of the view is visible on the screen. 10715 * 10716 * @hide 10717 */ 10718 @UnsupportedAppUsage(trackingBug = 171933273) isVisibleToUser(Rect boundInView)10719 protected boolean isVisibleToUser(Rect boundInView) { 10720 if (mAttachInfo != null) { 10721 // Attached to invisible window means this view is not visible. 10722 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 10723 return false; 10724 } 10725 // An invisible predecessor or one with alpha zero means 10726 // that this view is not visible to the user. 10727 Object current = this; 10728 while (current instanceof View) { 10729 View view = (View) current; 10730 // We have attach info so this view is attached and there is no 10731 // need to check whether we reach to ViewRootImpl on the way up. 10732 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 10733 view.getVisibility() != VISIBLE) { 10734 return false; 10735 } 10736 current = view.mParent; 10737 } 10738 // Check if the view is entirely covered by its predecessors. 10739 Rect visibleRect = mAttachInfo.mTmpInvalRect; 10740 Point offset = mAttachInfo.mPoint; 10741 if (!getGlobalVisibleRect(visibleRect, offset)) { 10742 return false; 10743 } 10744 // Check if the visible portion intersects the rectangle of interest. 10745 if (boundInView != null) { 10746 visibleRect.offset(-offset.x, -offset.y); 10747 return boundInView.intersect(visibleRect); 10748 } 10749 return true; 10750 } 10751 return false; 10752 } 10753 10754 /** 10755 * Returns the delegate for implementing accessibility support via 10756 * composition. For more details see {@link AccessibilityDelegate}. 10757 * 10758 * @return The delegate, or null if none set. 10759 */ getAccessibilityDelegate()10760 public AccessibilityDelegate getAccessibilityDelegate() { 10761 return mAccessibilityDelegate; 10762 } 10763 10764 /** 10765 * Sets a delegate for implementing accessibility support via composition 10766 * (as opposed to inheritance). For more details, see 10767 * {@link AccessibilityDelegate}. 10768 * <p> 10769 * <strong>Note:</strong> On platform versions prior to 10770 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 10771 * views in the {@code android.widget.*} package are called <i>before</i> 10772 * host methods. This prevents certain properties such as class name from 10773 * being modified by overriding 10774 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 10775 * as any changes will be overwritten by the host class. 10776 * <p> 10777 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 10778 * methods are called <i>after</i> host methods, which all properties to be 10779 * modified without being overwritten by the host class. 10780 * 10781 * @param delegate the object to which accessibility method calls should be 10782 * delegated 10783 * @see AccessibilityDelegate 10784 */ setAccessibilityDelegate(@ullable AccessibilityDelegate delegate)10785 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 10786 mAccessibilityDelegate = delegate; 10787 } 10788 10789 /** 10790 * Gets the provider for managing a virtual view hierarchy rooted at this View 10791 * and reported to {@link android.accessibilityservice.AccessibilityService}s 10792 * that explore the window content. 10793 * <p> 10794 * If this method returns an instance, this instance is responsible for managing 10795 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 10796 * View including the one representing the View itself. Similarly the returned 10797 * instance is responsible for performing accessibility actions on any virtual 10798 * view or the root view itself. 10799 * </p> 10800 * <p> 10801 * If an {@link AccessibilityDelegate} has been specified via calling 10802 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10803 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 10804 * is responsible for handling this call. 10805 * </p> 10806 * 10807 * @return The provider. 10808 * 10809 * @see AccessibilityNodeProvider 10810 */ getAccessibilityNodeProvider()10811 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 10812 if (mAccessibilityDelegate != null) { 10813 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 10814 } else { 10815 return null; 10816 } 10817 } 10818 10819 /** 10820 * Gets the unique identifier of this view on the screen for accessibility purposes. 10821 * 10822 * @return The view accessibility id. 10823 * 10824 * @hide 10825 */ 10826 @UnsupportedAppUsage getAccessibilityViewId()10827 public int getAccessibilityViewId() { 10828 if (mAccessibilityViewId == NO_ID) { 10829 mAccessibilityViewId = sNextAccessibilityViewId++; 10830 } 10831 return mAccessibilityViewId; 10832 } 10833 10834 /** 10835 * Gets the unique identifier of this view on the screen for autofill purposes. 10836 * 10837 * @return The view autofill id. 10838 * 10839 * @hide 10840 */ getAutofillViewId()10841 public int getAutofillViewId() { 10842 if (mAutofillViewId == NO_ID) { 10843 mAutofillViewId = mContext.getNextAutofillId(); 10844 } 10845 return mAutofillViewId; 10846 } 10847 10848 /** 10849 * Gets the unique identifier of the window in which this View resides. 10850 * 10851 * @return The window accessibility id. 10852 * 10853 * @hide 10854 */ getAccessibilityWindowId()10855 public int getAccessibilityWindowId() { 10856 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 10857 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 10858 } 10859 10860 /** 10861 * Returns the {@link View}'s state description. 10862 * <p> 10863 * <strong>Note:</strong> Do not override this method, as it will have no 10864 * effect on the state description presented to accessibility services. 10865 * You must call {@link #setStateDescription(CharSequence)} to modify the 10866 * state description. 10867 * 10868 * @return the state description 10869 * @see #setStateDescription(CharSequence) 10870 */ 10871 @ViewDebug.ExportedProperty(category = "accessibility") getStateDescription()10872 public final @Nullable CharSequence getStateDescription() { 10873 return mStateDescription; 10874 } 10875 10876 /** 10877 * Returns the {@link View}'s content description. 10878 * <p> 10879 * <strong>Note:</strong> Do not override this method, as it will have no 10880 * effect on the content description presented to accessibility services. 10881 * You must call {@link #setContentDescription(CharSequence)} to modify the 10882 * content description. 10883 * 10884 * @return the content description 10885 * @see #setContentDescription(CharSequence) 10886 * @attr ref android.R.styleable#View_contentDescription 10887 */ 10888 @ViewDebug.ExportedProperty(category = "accessibility") 10889 @InspectableProperty getContentDescription()10890 public CharSequence getContentDescription() { 10891 return mContentDescription; 10892 } 10893 10894 /** 10895 * Sets the {@link View}'s state description. 10896 * <p> 10897 * A state description briefly describes the states of the view and is primarily used 10898 * for accessibility support to determine how the states of a view should be presented to 10899 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 10900 * it is used for customized state description (for example, "wifi, connected, three bars"). 10901 * State description changes frequently while content description should change less often. 10902 * State description should be localized. For android widgets which have default state 10903 * descriptions, app developers can call this method to override the state descriptions. 10904 * Setting state description to null restores the default behavior. 10905 * 10906 * @param stateDescription The state description. 10907 * @see #getStateDescription() 10908 */ 10909 @RemotableViewMethod setStateDescription(@ullable CharSequence stateDescription)10910 public void setStateDescription(@Nullable CharSequence stateDescription) { 10911 if (mStateDescription == null) { 10912 if (stateDescription == null) { 10913 return; 10914 } 10915 } else if (mStateDescription.equals(stateDescription)) { 10916 return; 10917 } 10918 mStateDescription = stateDescription; 10919 if (!TextUtils.isEmpty(stateDescription) 10920 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10921 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10922 } 10923 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10924 AccessibilityEvent event = AccessibilityEvent.obtain(); 10925 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 10926 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 10927 sendAccessibilityEventUnchecked(event); 10928 } 10929 } 10930 10931 /** 10932 * Sets the {@link View}'s content description. 10933 * <p> 10934 * A content description briefly describes the view and is primarily used 10935 * for accessibility support to determine how a view should be presented to 10936 * the user. In the case of a view with no textual representation, such as 10937 * {@link android.widget.ImageButton}, a useful content description 10938 * explains what the view does. For example, an image button with a phone 10939 * icon that is used to place a call may use "Call" as its content 10940 * description. An image of a floppy disk that is used to save a file may 10941 * use "Save". 10942 * 10943 * @param contentDescription The content description. 10944 * @see #getContentDescription() 10945 * @attr ref android.R.styleable#View_contentDescription 10946 */ 10947 @RemotableViewMethod setContentDescription(CharSequence contentDescription)10948 public void setContentDescription(CharSequence contentDescription) { 10949 if (mContentDescription == null) { 10950 if (contentDescription == null) { 10951 return; 10952 } 10953 } else if (mContentDescription.equals(contentDescription)) { 10954 return; 10955 } 10956 mContentDescription = contentDescription; 10957 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 10958 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10959 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10960 notifySubtreeAccessibilityStateChangedIfNeeded(); 10961 } else { 10962 notifyViewAccessibilityStateChangedIfNeeded( 10963 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 10964 } 10965 } 10966 10967 /** 10968 * Sets the id of a view before which this one is visited in accessibility traversal. 10969 * A screen-reader must visit the content of this view before the content of the one 10970 * it precedes. For example, if view B is set to be before view A, then a screen-reader 10971 * will traverse the entire content of B before traversing the entire content of A, 10972 * regardles of what traversal strategy it is using. 10973 * <p> 10974 * Views that do not have specified before/after relationships are traversed in order 10975 * determined by the screen-reader. 10976 * </p> 10977 * <p> 10978 * Setting that this view is before a view that is not important for accessibility 10979 * or if this view is not important for accessibility will have no effect as the 10980 * screen-reader is not aware of unimportant views. 10981 * </p> 10982 * 10983 * @param beforeId The id of a view this one precedes in accessibility traversal. 10984 * 10985 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 10986 * 10987 * @see #setImportantForAccessibility(int) 10988 */ 10989 @RemotableViewMethod setAccessibilityTraversalBefore(@dRes int beforeId)10990 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 10991 if (mAccessibilityTraversalBeforeId == beforeId) { 10992 return; 10993 } 10994 mAccessibilityTraversalBeforeId = beforeId; 10995 notifyViewAccessibilityStateChangedIfNeeded( 10996 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10997 } 10998 10999 /** 11000 * Gets the id of a view before which this one is visited in accessibility traversal. 11001 * 11002 * @return The id of a view this one precedes in accessibility traversal if 11003 * specified, otherwise {@link #NO_ID}. 11004 * 11005 * @see #setAccessibilityTraversalBefore(int) 11006 */ 11007 @IdRes 11008 @InspectableProperty getAccessibilityTraversalBefore()11009 public int getAccessibilityTraversalBefore() { 11010 return mAccessibilityTraversalBeforeId; 11011 } 11012 11013 /** 11014 * Sets the id of a view after which this one is visited in accessibility traversal. 11015 * A screen-reader must visit the content of the other view before the content of this 11016 * one. For example, if view B is set to be after view A, then a screen-reader 11017 * will traverse the entire content of A before traversing the entire content of B, 11018 * regardles of what traversal strategy it is using. 11019 * <p> 11020 * Views that do not have specified before/after relationships are traversed in order 11021 * determined by the screen-reader. 11022 * </p> 11023 * <p> 11024 * Setting that this view is after a view that is not important for accessibility 11025 * or if this view is not important for accessibility will have no effect as the 11026 * screen-reader is not aware of unimportant views. 11027 * </p> 11028 * 11029 * @param afterId The id of a view this one succedees in accessibility traversal. 11030 * 11031 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 11032 * 11033 * @see #setImportantForAccessibility(int) 11034 */ 11035 @RemotableViewMethod setAccessibilityTraversalAfter(@dRes int afterId)11036 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 11037 if (mAccessibilityTraversalAfterId == afterId) { 11038 return; 11039 } 11040 mAccessibilityTraversalAfterId = afterId; 11041 notifyViewAccessibilityStateChangedIfNeeded( 11042 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11043 } 11044 11045 /** 11046 * Gets the id of a view after which this one is visited in accessibility traversal. 11047 * 11048 * @return The id of a view this one succeedes in accessibility traversal if 11049 * specified, otherwise {@link #NO_ID}. 11050 * 11051 * @see #setAccessibilityTraversalAfter(int) 11052 */ 11053 @IdRes 11054 @InspectableProperty getAccessibilityTraversalAfter()11055 public int getAccessibilityTraversalAfter() { 11056 return mAccessibilityTraversalAfterId; 11057 } 11058 11059 /** 11060 * Gets the id of a view for which this view serves as a label for 11061 * accessibility purposes. 11062 * 11063 * @return The labeled view id. 11064 */ 11065 @IdRes 11066 @ViewDebug.ExportedProperty(category = "accessibility") 11067 @InspectableProperty getLabelFor()11068 public int getLabelFor() { 11069 return mLabelForId; 11070 } 11071 11072 /** 11073 * Sets the id of a view for which this view serves as a label for 11074 * accessibility purposes. 11075 * 11076 * @param id The labeled view id. 11077 */ 11078 @RemotableViewMethod setLabelFor(@dRes int id)11079 public void setLabelFor(@IdRes int id) { 11080 if (mLabelForId == id) { 11081 return; 11082 } 11083 mLabelForId = id; 11084 if (mLabelForId != View.NO_ID 11085 && mID == View.NO_ID) { 11086 mID = generateViewId(); 11087 } 11088 notifyViewAccessibilityStateChangedIfNeeded( 11089 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11090 } 11091 11092 /** 11093 * Invoked whenever this view loses focus, either by losing window focus or by losing 11094 * focus within its window. This method can be used to clear any state tied to the 11095 * focus. For instance, if a button is held pressed with the trackball and the window 11096 * loses focus, this method can be used to cancel the press. 11097 * 11098 * Subclasses of View overriding this method should always call super.onFocusLost(). 11099 * 11100 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 11101 * @see #onWindowFocusChanged(boolean) 11102 * 11103 * @hide pending API council approval 11104 */ 11105 @CallSuper 11106 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onFocusLost()11107 protected void onFocusLost() { 11108 resetPressedState(); 11109 } 11110 resetPressedState()11111 private void resetPressedState() { 11112 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11113 return; 11114 } 11115 11116 if (isPressed()) { 11117 setPressed(false); 11118 11119 if (!mHasPerformedLongPress) { 11120 removeLongPressCallback(); 11121 } 11122 } 11123 } 11124 11125 /** 11126 * Returns true if this view has focus 11127 * 11128 * @return True if this view has focus, false otherwise. 11129 */ 11130 @ViewDebug.ExportedProperty(category = "focus") 11131 @InspectableProperty(hasAttributeId = false) isFocused()11132 public boolean isFocused() { 11133 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 11134 } 11135 11136 /** 11137 * Find the view in the hierarchy rooted at this view that currently has 11138 * focus. 11139 * 11140 * @return The view that currently has focus, or null if no focused view can 11141 * be found. 11142 */ findFocus()11143 public View findFocus() { 11144 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 11145 } 11146 11147 /** 11148 * Indicates whether this view is one of the set of scrollable containers in 11149 * its window. 11150 * 11151 * @return whether this view is one of the set of scrollable containers in 11152 * its window 11153 * 11154 * @attr ref android.R.styleable#View_isScrollContainer 11155 */ 11156 @InspectableProperty(name = "isScrollContainer") isScrollContainer()11157 public boolean isScrollContainer() { 11158 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 11159 } 11160 11161 /** 11162 * Change whether this view is one of the set of scrollable containers in 11163 * its window. This will be used to determine whether the window can 11164 * resize or must pan when a soft input area is open -- scrollable 11165 * containers allow the window to use resize mode since the container 11166 * will appropriately shrink. 11167 * 11168 * @attr ref android.R.styleable#View_isScrollContainer 11169 */ setScrollContainer(boolean isScrollContainer)11170 public void setScrollContainer(boolean isScrollContainer) { 11171 if (isScrollContainer) { 11172 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 11173 mAttachInfo.mScrollContainers.add(this); 11174 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 11175 } 11176 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 11177 } else { 11178 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 11179 mAttachInfo.mScrollContainers.remove(this); 11180 } 11181 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 11182 } 11183 } 11184 11185 /** 11186 * Returns the quality of the drawing cache. 11187 * 11188 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11189 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11190 * 11191 * @see #setDrawingCacheQuality(int) 11192 * @see #setDrawingCacheEnabled(boolean) 11193 * @see #isDrawingCacheEnabled() 11194 * 11195 * @attr ref android.R.styleable#View_drawingCacheQuality 11196 * 11197 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11198 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11199 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11200 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11201 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11202 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11203 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11204 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11205 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11206 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11207 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11208 * reports or unit testing the {@link PixelCopy} API is recommended. 11209 */ 11210 @Deprecated 11211 @DrawingCacheQuality 11212 @InspectableProperty(enumMapping = { 11213 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 11214 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 11215 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 11216 }) getDrawingCacheQuality()11217 public int getDrawingCacheQuality() { 11218 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 11219 } 11220 11221 /** 11222 * Set the drawing cache quality of this view. This value is used only when the 11223 * drawing cache is enabled 11224 * 11225 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11226 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11227 * 11228 * @see #getDrawingCacheQuality() 11229 * @see #setDrawingCacheEnabled(boolean) 11230 * @see #isDrawingCacheEnabled() 11231 * 11232 * @attr ref android.R.styleable#View_drawingCacheQuality 11233 * 11234 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11235 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11236 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11237 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11238 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11239 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11240 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11241 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11242 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11243 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11244 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11245 * reports or unit testing the {@link PixelCopy} API is recommended. 11246 */ 11247 @Deprecated setDrawingCacheQuality(@rawingCacheQuality int quality)11248 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 11249 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 11250 } 11251 11252 /** 11253 * Returns whether the screen should remain on, corresponding to the current 11254 * value of {@link #KEEP_SCREEN_ON}. 11255 * 11256 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 11257 * 11258 * @see #setKeepScreenOn(boolean) 11259 * 11260 * @attr ref android.R.styleable#View_keepScreenOn 11261 */ 11262 @InspectableProperty getKeepScreenOn()11263 public boolean getKeepScreenOn() { 11264 return (mViewFlags & KEEP_SCREEN_ON) != 0; 11265 } 11266 11267 /** 11268 * Controls whether the screen should remain on, modifying the 11269 * value of {@link #KEEP_SCREEN_ON}. 11270 * 11271 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 11272 * 11273 * @see #getKeepScreenOn() 11274 * 11275 * @attr ref android.R.styleable#View_keepScreenOn 11276 */ setKeepScreenOn(boolean keepScreenOn)11277 public void setKeepScreenOn(boolean keepScreenOn) { 11278 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 11279 } 11280 11281 /** 11282 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11283 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11284 * 11285 * @attr ref android.R.styleable#View_nextFocusLeft 11286 */ 11287 @IdRes 11288 @InspectableProperty(name = "nextFocusLeft") getNextFocusLeftId()11289 public int getNextFocusLeftId() { 11290 return mNextFocusLeftId; 11291 } 11292 11293 /** 11294 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11295 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 11296 * decide automatically. 11297 * 11298 * @attr ref android.R.styleable#View_nextFocusLeft 11299 */ setNextFocusLeftId(@dRes int nextFocusLeftId)11300 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 11301 mNextFocusLeftId = nextFocusLeftId; 11302 } 11303 11304 /** 11305 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11306 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11307 * 11308 * @attr ref android.R.styleable#View_nextFocusRight 11309 */ 11310 @IdRes 11311 @InspectableProperty(name = "nextFocusRight") getNextFocusRightId()11312 public int getNextFocusRightId() { 11313 return mNextFocusRightId; 11314 } 11315 11316 /** 11317 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11318 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 11319 * decide automatically. 11320 * 11321 * @attr ref android.R.styleable#View_nextFocusRight 11322 */ setNextFocusRightId(@dRes int nextFocusRightId)11323 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 11324 mNextFocusRightId = nextFocusRightId; 11325 } 11326 11327 /** 11328 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11329 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11330 * 11331 * @attr ref android.R.styleable#View_nextFocusUp 11332 */ 11333 @IdRes 11334 @InspectableProperty(name = "nextFocusUp") getNextFocusUpId()11335 public int getNextFocusUpId() { 11336 return mNextFocusUpId; 11337 } 11338 11339 /** 11340 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11341 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 11342 * decide automatically. 11343 * 11344 * @attr ref android.R.styleable#View_nextFocusUp 11345 */ setNextFocusUpId(@dRes int nextFocusUpId)11346 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 11347 mNextFocusUpId = nextFocusUpId; 11348 } 11349 11350 /** 11351 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11352 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11353 * 11354 * @attr ref android.R.styleable#View_nextFocusDown 11355 */ 11356 @IdRes 11357 @InspectableProperty(name = "nextFocusDown") getNextFocusDownId()11358 public int getNextFocusDownId() { 11359 return mNextFocusDownId; 11360 } 11361 11362 /** 11363 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11364 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 11365 * decide automatically. 11366 * 11367 * @attr ref android.R.styleable#View_nextFocusDown 11368 */ setNextFocusDownId(@dRes int nextFocusDownId)11369 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 11370 mNextFocusDownId = nextFocusDownId; 11371 } 11372 11373 /** 11374 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11375 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11376 * 11377 * @attr ref android.R.styleable#View_nextFocusForward 11378 */ 11379 @IdRes 11380 @InspectableProperty(name = "nextFocusForward") getNextFocusForwardId()11381 public int getNextFocusForwardId() { 11382 return mNextFocusForwardId; 11383 } 11384 11385 /** 11386 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11387 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 11388 * decide automatically. 11389 * 11390 * @attr ref android.R.styleable#View_nextFocusForward 11391 */ setNextFocusForwardId(@dRes int nextFocusForwardId)11392 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 11393 mNextFocusForwardId = nextFocusForwardId; 11394 } 11395 11396 /** 11397 * Gets the id of the root of the next keyboard navigation cluster. 11398 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 11399 * decide automatically. 11400 * 11401 * @attr ref android.R.styleable#View_nextClusterForward 11402 */ 11403 @IdRes 11404 @InspectableProperty(name = "nextClusterForward") getNextClusterForwardId()11405 public int getNextClusterForwardId() { 11406 return mNextClusterForwardId; 11407 } 11408 11409 /** 11410 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 11411 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 11412 * decide automatically. 11413 * 11414 * @attr ref android.R.styleable#View_nextClusterForward 11415 */ setNextClusterForwardId(@dRes int nextClusterForwardId)11416 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 11417 mNextClusterForwardId = nextClusterForwardId; 11418 } 11419 11420 /** 11421 * Returns the visibility of this view and all of its ancestors 11422 * 11423 * @return True if this view and all of its ancestors are {@link #VISIBLE} 11424 */ isShown()11425 public boolean isShown() { 11426 View current = this; 11427 //noinspection ConstantConditions 11428 do { 11429 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 11430 return false; 11431 } 11432 ViewParent parent = current.mParent; 11433 if (parent == null) { 11434 return false; // We are not attached to the view root 11435 } 11436 if (!(parent instanceof View)) { 11437 return true; 11438 } 11439 current = (View) parent; 11440 } while (current != null); 11441 11442 return false; 11443 } 11444 detached()11445 private boolean detached() { 11446 View current = this; 11447 //noinspection ConstantConditions 11448 do { 11449 if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { 11450 return true; 11451 } 11452 ViewParent parent = current.mParent; 11453 if (parent == null) { 11454 return false; 11455 } 11456 if (!(parent instanceof View)) { 11457 return false; 11458 } 11459 current = (View) parent; 11460 } while (current != null); 11461 11462 return false; 11463 } 11464 11465 /** 11466 * Called by the view hierarchy when the content insets for a window have 11467 * changed, to allow it to adjust its content to fit within those windows. 11468 * The content insets tell you the space that the status bar, input method, 11469 * and other system windows infringe on the application's window. 11470 * 11471 * <p>You do not normally need to deal with this function, since the default 11472 * window decoration given to applications takes care of applying it to the 11473 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 11474 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 11475 * and your content can be placed under those system elements. You can then 11476 * use this method within your view hierarchy if you have parts of your UI 11477 * which you would like to ensure are not being covered. 11478 * 11479 * <p>The default implementation of this method simply applies the content 11480 * insets to the view's padding, consuming that content (modifying the 11481 * insets to be 0), and returning true. This behavior is off by default, but can 11482 * be enabled through {@link #setFitsSystemWindows(boolean)}. 11483 * 11484 * <p>This function's traversal down the hierarchy is depth-first. The same content 11485 * insets object is propagated down the hierarchy, so any changes made to it will 11486 * be seen by all following views (including potentially ones above in 11487 * the hierarchy since this is a depth-first traversal). The first view 11488 * that returns true will abort the entire traversal. 11489 * 11490 * <p>The default implementation works well for a situation where it is 11491 * used with a container that covers the entire window, allowing it to 11492 * apply the appropriate insets to its content on all edges. If you need 11493 * a more complicated layout (such as two different views fitting system 11494 * windows, one on the top of the window, and one on the bottom), 11495 * you can override the method and handle the insets however you would like. 11496 * Note that the insets provided by the framework are always relative to the 11497 * far edges of the window, not accounting for the location of the called view 11498 * within that window. (In fact when this method is called you do not yet know 11499 * where the layout will place the view, as it is done before layout happens.) 11500 * 11501 * <p>Note: unlike many View methods, there is no dispatch phase to this 11502 * call. If you are overriding it in a ViewGroup and want to allow the 11503 * call to continue to your children, you must be sure to call the super 11504 * implementation. 11505 * 11506 * <p>Here is a sample layout that makes use of fitting system windows 11507 * to have controls for a video view placed inside of the window decorations 11508 * that it hides and shows. This can be used with code like the second 11509 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 11510 * 11511 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 11512 * 11513 * @param insets Current content insets of the window. Prior to 11514 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 11515 * the insets or else you and Android will be unhappy. 11516 * 11517 * @return {@code true} if this view applied the insets and it should not 11518 * continue propagating further down the hierarchy, {@code false} otherwise. 11519 * @see #getFitsSystemWindows() 11520 * @see #setFitsSystemWindows(boolean) 11521 * @see #setSystemUiVisibility(int) 11522 * 11523 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 11524 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 11525 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 11526 * to implement handling their own insets. 11527 */ 11528 @Deprecated fitSystemWindows(Rect insets)11529 protected boolean fitSystemWindows(Rect insets) { 11530 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 11531 if (insets == null) { 11532 // Null insets by definition have already been consumed. 11533 // This call cannot apply insets since there are none to apply, 11534 // so return false. 11535 return false; 11536 } 11537 // If we're not in the process of dispatching the newer apply insets call, 11538 // that means we're not in the compatibility path. Dispatch into the newer 11539 // apply insets path and take things from there. 11540 try { 11541 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 11542 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 11543 } finally { 11544 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 11545 } 11546 } else { 11547 // We're being called from the newer apply insets path. 11548 // Perform the standard fallback behavior. 11549 return fitSystemWindowsInt(insets); 11550 } 11551 } 11552 fitSystemWindowsInt(Rect insets)11553 private boolean fitSystemWindowsInt(Rect insets) { 11554 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 11555 Rect localInsets = sThreadLocal.get(); 11556 boolean res = computeFitSystemWindows(insets, localInsets); 11557 applyInsets(localInsets); 11558 return res; 11559 } 11560 return false; 11561 } 11562 applyInsets(Rect insets)11563 private void applyInsets(Rect insets) { 11564 mUserPaddingStart = UNDEFINED_PADDING; 11565 mUserPaddingEnd = UNDEFINED_PADDING; 11566 mUserPaddingLeftInitial = insets.left; 11567 mUserPaddingRightInitial = insets.right; 11568 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 11569 } 11570 11571 /** 11572 * Called when the view should apply {@link WindowInsets} according to its internal policy. 11573 * 11574 * <p>This method should be overridden by views that wish to apply a policy different from or 11575 * in addition to the default behavior. Clients that wish to force a view subtree 11576 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 11577 * 11578 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 11579 * it will be called during dispatch instead of this method. The listener may optionally 11580 * call this method from its own implementation if it wishes to apply the view's default 11581 * insets policy in addition to its own.</p> 11582 * 11583 * <p>Implementations of this method should either return the insets parameter unchanged 11584 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 11585 * that this view applied itself. This allows new inset types added in future platform 11586 * versions to pass through existing implementations unchanged without being erroneously 11587 * consumed.</p> 11588 * 11589 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 11590 * property is set then the view will consume the system window insets and apply them 11591 * as padding for the view.</p> 11592 * 11593 * @param insets Insets to apply 11594 * @return The supplied insets with any applied insets consumed 11595 */ onApplyWindowInsets(WindowInsets insets)11596 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 11597 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11598 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 11599 return onApplyFrameworkOptionalFitSystemWindows(insets); 11600 } 11601 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 11602 // We weren't called from within a direct call to fitSystemWindows, 11603 // call into it as a fallback in case we're in a class that overrides it 11604 // and has logic to perform. 11605 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 11606 return insets.consumeSystemWindowInsets(); 11607 } 11608 } else { 11609 // We were called from within a direct call to fitSystemWindows. 11610 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 11611 return insets.consumeSystemWindowInsets(); 11612 } 11613 } 11614 return insets; 11615 } 11616 onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets)11617 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 11618 Rect localInsets = sThreadLocal.get(); 11619 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 11620 applyInsets(localInsets); 11621 return result; 11622 } 11623 11624 /** 11625 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 11626 * window insets to this view. The listener's 11627 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 11628 * method will be called instead of the view's 11629 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 11630 * 11631 * @param listener Listener to set 11632 * 11633 * @see #onApplyWindowInsets(WindowInsets) 11634 */ setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)11635 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 11636 getListenerInfo().mOnApplyWindowInsetsListener = listener; 11637 } 11638 11639 /** 11640 * Request to apply the given window insets to this view or another view in its subtree. 11641 * 11642 * <p>This method should be called by clients wishing to apply insets corresponding to areas 11643 * obscured by window decorations or overlays. This can include the status and navigation bars, 11644 * action bars, input methods and more. New inset categories may be added in the future. 11645 * The method returns the insets provided minus any that were applied by this view or its 11646 * children.</p> 11647 * 11648 * <p>Clients wishing to provide custom behavior should override the 11649 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 11650 * {@link OnApplyWindowInsetsListener} via the 11651 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 11652 * method.</p> 11653 * 11654 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 11655 * </p> 11656 * 11657 * @param insets Insets to apply 11658 * @return The provided insets minus the insets that were consumed 11659 */ dispatchApplyWindowInsets(WindowInsets insets)11660 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 11661 try { 11662 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 11663 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 11664 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 11665 } else { 11666 return onApplyWindowInsets(insets); 11667 } 11668 } finally { 11669 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 11670 } 11671 } 11672 11673 /** 11674 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 11675 * cause insets. 11676 * <p> 11677 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 11678 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 11679 * this view. 11680 * </p> 11681 * @param callback The callback to set. 11682 */ setWindowInsetsAnimationCallback( @ullable WindowInsetsAnimation.Callback callback)11683 public void setWindowInsetsAnimationCallback( 11684 @Nullable WindowInsetsAnimation.Callback callback) { 11685 getListenerInfo().mWindowInsetsAnimationCallback = callback; 11686 } 11687 11688 /** 11689 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 11690 * or view tree of the sub-hierarchy {@code false} otherwise. 11691 * @hide 11692 */ hasWindowInsetsAnimationCallback()11693 public boolean hasWindowInsetsAnimationCallback() { 11694 return getListenerInfo().mWindowInsetsAnimationCallback != null; 11695 } 11696 11697 /** 11698 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 11699 * when Window Insets animation is being prepared. 11700 * @param animation current animation 11701 * 11702 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 11703 */ dispatchWindowInsetsAnimationPrepare( @onNull WindowInsetsAnimation animation)11704 public void dispatchWindowInsetsAnimationPrepare( 11705 @NonNull WindowInsetsAnimation animation) { 11706 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11707 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 11708 } 11709 } 11710 11711 /** 11712 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 11713 * when Window Insets animation is started. 11714 * @param animation current animation 11715 * @param bounds the upper and lower {@link Bounds} that provides range of 11716 * {@link WindowInsetsAnimation}. 11717 * @return the upper and lower {@link Bounds}. 11718 */ 11719 @NonNull dispatchWindowInsetsAnimationStart( @onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)11720 public Bounds dispatchWindowInsetsAnimationStart( 11721 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 11722 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11723 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 11724 } 11725 return bounds; 11726 } 11727 11728 /** 11729 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 11730 * when Window Insets animation makes progress. 11731 * @param insets The current {@link WindowInsets}. 11732 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 11733 * @return current {@link WindowInsets}. 11734 */ 11735 @NonNull dispatchWindowInsetsAnimationProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)11736 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 11737 @NonNull List<WindowInsetsAnimation> runningAnimations) { 11738 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11739 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 11740 runningAnimations); 11741 } else { 11742 return insets; 11743 } 11744 } 11745 11746 /** 11747 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 11748 * when Window Insets animation ends. 11749 * @param animation The current ongoing {@link WindowInsetsAnimation}. 11750 */ dispatchWindowInsetsAnimationEnd(@onNull WindowInsetsAnimation animation)11751 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 11752 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11753 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 11754 } 11755 } 11756 11757 /** 11758 * Sets a list of areas within this view's post-layout coordinate space where the system 11759 * should not intercept touch or other pointing device gestures. <em>This method should 11760 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 11761 * 11762 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 11763 * input in order to function correctly in the presence of global system gestures that may 11764 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 11765 * to provide system-level navigation functionality, a view such as a navigation drawer 11766 * container can mark the left (or starting) edge of itself as requiring gesture capture 11767 * priority using this API. The system may then choose to relax its own gesture recognition 11768 * to allow the app to consume the user's gesture. It is not necessary for an app to register 11769 * exclusion rects for broadly spanning regions such as the entirety of a 11770 * <code>ScrollView</code> or for simple press and release click targets such as 11771 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 11772 * a precision touch gesture in a small area in either the X or Y dimension, such as 11773 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 11774 * 11775 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 11776 * exclusions it takes into account. The limit does not apply while the navigation 11777 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 11778 * {@link android.inputmethodservice.InputMethodService input method} and 11779 * {@link Intent#CATEGORY_HOME home activity}. 11780 * </p> 11781 * 11782 * @param rects A list of precision gesture regions that this view needs to function correctly 11783 */ setSystemGestureExclusionRects(@onNull List<Rect> rects)11784 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 11785 if (rects.isEmpty() && mListenerInfo == null) return; 11786 11787 final ListenerInfo info = getListenerInfo(); 11788 if (info.mSystemGestureExclusionRects != null) { 11789 info.mSystemGestureExclusionRects.clear(); 11790 info.mSystemGestureExclusionRects.addAll(rects); 11791 } else { 11792 info.mSystemGestureExclusionRects = new ArrayList<>(rects); 11793 } 11794 11795 updatePositionUpdateListener(); 11796 postUpdate(this::updateSystemGestureExclusionRects); 11797 } 11798 updatePositionUpdateListener()11799 private void updatePositionUpdateListener() { 11800 final ListenerInfo info = getListenerInfo(); 11801 if (getSystemGestureExclusionRects().isEmpty() 11802 && collectPreferKeepClearRects().isEmpty() 11803 && collectUnrestrictedPreferKeepClearRects().isEmpty() 11804 && (info.mHandwritingArea == null || !isAutoHandwritingEnabled())) { 11805 if (info.mPositionUpdateListener != null) { 11806 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 11807 info.mPositionUpdateListener = null; 11808 info.mPositionChangedUpdate = null; 11809 } 11810 } else { 11811 if (info.mPositionUpdateListener == null) { 11812 info.mPositionChangedUpdate = () -> { 11813 updateSystemGestureExclusionRects(); 11814 updateKeepClearRects(); 11815 updateHandwritingArea(); 11816 }; 11817 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 11818 @Override 11819 public void positionChanged(long n, int l, int t, int r, int b) { 11820 postUpdate(info.mPositionChangedUpdate); 11821 } 11822 11823 @Override 11824 public void positionLost(long frameNumber) { 11825 postUpdate(info.mPositionChangedUpdate); 11826 } 11827 }; 11828 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 11829 } 11830 } 11831 } 11832 11833 /** 11834 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 11835 */ postUpdate(Runnable r)11836 private void postUpdate(Runnable r) { 11837 // Potentially racey from a background thread. It's ok if it's not perfect. 11838 final Handler h = getHandler(); 11839 if (h != null) { 11840 h.postAtFrontOfQueue(r); 11841 } 11842 } 11843 updateSystemGestureExclusionRects()11844 void updateSystemGestureExclusionRects() { 11845 final AttachInfo ai = mAttachInfo; 11846 if (ai != null) { 11847 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 11848 } 11849 } 11850 11851 /** 11852 * Retrieve the list of areas within this view's post-layout coordinate space where the system 11853 * should not intercept touch or other pointing device gestures. 11854 * 11855 * <p>Do not modify the returned list.</p> 11856 * 11857 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 11858 */ 11859 @NonNull getSystemGestureExclusionRects()11860 public List<Rect> getSystemGestureExclusionRects() { 11861 final ListenerInfo info = mListenerInfo; 11862 if (info != null) { 11863 final List<Rect> list = info.mSystemGestureExclusionRects; 11864 if (list != null) { 11865 return list; 11866 } 11867 } 11868 return Collections.emptyList(); 11869 } 11870 11871 /** 11872 * Set a preference to keep the bounds of this view clear from floating windows above this 11873 * view's window. This informs the system that the view is considered a vital area for the 11874 * user and that ideally it should not be covered. Setting this is only appropriate for UI 11875 * where the user would likely take action to uncover it. 11876 * <p> 11877 * The system will try to respect this preference, but when not possible will ignore it. 11878 * <p> 11879 * Note: This is independent from {@link #setPreferKeepClearRects}. If both are set, both will 11880 * be taken into account. 11881 * <p> 11882 * @see #setPreferKeepClearRects 11883 * @see #isPreferKeepClear 11884 * @attr ref android.R.styleable#View_preferKeepClear 11885 */ setPreferKeepClear(boolean preferKeepClear)11886 public final void setPreferKeepClear(boolean preferKeepClear) { 11887 getListenerInfo().mPreferKeepClear = preferKeepClear; 11888 updatePositionUpdateListener(); 11889 postUpdate(this::updateKeepClearRects); 11890 } 11891 11892 /** 11893 * Retrieve the preference for this view to be kept clear. This is set either by 11894 * {@link #setPreferKeepClear} or via the attribute android.R.styleable#View_preferKeepClear. 11895 * <p> 11896 * If this is {@code true}, the system will ignore the Rects set by 11897 * {@link #setPreferKeepClearRects} and try to keep the whole view clear. 11898 * <p> 11899 * @see #setPreferKeepClear 11900 * @attr ref android.R.styleable#View_preferKeepClear 11901 */ isPreferKeepClear()11902 public final boolean isPreferKeepClear() { 11903 return mListenerInfo != null && mListenerInfo.mPreferKeepClear; 11904 } 11905 11906 /** 11907 * Set a preference to keep the provided rects clear from floating windows above this 11908 * view's window. This informs the system that these rects are considered vital areas for the 11909 * user and that ideally they should not be covered. Setting this is only appropriate for UI 11910 * where the user would likely take action to uncover it. 11911 * <p> 11912 * The system will try to respect this preference, but when not possible will ignore it. 11913 * <p> 11914 * Note: This is independent from {@link #setPreferKeepClear}. If both are set, both will be 11915 * taken into account. 11916 * <p> 11917 * @see #setPreferKeepClear 11918 * @see #getPreferKeepClearRects 11919 * 11920 * @param rects A list of rects in this view's local coordinate system 11921 */ setPreferKeepClearRects(@onNull List<Rect> rects)11922 public final void setPreferKeepClearRects(@NonNull List<Rect> rects) { 11923 final ListenerInfo info = getListenerInfo(); 11924 if (info.mKeepClearRects != null) { 11925 info.mKeepClearRects.clear(); 11926 info.mKeepClearRects.addAll(rects); 11927 } else { 11928 info.mKeepClearRects = new ArrayList<>(rects); 11929 } 11930 updatePositionUpdateListener(); 11931 postUpdate(this::updateKeepClearRects); 11932 } 11933 11934 /** 11935 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 11936 * 11937 * @see #setPreferKeepClearRects 11938 */ 11939 @NonNull getPreferKeepClearRects()11940 public final List<Rect> getPreferKeepClearRects() { 11941 final ListenerInfo info = mListenerInfo; 11942 if (info != null && info.mKeepClearRects != null) { 11943 return new ArrayList(info.mKeepClearRects); 11944 } 11945 11946 return Collections.emptyList(); 11947 } 11948 11949 /** 11950 * Set a preference to keep the provided rects clear from floating windows above this 11951 * view's window. This informs the system that these rects are considered vital areas for the 11952 * user and that ideally they should not be covered. Setting this is only appropriate for UI 11953 * where the user would likely take action to uncover it. 11954 * <p> 11955 * Note: The difference with {@link #setPreferKeepClearRects} is that the system won't apply 11956 * restrictions to the rects set here. 11957 * <p> 11958 * @see #setPreferKeepClear 11959 * @see #getPreferKeepClearRects 11960 * 11961 * @param rects A list of rects in this view's local coordinate system 11962 * 11963 * @hide 11964 */ 11965 @SystemApi 11966 @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) setUnrestrictedPreferKeepClearRects(@onNull List<Rect> rects)11967 public final void setUnrestrictedPreferKeepClearRects(@NonNull List<Rect> rects) { 11968 final ListenerInfo info = getListenerInfo(); 11969 if (info.mUnrestrictedKeepClearRects != null) { 11970 info.mUnrestrictedKeepClearRects.clear(); 11971 info.mUnrestrictedKeepClearRects.addAll(rects); 11972 } else { 11973 info.mUnrestrictedKeepClearRects = new ArrayList<>(rects); 11974 } 11975 updatePositionUpdateListener(); 11976 postUpdate(this::updateKeepClearRects); 11977 } 11978 11979 /** 11980 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 11981 * 11982 * @see #setPreferKeepClearRects 11983 * 11984 * @hide 11985 */ 11986 @SystemApi 11987 @NonNull getUnrestrictedPreferKeepClearRects()11988 public final List<Rect> getUnrestrictedPreferKeepClearRects() { 11989 final ListenerInfo info = mListenerInfo; 11990 if (info != null && info.mUnrestrictedKeepClearRects != null) { 11991 return new ArrayList(info.mUnrestrictedKeepClearRects); 11992 } 11993 11994 return Collections.emptyList(); 11995 } 11996 updateKeepClearRects()11997 void updateKeepClearRects() { 11998 final AttachInfo ai = mAttachInfo; 11999 if (ai != null) { 12000 ai.mViewRootImpl.updateKeepClearRectsForView(this); 12001 } 12002 } 12003 12004 /** 12005 * Retrieve the list of areas within this view's post-layout coordinate space which the 12006 * system will try to not cover with other floating elements, like the pip window. 12007 */ 12008 @NonNull collectPreferKeepClearRects()12009 List<Rect> collectPreferKeepClearRects() { 12010 ListenerInfo info = mListenerInfo; 12011 boolean keepClearForFocus = isFocused() 12012 && ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled(); 12013 boolean keepBoundsClear = (info != null && info.mPreferKeepClear) || keepClearForFocus; 12014 boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null; 12015 12016 if (!keepBoundsClear && !hasCustomKeepClearRects) { 12017 return Collections.emptyList(); 12018 } else if (keepBoundsClear && !hasCustomKeepClearRects) { 12019 return Collections.singletonList(new Rect(0, 0, getWidth(), getHeight())); 12020 } 12021 12022 final List<Rect> list = new ArrayList<>(); 12023 if (keepBoundsClear) { 12024 list.add(new Rect(0, 0, getWidth(), getHeight())); 12025 } 12026 12027 if (hasCustomKeepClearRects) { 12028 list.addAll(info.mKeepClearRects); 12029 } 12030 12031 return list; 12032 } 12033 updatePreferKeepClearForFocus()12034 private void updatePreferKeepClearForFocus() { 12035 if (ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()) { 12036 updatePositionUpdateListener(); 12037 post(this::updateKeepClearRects); 12038 } 12039 } 12040 12041 /** 12042 * Retrieve the list of unrestricted areas within this view's post-layout coordinate space 12043 * which the system will try to not cover with other floating elements, like the pip window. 12044 */ 12045 @NonNull collectUnrestrictedPreferKeepClearRects()12046 List<Rect> collectUnrestrictedPreferKeepClearRects() { 12047 final ListenerInfo info = mListenerInfo; 12048 if (info != null && info.mUnrestrictedKeepClearRects != null) { 12049 return info.mUnrestrictedKeepClearRects; 12050 } 12051 12052 return Collections.emptyList(); 12053 } 12054 12055 /** 12056 * Set a list of handwriting areas in this view. If there is any stylus {@link MotionEvent} 12057 * occurs within those areas, it will trigger stylus handwriting mode. This can be disabled by 12058 * disabling the auto handwriting initiation by calling 12059 * {@link #setAutoHandwritingEnabled(boolean)} with false. 12060 * 12061 * @attr rects a list of handwriting area in the view's local coordiniates. 12062 * 12063 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 12064 * @see #setAutoHandwritingEnabled(boolean) 12065 * 12066 * @hide 12067 */ setHandwritingArea(@ullable Rect rect)12068 public void setHandwritingArea(@Nullable Rect rect) { 12069 final ListenerInfo info = getListenerInfo(); 12070 info.mHandwritingArea = rect; 12071 updatePositionUpdateListener(); 12072 postUpdate(this::updateHandwritingArea); 12073 } 12074 12075 /** 12076 * Return the handwriting areas set on this view, in its local coordinates. 12077 * @see #setHandwritingArea(Rect) 12078 * 12079 * @hide 12080 */ 12081 @Nullable getHandwritingArea()12082 public Rect getHandwritingArea() { 12083 final ListenerInfo info = mListenerInfo; 12084 if (info != null && info.mHandwritingArea != null) { 12085 return new Rect(info.mHandwritingArea); 12086 } 12087 return null; 12088 } 12089 updateHandwritingArea()12090 void updateHandwritingArea() { 12091 // If autoHandwritingArea is not enabled, do nothing. 12092 if (!isAutoHandwritingEnabled()) return; 12093 final AttachInfo ai = mAttachInfo; 12094 if (ai != null) { 12095 ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this); 12096 } 12097 } 12098 12099 /** 12100 * Gets the coordinates of this view in the coordinate space of the 12101 * {@link Surface} that contains the view. 12102 * 12103 * <p>In multiple-screen scenarios, if the surface spans multiple screens, 12104 * the coordinate space of the surface also spans multiple screens. 12105 * 12106 * <p>After the method returns, the argument array contains the x and y 12107 * coordinates of the view relative to the view's left and top edges, 12108 * respectively. 12109 * 12110 * @param location A two-element integer array in which the view coordinates 12111 * are stored. The x-coordinate is at index 0; the y-coordinate, at 12112 * index 1. 12113 */ getLocationInSurface(@onNull @ize2) int[] location)12114 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 12115 getLocationInWindow(location); 12116 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 12117 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 12118 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 12119 } 12120 } 12121 12122 /** 12123 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 12124 * only available if the view is attached. 12125 * 12126 * @return WindowInsets from the top of the view hierarchy or null if View is detached 12127 */ getRootWindowInsets()12128 public WindowInsets getRootWindowInsets() { 12129 if (mAttachInfo != null) { 12130 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 12131 } 12132 return null; 12133 } 12134 12135 /** 12136 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 12137 * 12138 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 12139 * a window nor a view tree with a decor. 12140 * @see Window#getInsetsController() 12141 */ getWindowInsetsController()12142 public @Nullable WindowInsetsController getWindowInsetsController() { 12143 if (mAttachInfo != null) { 12144 return mAttachInfo.mViewRootImpl.getInsetsController(); 12145 } 12146 ViewParent parent = getParent(); 12147 if (parent instanceof View) { 12148 return ((View) parent).getWindowInsetsController(); 12149 } else if (parent instanceof ViewRootImpl) { 12150 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 12151 return ((ViewRootImpl) parent).getInsetsController(); 12152 } 12153 return null; 12154 } 12155 12156 12157 /** 12158 * Walk up the View hierarchy to find the nearest {@link OnBackInvokedDispatcher}. 12159 * 12160 * @return The {@link OnBackInvokedDispatcher} from this or the nearest 12161 * ancestor, or null if this view is both not attached and have no ancestor providing an 12162 * {@link OnBackInvokedDispatcher}. 12163 */ 12164 @Nullable findOnBackInvokedDispatcher()12165 public final OnBackInvokedDispatcher findOnBackInvokedDispatcher() { 12166 ViewParent parent = getParent(); 12167 if (parent != null) { 12168 return parent.findOnBackInvokedDispatcherForChild(this, this); 12169 } 12170 return null; 12171 } 12172 12173 /** 12174 * @hide Compute the insets that should be consumed by this view and the ones 12175 * that should propagate to those under it. 12176 * 12177 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 12178 * 12179 * @param inoutInsets the insets given to this view 12180 * @param outLocalInsets the insets that should be applied to this view 12181 * @deprecated use {@link #computeSystemWindowInsets} 12182 * @return 12183 */ 12184 @Deprecated 12185 @UnsupportedAppUsage computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets)12186 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 12187 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 12188 outLocalInsets); 12189 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 12190 return innerInsets.isSystemWindowInsetsConsumed(); 12191 } 12192 12193 /** 12194 * Compute insets that should be consumed by this view and the ones that should propagate 12195 * to those under it. 12196 * 12197 * @param in Insets currently being processed by this View, likely received as a parameter 12198 * to {@link #onApplyWindowInsets(WindowInsets)}. 12199 * @param outLocalInsets A Rect that will receive the insets that should be consumed 12200 * by this view 12201 * @return Insets that should be passed along to views under this one 12202 */ computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets)12203 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 12204 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 12205 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 12206 if (isOptionalFitSystemWindows && mAttachInfo != null) { 12207 OnContentApplyWindowInsetsListener listener = 12208 mAttachInfo.mContentOnApplyWindowInsetsListener; 12209 if (listener == null) { 12210 // The application wants to take care of fitting system window for 12211 // the content. 12212 outLocalInsets.setEmpty(); 12213 return in; 12214 } 12215 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 12216 outLocalInsets.set(result.first.toRect()); 12217 return result.second; 12218 } else { 12219 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 12220 return in.consumeSystemWindowInsets().inset(outLocalInsets); 12221 } 12222 } 12223 12224 /** 12225 * Sets whether or not this view should account for system screen decorations 12226 * such as the status bar and inset its content; that is, controlling whether 12227 * the default implementation of {@link #fitSystemWindows(Rect)} will be 12228 * executed. See that method for more details. 12229 * 12230 * <p>Note that if you are providing your own implementation of 12231 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 12232 * flag to true -- your implementation will be overriding the default 12233 * implementation that checks this flag. 12234 * 12235 * @param fitSystemWindows If true, then the default implementation of 12236 * {@link #fitSystemWindows(Rect)} will be executed. 12237 * 12238 * @attr ref android.R.styleable#View_fitsSystemWindows 12239 * @see #getFitsSystemWindows() 12240 * @see #fitSystemWindows(Rect) 12241 * @see #setSystemUiVisibility(int) 12242 */ setFitsSystemWindows(boolean fitSystemWindows)12243 public void setFitsSystemWindows(boolean fitSystemWindows) { 12244 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 12245 } 12246 12247 /** 12248 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 12249 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 12250 * will be executed. 12251 * 12252 * @return {@code true} if the default implementation of 12253 * {@link #fitSystemWindows(Rect)} will be executed. 12254 * 12255 * @attr ref android.R.styleable#View_fitsSystemWindows 12256 * @see #setFitsSystemWindows(boolean) 12257 * @see #fitSystemWindows(Rect) 12258 * @see #setSystemUiVisibility(int) 12259 */ 12260 @ViewDebug.ExportedProperty 12261 @InspectableProperty getFitsSystemWindows()12262 public boolean getFitsSystemWindows() { 12263 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 12264 } 12265 12266 /** @hide */ 12267 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) fitsSystemWindows()12268 public boolean fitsSystemWindows() { 12269 return getFitsSystemWindows(); 12270 } 12271 12272 /** 12273 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 12274 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 12275 */ 12276 @Deprecated requestFitSystemWindows()12277 public void requestFitSystemWindows() { 12278 if (mParent != null) { 12279 mParent.requestFitSystemWindows(); 12280 } 12281 } 12282 12283 /** 12284 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 12285 */ requestApplyInsets()12286 public void requestApplyInsets() { 12287 requestFitSystemWindows(); 12288 } 12289 12290 /** 12291 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 12292 * @hide 12293 */ 12294 @UnsupportedAppUsage makeOptionalFitsSystemWindows()12295 public void makeOptionalFitsSystemWindows() { 12296 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 12297 } 12298 12299 /** 12300 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 12301 * @hide 12302 */ makeFrameworkOptionalFitsSystemWindows()12303 public void makeFrameworkOptionalFitsSystemWindows() { 12304 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 12305 } 12306 12307 /** 12308 * @hide 12309 */ isFrameworkOptionalFitsSystemWindows()12310 public boolean isFrameworkOptionalFitsSystemWindows() { 12311 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 12312 } 12313 12314 /** 12315 * Returns the visibility status for this view. 12316 * 12317 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 12318 * @attr ref android.R.styleable#View_visibility 12319 */ 12320 @ViewDebug.ExportedProperty(mapping = { 12321 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 12322 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 12323 @ViewDebug.IntToString(from = GONE, to = "GONE") 12324 }) 12325 @InspectableProperty(enumMapping = { 12326 @EnumEntry(value = VISIBLE, name = "visible"), 12327 @EnumEntry(value = INVISIBLE, name = "invisible"), 12328 @EnumEntry(value = GONE, name = "gone") 12329 }) 12330 @Visibility getVisibility()12331 public int getVisibility() { 12332 return mViewFlags & VISIBILITY_MASK; 12333 } 12334 12335 /** 12336 * Set the visibility state of this view. 12337 * 12338 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 12339 * @attr ref android.R.styleable#View_visibility 12340 */ 12341 @RemotableViewMethod setVisibility(@isibility int visibility)12342 public void setVisibility(@Visibility int visibility) { 12343 setFlags(visibility, VISIBILITY_MASK); 12344 } 12345 12346 /** 12347 * Returns the enabled status for this view. The interpretation of the 12348 * enabled state varies by subclass. 12349 * 12350 * @return True if this view is enabled, false otherwise. 12351 */ 12352 @ViewDebug.ExportedProperty 12353 @InspectableProperty isEnabled()12354 public boolean isEnabled() { 12355 return (mViewFlags & ENABLED_MASK) == ENABLED; 12356 } 12357 12358 /** 12359 * Set the enabled state of this view. The interpretation of the enabled 12360 * state varies by subclass. 12361 * 12362 * @param enabled True if this view is enabled, false otherwise. 12363 */ 12364 @RemotableViewMethod setEnabled(boolean enabled)12365 public void setEnabled(boolean enabled) { 12366 if (enabled == isEnabled()) return; 12367 12368 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 12369 12370 /* 12371 * The View most likely has to change its appearance, so refresh 12372 * the drawable state. 12373 */ 12374 refreshDrawableState(); 12375 12376 // Invalidate too, since the default behavior for views is to be 12377 // be drawn at 50% alpha rather than to change the drawable. 12378 invalidate(true); 12379 12380 if (!enabled) { 12381 cancelPendingInputEvents(); 12382 } 12383 } 12384 12385 /** 12386 * Set whether this view can receive the focus. 12387 * <p> 12388 * Setting this to false will also ensure that this view is not focusable 12389 * in touch mode. 12390 * 12391 * @param focusable If true, this view can receive the focus. 12392 * 12393 * @see #setFocusableInTouchMode(boolean) 12394 * @see #setFocusable(int) 12395 * @attr ref android.R.styleable#View_focusable 12396 */ 12397 @RemotableViewMethod setFocusable(boolean focusable)12398 public void setFocusable(boolean focusable) { 12399 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 12400 } 12401 12402 /** 12403 * Sets whether this view can receive focus. 12404 * <p> 12405 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 12406 * automatically based on the view's interactivity. This is the default. 12407 * <p> 12408 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 12409 * in touch mode. 12410 * 12411 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 12412 * or {@link #FOCUSABLE_AUTO}. 12413 * @see #setFocusableInTouchMode(boolean) 12414 * @attr ref android.R.styleable#View_focusable 12415 */ 12416 @RemotableViewMethod setFocusable(@ocusable int focusable)12417 public void setFocusable(@Focusable int focusable) { 12418 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 12419 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 12420 } 12421 setFlags(focusable, FOCUSABLE_MASK); 12422 } 12423 12424 /** 12425 * Set whether this view can receive focus while in touch mode. 12426 * 12427 * Setting this to true will also ensure that this view is focusable. 12428 * 12429 * @param focusableInTouchMode If true, this view can receive the focus while 12430 * in touch mode. 12431 * 12432 * @see #setFocusable(boolean) 12433 * @attr ref android.R.styleable#View_focusableInTouchMode 12434 */ 12435 @RemotableViewMethod setFocusableInTouchMode(boolean focusableInTouchMode)12436 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 12437 // Focusable in touch mode should always be set before the focusable flag 12438 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 12439 // which, in touch mode, will not successfully request focus on this view 12440 // because the focusable in touch mode flag is not set 12441 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 12442 12443 // Clear FOCUSABLE_AUTO if set. 12444 if (focusableInTouchMode) { 12445 // Clears FOCUSABLE_AUTO if set. 12446 setFlags(FOCUSABLE, FOCUSABLE_MASK); 12447 } 12448 } 12449 12450 /** 12451 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 12452 * to autofill the view with the user's data. 12453 * 12454 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 12455 * For example, if the application accepts either an username or email address to identify 12456 * an user. 12457 * 12458 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 12459 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 12460 * constants such as: 12461 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 12462 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 12463 * {@link #AUTOFILL_HINT_NAME}, 12464 * {@link #AUTOFILL_HINT_PHONE}, 12465 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 12466 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 12467 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 12468 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 12469 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 12470 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 12471 * 12472 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 12473 * @attr ref android.R.styleable#View_autofillHints 12474 */ setAutofillHints(@ullable String... autofillHints)12475 public void setAutofillHints(@Nullable String... autofillHints) { 12476 if (autofillHints == null || autofillHints.length == 0) { 12477 mAutofillHints = null; 12478 } else { 12479 mAutofillHints = autofillHints; 12480 } 12481 } 12482 12483 /** 12484 * @hide 12485 */ 12486 @TestApi setAutofilled(boolean isAutofilled, boolean hideHighlight)12487 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 12488 boolean wasChanged = isAutofilled != isAutofilled(); 12489 12490 if (wasChanged) { 12491 if (isAutofilled) { 12492 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 12493 } else { 12494 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 12495 } 12496 12497 if (hideHighlight) { 12498 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 12499 } else { 12500 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 12501 } 12502 12503 invalidate(); 12504 } 12505 } 12506 12507 /** 12508 * Set whether this view should have sound effects enabled for events such as 12509 * clicking and touching. 12510 * 12511 * <p>You may wish to disable sound effects for a view if you already play sounds, 12512 * for instance, a dial key that plays dtmf tones. 12513 * 12514 * @param soundEffectsEnabled whether sound effects are enabled for this view. 12515 * @see #isSoundEffectsEnabled() 12516 * @see #playSoundEffect(int) 12517 * @attr ref android.R.styleable#View_soundEffectsEnabled 12518 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)12519 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 12520 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 12521 } 12522 12523 /** 12524 * @return whether this view should have sound effects enabled for events such as 12525 * clicking and touching. 12526 * 12527 * @see #setSoundEffectsEnabled(boolean) 12528 * @see #playSoundEffect(int) 12529 * @attr ref android.R.styleable#View_soundEffectsEnabled 12530 */ 12531 @ViewDebug.ExportedProperty 12532 @InspectableProperty isSoundEffectsEnabled()12533 public boolean isSoundEffectsEnabled() { 12534 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 12535 } 12536 12537 /** 12538 * Set whether this view should have haptic feedback for events such as 12539 * long presses. 12540 * 12541 * <p>You may wish to disable haptic feedback if your view already controls 12542 * its own haptic feedback. 12543 * 12544 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 12545 * @see #isHapticFeedbackEnabled() 12546 * @see #performHapticFeedback(int) 12547 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 12548 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)12549 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 12550 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 12551 } 12552 12553 /** 12554 * @return whether this view should have haptic feedback enabled for events 12555 * such as long presses. 12556 * 12557 * @see #setHapticFeedbackEnabled(boolean) 12558 * @see #performHapticFeedback(int) 12559 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 12560 */ 12561 @ViewDebug.ExportedProperty 12562 @InspectableProperty isHapticFeedbackEnabled()12563 public boolean isHapticFeedbackEnabled() { 12564 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 12565 } 12566 12567 /** 12568 * Returns the layout direction for this view. 12569 * 12570 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 12571 * {@link #LAYOUT_DIRECTION_RTL}, 12572 * {@link #LAYOUT_DIRECTION_INHERIT} or 12573 * {@link #LAYOUT_DIRECTION_LOCALE}. 12574 * 12575 * @attr ref android.R.styleable#View_layoutDirection 12576 * 12577 * @hide 12578 */ 12579 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12580 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 12581 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 12582 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 12583 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 12584 }) 12585 @InspectableProperty(hasAttributeId = false, enumMapping = { 12586 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12587 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 12588 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 12589 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 12590 }) 12591 @LayoutDir getRawLayoutDirection()12592 public int getRawLayoutDirection() { 12593 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 12594 } 12595 12596 /** 12597 * Set the layout direction for this view. This will propagate a reset of layout direction 12598 * resolution to the view's children and resolve layout direction for this view. 12599 * 12600 * @param layoutDirection the layout direction to set. Should be one of: 12601 * 12602 * {@link #LAYOUT_DIRECTION_LTR}, 12603 * {@link #LAYOUT_DIRECTION_RTL}, 12604 * {@link #LAYOUT_DIRECTION_INHERIT}, 12605 * {@link #LAYOUT_DIRECTION_LOCALE}. 12606 * 12607 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 12608 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 12609 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 12610 * 12611 * @attr ref android.R.styleable#View_layoutDirection 12612 */ 12613 @RemotableViewMethod setLayoutDirection(@ayoutDir int layoutDirection)12614 public void setLayoutDirection(@LayoutDir int layoutDirection) { 12615 if (getRawLayoutDirection() != layoutDirection) { 12616 // Reset the current layout direction and the resolved one 12617 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 12618 resetRtlProperties(); 12619 // Set the new layout direction (filtered) 12620 mPrivateFlags2 |= 12621 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 12622 // We need to resolve all RTL properties as they all depend on layout direction 12623 resolveRtlPropertiesIfNeeded(); 12624 requestLayout(); 12625 invalidate(true); 12626 } 12627 } 12628 12629 /** 12630 * Returns the resolved layout direction for this view. 12631 * 12632 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 12633 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 12634 * 12635 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 12636 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 12637 * 12638 * @attr ref android.R.styleable#View_layoutDirection 12639 */ 12640 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12641 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 12642 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 12643 }) 12644 @InspectableProperty(enumMapping = { 12645 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12646 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 12647 }) 12648 @ResolvedLayoutDir getLayoutDirection()12649 public int getLayoutDirection() { 12650 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 12651 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 12652 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 12653 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 12654 } 12655 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 12656 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 12657 } 12658 12659 /** 12660 * Indicates whether or not this view's layout is right-to-left. This is resolved from 12661 * layout attribute and/or the inherited value from the parent 12662 * 12663 * @return true if the layout is right-to-left. 12664 * 12665 * @hide 12666 */ 12667 @ViewDebug.ExportedProperty(category = "layout") 12668 @UnsupportedAppUsage isLayoutRtl()12669 public boolean isLayoutRtl() { 12670 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 12671 } 12672 12673 /** 12674 * Indicates whether the view is currently tracking transient state that the 12675 * app should not need to concern itself with saving and restoring, but that 12676 * the framework should take special note to preserve when possible. 12677 * 12678 * <p>A view with transient state cannot be trivially rebound from an external 12679 * data source, such as an adapter binding item views in a list. This may be 12680 * because the view is performing an animation, tracking user selection 12681 * of content, or similar.</p> 12682 * 12683 * @return true if the view has transient state 12684 */ 12685 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()12686 public boolean hasTransientState() { 12687 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 12688 } 12689 12690 /** 12691 * Set whether this view is currently tracking transient state that the 12692 * framework should attempt to preserve when possible. This flag is reference counted, 12693 * so every call to setHasTransientState(true) should be paired with a later call 12694 * to setHasTransientState(false). 12695 * 12696 * <p>A view with transient state cannot be trivially rebound from an external 12697 * data source, such as an adapter binding item views in a list. This may be 12698 * because the view is performing an animation, tracking user selection 12699 * of content, or similar.</p> 12700 * 12701 * @param hasTransientState true if this view has transient state 12702 */ setHasTransientState(boolean hasTransientState)12703 public void setHasTransientState(boolean hasTransientState) { 12704 final boolean oldHasTransientState = hasTransientState(); 12705 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 12706 mTransientStateCount - 1; 12707 if (mTransientStateCount < 0) { 12708 mTransientStateCount = 0; 12709 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 12710 "unmatched pair of setHasTransientState calls"); 12711 } else if ((hasTransientState && mTransientStateCount == 1) || 12712 (!hasTransientState && mTransientStateCount == 0)) { 12713 // update flag if we've just incremented up from 0 or decremented down to 0 12714 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 12715 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 12716 final boolean newHasTransientState = hasTransientState(); 12717 if (mParent != null && newHasTransientState != oldHasTransientState) { 12718 try { 12719 mParent.childHasTransientStateChanged(this, newHasTransientState); 12720 } catch (AbstractMethodError e) { 12721 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 12722 " does not fully implement ViewParent", e); 12723 } 12724 } 12725 } 12726 } 12727 12728 /** 12729 * Set the view is tracking translation transient state. This flag is used to check if the view 12730 * need to call setHasTransientState(false) to reset transient state that set when starting 12731 * translation. 12732 * 12733 * @param hasTranslationTransientState true if this view has translation transient state 12734 * @hide 12735 */ setHasTranslationTransientState(boolean hasTranslationTransientState)12736 public void setHasTranslationTransientState(boolean hasTranslationTransientState) { 12737 if (hasTranslationTransientState) { 12738 mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12739 } else { 12740 mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12741 } 12742 } 12743 12744 /** 12745 * @hide 12746 */ hasTranslationTransientState()12747 public boolean hasTranslationTransientState() { 12748 return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) 12749 == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12750 } 12751 12752 /** 12753 * @hide 12754 */ clearTranslationState()12755 public void clearTranslationState() { 12756 if (mViewTranslationCallback != null) { 12757 mViewTranslationCallback.onClearTranslation(this); 12758 } 12759 clearViewTranslationResponse(); 12760 if (hasTranslationTransientState()) { 12761 setHasTransientState(false); 12762 setHasTranslationTransientState(false); 12763 } 12764 } 12765 12766 /** 12767 * Returns true if this view is currently attached to a window. 12768 */ isAttachedToWindow()12769 public boolean isAttachedToWindow() { 12770 return mAttachInfo != null; 12771 } 12772 12773 /** 12774 * Returns true if this view has been through at least one layout since it 12775 * was last attached to or detached from a window. 12776 */ isLaidOut()12777 public boolean isLaidOut() { 12778 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 12779 } 12780 12781 /** 12782 * @return {@code true} if laid-out and not about to do another layout. 12783 */ isLayoutValid()12784 boolean isLayoutValid() { 12785 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 12786 } 12787 12788 /** 12789 * If this view doesn't do any drawing on its own, set this flag to 12790 * allow further optimizations. By default, this flag is not set on 12791 * View, but could be set on some View subclasses such as ViewGroup. 12792 * 12793 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 12794 * you should clear this flag. 12795 * 12796 * @param willNotDraw whether or not this View draw on its own 12797 */ setWillNotDraw(boolean willNotDraw)12798 public void setWillNotDraw(boolean willNotDraw) { 12799 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 12800 } 12801 12802 /** 12803 * Returns whether or not this View draws on its own. 12804 * 12805 * @return true if this view has nothing to draw, false otherwise 12806 */ 12807 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()12808 public boolean willNotDraw() { 12809 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 12810 } 12811 12812 /** 12813 * When a View's drawing cache is enabled, drawing is redirected to an 12814 * offscreen bitmap. Some views, like an ImageView, must be able to 12815 * bypass this mechanism if they already draw a single bitmap, to avoid 12816 * unnecessary usage of the memory. 12817 * 12818 * @param willNotCacheDrawing true if this view does not cache its 12819 * drawing, false otherwise 12820 * 12821 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12822 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12823 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12824 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12825 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12826 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12827 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12828 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12829 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12830 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12831 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12832 * reports or unit testing the {@link PixelCopy} API is recommended. 12833 */ 12834 @Deprecated setWillNotCacheDrawing(boolean willNotCacheDrawing)12835 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 12836 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 12837 } 12838 12839 /** 12840 * Returns whether or not this View can cache its drawing or not. 12841 * 12842 * @return true if this view does not cache its drawing, false otherwise 12843 * 12844 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12845 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12846 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12847 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12848 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12849 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12850 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12851 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12852 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12853 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12854 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12855 * reports or unit testing the {@link PixelCopy} API is recommended. 12856 */ 12857 @ViewDebug.ExportedProperty(category = "drawing") 12858 @Deprecated willNotCacheDrawing()12859 public boolean willNotCacheDrawing() { 12860 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 12861 } 12862 12863 /** 12864 * Indicates whether this view reacts to click events or not. 12865 * 12866 * @return true if the view is clickable, false otherwise 12867 * 12868 * @see #setClickable(boolean) 12869 * @attr ref android.R.styleable#View_clickable 12870 */ 12871 @ViewDebug.ExportedProperty 12872 @InspectableProperty isClickable()12873 public boolean isClickable() { 12874 return (mViewFlags & CLICKABLE) == CLICKABLE; 12875 } 12876 12877 /** 12878 * Enables or disables click events for this view. When a view 12879 * is clickable it will change its state to "pressed" on every click. 12880 * Subclasses should set the view clickable to visually react to 12881 * user's clicks. 12882 * 12883 * @param clickable true to make the view clickable, false otherwise 12884 * 12885 * @see #isClickable() 12886 * @attr ref android.R.styleable#View_clickable 12887 */ setClickable(boolean clickable)12888 public void setClickable(boolean clickable) { 12889 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 12890 } 12891 12892 /** 12893 * Enables or disables click events for this view when disabled. 12894 * 12895 * @param clickableWhenDisabled true to make the view clickable, false otherwise 12896 * 12897 * @attr ref android.R.styleable#View_allowClickWhenDisabled 12898 */ setAllowClickWhenDisabled(boolean clickableWhenDisabled)12899 public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { 12900 if (clickableWhenDisabled) { 12901 mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 12902 } else { 12903 mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 12904 } 12905 } 12906 12907 /** 12908 * Indicates whether this view reacts to long click events or not. 12909 * 12910 * @return true if the view is long clickable, false otherwise 12911 * 12912 * @see #setLongClickable(boolean) 12913 * @attr ref android.R.styleable#View_longClickable 12914 */ 12915 @InspectableProperty isLongClickable()12916 public boolean isLongClickable() { 12917 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12918 } 12919 12920 /** 12921 * Enables or disables long click events for this view. When a view is long 12922 * clickable it reacts to the user holding down the button for a longer 12923 * duration than a tap. This event can either launch the listener or a 12924 * context menu. 12925 * 12926 * @param longClickable true to make the view long clickable, false otherwise 12927 * @see #isLongClickable() 12928 * @attr ref android.R.styleable#View_longClickable 12929 */ setLongClickable(boolean longClickable)12930 public void setLongClickable(boolean longClickable) { 12931 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 12932 } 12933 12934 /** 12935 * Indicates whether this view reacts to context clicks or not. 12936 * 12937 * @return true if the view is context clickable, false otherwise 12938 * @see #setContextClickable(boolean) 12939 * @attr ref android.R.styleable#View_contextClickable 12940 */ 12941 @InspectableProperty isContextClickable()12942 public boolean isContextClickable() { 12943 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12944 } 12945 12946 /** 12947 * Enables or disables context clicking for this view. This event can launch the listener. 12948 * 12949 * @param contextClickable true to make the view react to a context click, false otherwise 12950 * @see #isContextClickable() 12951 * @attr ref android.R.styleable#View_contextClickable 12952 */ setContextClickable(boolean contextClickable)12953 public void setContextClickable(boolean contextClickable) { 12954 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 12955 } 12956 12957 /** 12958 * Sets the pressed state for this view and provides a touch coordinate for 12959 * animation hinting. 12960 * 12961 * @param pressed Pass true to set the View's internal state to "pressed", 12962 * or false to reverts the View's internal state from a 12963 * previously set "pressed" state. 12964 * @param x The x coordinate of the touch that caused the press 12965 * @param y The y coordinate of the touch that caused the press 12966 */ setPressed(boolean pressed, float x, float y)12967 private void setPressed(boolean pressed, float x, float y) { 12968 if (pressed) { 12969 drawableHotspotChanged(x, y); 12970 } 12971 12972 setPressed(pressed); 12973 } 12974 12975 /** 12976 * Sets the pressed state for this view. 12977 * 12978 * @see #isClickable() 12979 * @see #setClickable(boolean) 12980 * 12981 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 12982 * the View's internal state from a previously set "pressed" state. 12983 */ setPressed(boolean pressed)12984 public void setPressed(boolean pressed) { 12985 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 12986 12987 if (pressed) { 12988 mPrivateFlags |= PFLAG_PRESSED; 12989 } else { 12990 mPrivateFlags &= ~PFLAG_PRESSED; 12991 } 12992 12993 if (needsRefresh) { 12994 refreshDrawableState(); 12995 } 12996 dispatchSetPressed(pressed); 12997 } 12998 12999 /** 13000 * Dispatch setPressed to all of this View's children. 13001 * 13002 * @see #setPressed(boolean) 13003 * 13004 * @param pressed The new pressed state 13005 */ dispatchSetPressed(boolean pressed)13006 protected void dispatchSetPressed(boolean pressed) { 13007 } 13008 13009 /** 13010 * Indicates whether the view is currently in pressed state. Unless 13011 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 13012 * the pressed state. 13013 * 13014 * @see #setPressed(boolean) 13015 * @see #isClickable() 13016 * @see #setClickable(boolean) 13017 * 13018 * @return true if the view is currently pressed, false otherwise 13019 */ 13020 @ViewDebug.ExportedProperty 13021 @InspectableProperty(hasAttributeId = false) isPressed()13022 public boolean isPressed() { 13023 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 13024 } 13025 13026 /** 13027 * @hide 13028 * Indicates whether this view will participate in data collection through 13029 * {@link ViewStructure}. If true, it will not provide any data 13030 * for itself or its children. If false, the normal data collection will be allowed. 13031 * 13032 * @return Returns false if assist data collection is not blocked, else true. 13033 * 13034 * @see #setAssistBlocked(boolean) 13035 * @attr ref android.R.styleable#View_assistBlocked 13036 */ isAssistBlocked()13037 public boolean isAssistBlocked() { 13038 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 13039 } 13040 13041 /** 13042 * @hide 13043 * Controls whether assist data collection from this view and its children is enabled 13044 * (that is, whether {@link #onProvideStructure} and 13045 * {@link #onProvideVirtualStructure} will be called). The default value is false, 13046 * allowing normal assist collection. Setting this to false will disable assist collection. 13047 * 13048 * @param enabled Set to true to <em>disable</em> assist data collection, or false 13049 * (the default) to allow it. 13050 * 13051 * @see #isAssistBlocked() 13052 * @see #onProvideStructure 13053 * @see #onProvideVirtualStructure 13054 * @attr ref android.R.styleable#View_assistBlocked 13055 */ 13056 @UnsupportedAppUsage setAssistBlocked(boolean enabled)13057 public void setAssistBlocked(boolean enabled) { 13058 if (enabled) { 13059 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 13060 } else { 13061 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 13062 } 13063 } 13064 13065 /** 13066 * Indicates whether this view will save its state (that is, 13067 * whether its {@link #onSaveInstanceState} method will be called). 13068 * 13069 * @return Returns true if the view state saving is enabled, else false. 13070 * 13071 * @see #setSaveEnabled(boolean) 13072 * @attr ref android.R.styleable#View_saveEnabled 13073 */ 13074 @InspectableProperty isSaveEnabled()13075 public boolean isSaveEnabled() { 13076 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 13077 } 13078 13079 /** 13080 * Controls whether the saving of this view's state is 13081 * enabled (that is, whether its {@link #onSaveInstanceState} method 13082 * will be called). Note that even if freezing is enabled, the 13083 * view still must have an id assigned to it (via {@link #setId(int)}) 13084 * for its state to be saved. This flag can only disable the 13085 * saving of this view; any child views may still have their state saved. 13086 * 13087 * @param enabled Set to false to <em>disable</em> state saving, or true 13088 * (the default) to allow it. 13089 * 13090 * @see #isSaveEnabled() 13091 * @see #setId(int) 13092 * @see #onSaveInstanceState() 13093 * @attr ref android.R.styleable#View_saveEnabled 13094 */ setSaveEnabled(boolean enabled)13095 public void setSaveEnabled(boolean enabled) { 13096 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 13097 } 13098 13099 /** 13100 * Gets whether the framework should discard touches when the view's 13101 * window is obscured by another visible window at the touched location. 13102 * Refer to the {@link View} security documentation for more details. 13103 * 13104 * @return True if touch filtering is enabled. 13105 * 13106 * @see #setFilterTouchesWhenObscured(boolean) 13107 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 13108 */ 13109 @ViewDebug.ExportedProperty 13110 @InspectableProperty getFilterTouchesWhenObscured()13111 public boolean getFilterTouchesWhenObscured() { 13112 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 13113 } 13114 13115 /** 13116 * Sets whether the framework should discard touches when the view's 13117 * window is obscured by another visible window at the touched location. 13118 * Refer to the {@link View} security documentation for more details. 13119 * 13120 * @param enabled True if touch filtering should be enabled. 13121 * 13122 * @see #getFilterTouchesWhenObscured 13123 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 13124 */ setFilterTouchesWhenObscured(boolean enabled)13125 public void setFilterTouchesWhenObscured(boolean enabled) { 13126 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 13127 FILTER_TOUCHES_WHEN_OBSCURED); 13128 } 13129 13130 /** 13131 * Indicates whether the entire hierarchy under this view will save its 13132 * state when a state saving traversal occurs from its parent. The default 13133 * is true; if false, these views will not be saved unless 13134 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 13135 * 13136 * @return Returns true if the view state saving from parent is enabled, else false. 13137 * 13138 * @see #setSaveFromParentEnabled(boolean) 13139 */ isSaveFromParentEnabled()13140 public boolean isSaveFromParentEnabled() { 13141 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 13142 } 13143 13144 /** 13145 * Controls whether the entire hierarchy under this view will save its 13146 * state when a state saving traversal occurs from its parent. The default 13147 * is true; if false, these views will not be saved unless 13148 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 13149 * 13150 * @param enabled Set to false to <em>disable</em> state saving, or true 13151 * (the default) to allow it. 13152 * 13153 * @see #isSaveFromParentEnabled() 13154 * @see #setId(int) 13155 * @see #onSaveInstanceState() 13156 */ setSaveFromParentEnabled(boolean enabled)13157 public void setSaveFromParentEnabled(boolean enabled) { 13158 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 13159 } 13160 13161 13162 /** 13163 * Returns whether this View is currently able to take focus. 13164 * 13165 * @return True if this view can take focus, or false otherwise. 13166 */ 13167 @ViewDebug.ExportedProperty(category = "focus") isFocusable()13168 public final boolean isFocusable() { 13169 return FOCUSABLE == (mViewFlags & FOCUSABLE); 13170 } 13171 13172 /** 13173 * Returns the focusable setting for this view. 13174 * 13175 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 13176 * @attr ref android.R.styleable#View_focusable 13177 */ 13178 @ViewDebug.ExportedProperty(mapping = { 13179 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 13180 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 13181 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 13182 }, category = "focus") 13183 @InspectableProperty(enumMapping = { 13184 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 13185 @EnumEntry(value = FOCUSABLE, name = "true"), 13186 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 13187 }) 13188 @Focusable getFocusable()13189 public int getFocusable() { 13190 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 13191 } 13192 13193 /** 13194 * When a view is focusable, it may not want to take focus when in touch mode. 13195 * For example, a button would like focus when the user is navigating via a D-pad 13196 * so that the user can click on it, but once the user starts touching the screen, 13197 * the button shouldn't take focus 13198 * @return Whether the view is focusable in touch mode. 13199 * @attr ref android.R.styleable#View_focusableInTouchMode 13200 */ 13201 @ViewDebug.ExportedProperty(category = "focus") 13202 @InspectableProperty isFocusableInTouchMode()13203 public final boolean isFocusableInTouchMode() { 13204 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 13205 } 13206 13207 /** 13208 * Returns whether the view should be treated as a focusable unit by screen reader 13209 * accessibility tools. 13210 * @see #setScreenReaderFocusable(boolean) 13211 * 13212 * @return Whether the view should be treated as a focusable unit by screen reader. 13213 * 13214 * @attr ref android.R.styleable#View_screenReaderFocusable 13215 */ 13216 @InspectableProperty isScreenReaderFocusable()13217 public boolean isScreenReaderFocusable() { 13218 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 13219 } 13220 13221 /** 13222 * Sets whether this View should be a focusable element for screen readers 13223 * and include non-focusable Views from its subtree when providing feedback. 13224 * <p> 13225 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 13226 * but does not impact input focus behavior. 13227 * 13228 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 13229 * accessibility tools. 13230 * 13231 * @attr ref android.R.styleable#View_screenReaderFocusable 13232 */ setScreenReaderFocusable(boolean screenReaderFocusable)13233 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 13234 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 13235 } 13236 13237 /** 13238 * Gets whether this view is a heading for accessibility purposes. 13239 * 13240 * @return {@code true} if the view is a heading, {@code false} otherwise. 13241 * 13242 * @attr ref android.R.styleable#View_accessibilityHeading 13243 */ 13244 @InspectableProperty isAccessibilityHeading()13245 public boolean isAccessibilityHeading() { 13246 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 13247 } 13248 13249 /** 13250 * Set if view is a heading for a section of content for accessibility purposes. 13251 * 13252 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 13253 * 13254 * @attr ref android.R.styleable#View_accessibilityHeading 13255 */ setAccessibilityHeading(boolean isHeading)13256 public void setAccessibilityHeading(boolean isHeading) { 13257 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 13258 } 13259 updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue)13260 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 13261 int pflags3 = mPrivateFlags3; 13262 if (newValue) { 13263 pflags3 |= mask; 13264 } else { 13265 pflags3 &= ~mask; 13266 } 13267 13268 if (pflags3 != mPrivateFlags3) { 13269 mPrivateFlags3 = pflags3; 13270 notifyViewAccessibilityStateChangedIfNeeded( 13271 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13272 } 13273 } 13274 13275 /** 13276 * Find the nearest view in the specified direction that can take focus. 13277 * This does not actually give focus to that view. 13278 * 13279 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13280 * 13281 * @return The nearest focusable in the specified direction, or null if none 13282 * can be found. 13283 */ focusSearch(@ocusRealDirection int direction)13284 public View focusSearch(@FocusRealDirection int direction) { 13285 if (mParent != null) { 13286 return mParent.focusSearch(this, direction); 13287 } else { 13288 return null; 13289 } 13290 } 13291 13292 /** 13293 * Returns whether this View is a root of a keyboard navigation cluster. 13294 * 13295 * @return True if this view is a root of a cluster, or false otherwise. 13296 * @attr ref android.R.styleable#View_keyboardNavigationCluster 13297 */ 13298 @ViewDebug.ExportedProperty(category = "focus") 13299 @InspectableProperty isKeyboardNavigationCluster()13300 public final boolean isKeyboardNavigationCluster() { 13301 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 13302 } 13303 13304 /** 13305 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 13306 * will be ignored. 13307 * 13308 * @return the keyboard navigation cluster that this view is in (can be this view) 13309 * or {@code null} if not in one 13310 */ findKeyboardNavigationCluster()13311 View findKeyboardNavigationCluster() { 13312 if (mParent instanceof View) { 13313 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 13314 if (cluster != null) { 13315 return cluster; 13316 } else if (isKeyboardNavigationCluster()) { 13317 return this; 13318 } 13319 } 13320 return null; 13321 } 13322 13323 /** 13324 * Set whether this view is a root of a keyboard navigation cluster. 13325 * 13326 * @param isCluster If true, this view is a root of a cluster. 13327 * 13328 * @attr ref android.R.styleable#View_keyboardNavigationCluster 13329 */ setKeyboardNavigationCluster(boolean isCluster)13330 public void setKeyboardNavigationCluster(boolean isCluster) { 13331 if (isCluster) { 13332 mPrivateFlags3 |= PFLAG3_CLUSTER; 13333 } else { 13334 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 13335 } 13336 } 13337 13338 /** 13339 * Sets this View as the one which receives focus the next time cluster navigation jumps 13340 * to the cluster containing this View. This does NOT change focus even if the cluster 13341 * containing this view is current. 13342 * 13343 * @hide 13344 */ 13345 @TestApi setFocusedInCluster()13346 public final void setFocusedInCluster() { 13347 setFocusedInCluster(findKeyboardNavigationCluster()); 13348 } 13349 setFocusedInCluster(View cluster)13350 private void setFocusedInCluster(View cluster) { 13351 if (this instanceof ViewGroup) { 13352 ((ViewGroup) this).mFocusedInCluster = null; 13353 } 13354 if (cluster == this) { 13355 return; 13356 } 13357 ViewParent parent = mParent; 13358 View child = this; 13359 while (parent instanceof ViewGroup) { 13360 ((ViewGroup) parent).mFocusedInCluster = child; 13361 if (parent == cluster) { 13362 break; 13363 } 13364 child = (View) parent; 13365 parent = parent.getParent(); 13366 } 13367 } 13368 updateFocusedInCluster(View oldFocus, @FocusDirection int direction)13369 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 13370 if (oldFocus != null) { 13371 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 13372 View cluster = findKeyboardNavigationCluster(); 13373 if (oldCluster != cluster) { 13374 // Going from one cluster to another, so save last-focused. 13375 // This covers cluster jumps because they are always FOCUS_DOWN 13376 oldFocus.setFocusedInCluster(oldCluster); 13377 if (!(oldFocus.mParent instanceof ViewGroup)) { 13378 return; 13379 } 13380 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 13381 // This is a result of ordered navigation so consider navigation through 13382 // the previous cluster "complete" and clear its last-focused memory. 13383 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 13384 } else if (oldFocus instanceof ViewGroup 13385 && ((ViewGroup) oldFocus).getDescendantFocusability() 13386 == ViewGroup.FOCUS_AFTER_DESCENDANTS 13387 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 13388 // This means oldFocus is not focusable since it obviously has a focusable 13389 // child (this). Don't restore focus to it in the future. 13390 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 13391 } 13392 } 13393 } 13394 } 13395 13396 /** 13397 * Returns whether this View should receive focus when the focus is restored for the view 13398 * hierarchy containing this view. 13399 * <p> 13400 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 13401 * window or serves as a target of cluster navigation. 13402 * 13403 * @see #restoreDefaultFocus() 13404 * 13405 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 13406 * @attr ref android.R.styleable#View_focusedByDefault 13407 */ 13408 @ViewDebug.ExportedProperty(category = "focus") 13409 @InspectableProperty isFocusedByDefault()13410 public final boolean isFocusedByDefault() { 13411 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 13412 } 13413 13414 /** 13415 * Sets whether this View should receive focus when the focus is restored for the view 13416 * hierarchy containing this view. 13417 * <p> 13418 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 13419 * window or serves as a target of cluster navigation. 13420 * 13421 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 13422 * {@code false} otherwise. 13423 * 13424 * @see #restoreDefaultFocus() 13425 * 13426 * @attr ref android.R.styleable#View_focusedByDefault 13427 */ 13428 @RemotableViewMethod setFocusedByDefault(boolean isFocusedByDefault)13429 public void setFocusedByDefault(boolean isFocusedByDefault) { 13430 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 13431 return; 13432 } 13433 13434 if (isFocusedByDefault) { 13435 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 13436 } else { 13437 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 13438 } 13439 13440 if (mParent instanceof ViewGroup) { 13441 if (isFocusedByDefault) { 13442 ((ViewGroup) mParent).setDefaultFocus(this); 13443 } else { 13444 ((ViewGroup) mParent).clearDefaultFocus(this); 13445 } 13446 } 13447 } 13448 13449 /** 13450 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 13451 * 13452 * @return {@code true} if this view has default focus, {@code false} otherwise 13453 */ hasDefaultFocus()13454 boolean hasDefaultFocus() { 13455 return isFocusedByDefault(); 13456 } 13457 13458 /** 13459 * Find the nearest keyboard navigation cluster in the specified direction. 13460 * This does not actually give focus to that cluster. 13461 * 13462 * @param currentCluster The starting point of the search. Null means the current cluster is not 13463 * found yet 13464 * @param direction Direction to look 13465 * 13466 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 13467 * can be found 13468 */ keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)13469 public View keyboardNavigationClusterSearch(View currentCluster, 13470 @FocusDirection int direction) { 13471 if (isKeyboardNavigationCluster()) { 13472 currentCluster = this; 13473 } 13474 if (isRootNamespace()) { 13475 // Root namespace means we should consider ourselves the top of the 13476 // tree for group searching; otherwise we could be group searching 13477 // into other tabs. see LocalActivityManager and TabHost for more info. 13478 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 13479 this, currentCluster, direction); 13480 } else if (mParent != null) { 13481 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 13482 } 13483 return null; 13484 } 13485 13486 /** 13487 * This method is the last chance for the focused view and its ancestors to 13488 * respond to an arrow key. This is called when the focused view did not 13489 * consume the key internally, nor could the view system find a new view in 13490 * the requested direction to give focus to. 13491 * 13492 * @param focused The currently focused view. 13493 * @param direction The direction focus wants to move. One of FOCUS_UP, 13494 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 13495 * @return True if the this view consumed this unhandled move. 13496 */ dispatchUnhandledMove(View focused, @FocusRealDirection int direction)13497 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 13498 return false; 13499 } 13500 13501 /** 13502 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 13503 * have {@link android.R.attr#state_focused} defined in its background. 13504 * 13505 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 13506 * highlight, {@code false} otherwise. 13507 * 13508 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 13509 */ setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled)13510 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 13511 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 13512 } 13513 13514 /** 13515 * Returns whether this View should use a default focus highlight when it gets focused but 13516 * doesn't have {@link android.R.attr#state_focused} defined in its background. 13517 * 13518 * @return True if this View should use a default focus highlight. 13519 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 13520 */ 13521 @ViewDebug.ExportedProperty(category = "focus") 13522 @InspectableProperty getDefaultFocusHighlightEnabled()13523 public final boolean getDefaultFocusHighlightEnabled() { 13524 return mDefaultFocusHighlightEnabled; 13525 } 13526 13527 /** 13528 * If a user manually specified the next view id for a particular direction, 13529 * use the root to look up the view. 13530 * @param root The root view of the hierarchy containing this view. 13531 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 13532 * or FOCUS_BACKWARD. 13533 * @return The user specified next view, or null if there is none. 13534 */ findUserSetNextFocus(View root, @FocusDirection int direction)13535 View findUserSetNextFocus(View root, @FocusDirection int direction) { 13536 switch (direction) { 13537 case FOCUS_LEFT: 13538 if (mNextFocusLeftId == View.NO_ID) return null; 13539 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 13540 case FOCUS_RIGHT: 13541 if (mNextFocusRightId == View.NO_ID) return null; 13542 return findViewInsideOutShouldExist(root, mNextFocusRightId); 13543 case FOCUS_UP: 13544 if (mNextFocusUpId == View.NO_ID) return null; 13545 return findViewInsideOutShouldExist(root, mNextFocusUpId); 13546 case FOCUS_DOWN: 13547 if (mNextFocusDownId == View.NO_ID) return null; 13548 return findViewInsideOutShouldExist(root, mNextFocusDownId); 13549 case FOCUS_FORWARD: 13550 if (mNextFocusForwardId == View.NO_ID) return null; 13551 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 13552 case FOCUS_BACKWARD: { 13553 if (mID == View.NO_ID) return null; 13554 final View rootView = root; 13555 final View startView = this; 13556 // Since we have forward links but no backward links, we need to find the view that 13557 // forward links to this view. We can't just find the view with the specified ID 13558 // because view IDs need not be unique throughout the tree. 13559 return root.findViewByPredicateInsideOut(startView, 13560 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 13561 == startView); 13562 } 13563 } 13564 return null; 13565 } 13566 13567 /** 13568 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 13569 * use the root to look up the view. 13570 * 13571 * @param root the root view of the hierarchy containing this view 13572 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 13573 * @return the user-specified next cluster, or {@code null} if there is none 13574 */ findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction)13575 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 13576 switch (direction) { 13577 case FOCUS_FORWARD: 13578 if (mNextClusterForwardId == View.NO_ID) return null; 13579 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 13580 case FOCUS_BACKWARD: { 13581 if (mID == View.NO_ID) return null; 13582 final int id = mID; 13583 return root.findViewByPredicateInsideOut(this, 13584 (Predicate<View>) t -> t.mNextClusterForwardId == id); 13585 } 13586 } 13587 return null; 13588 } 13589 findViewInsideOutShouldExist(View root, int id)13590 private View findViewInsideOutShouldExist(View root, int id) { 13591 return findViewInsideOutShouldExist(root, this, id); 13592 } 13593 findViewInsideOutShouldExist(View root, View start, int id)13594 private View findViewInsideOutShouldExist(View root, View start, int id) { 13595 if (mMatchIdPredicate == null) { 13596 mMatchIdPredicate = new MatchIdPredicate(); 13597 } 13598 mMatchIdPredicate.mId = id; 13599 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 13600 if (result == null) { 13601 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 13602 } 13603 return result; 13604 } 13605 13606 /** 13607 * Find and return all focusable views that are descendants of this view, 13608 * possibly including this view if it is focusable itself. 13609 * 13610 * @param direction The direction of the focus 13611 * @return A list of focusable views 13612 */ getFocusables(@ocusDirection int direction)13613 public ArrayList<View> getFocusables(@FocusDirection int direction) { 13614 ArrayList<View> result = new ArrayList<View>(24); 13615 addFocusables(result, direction); 13616 return result; 13617 } 13618 13619 /** 13620 * Add any focusable views that are descendants of this view (possibly 13621 * including this view if it is focusable itself) to views. If we are in touch mode, 13622 * only add views that are also focusable in touch mode. 13623 * 13624 * @param views Focusable views found so far 13625 * @param direction The direction of the focus 13626 */ addFocusables(ArrayList<View> views, @FocusDirection int direction)13627 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 13628 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 13629 } 13630 13631 /** 13632 * Adds any focusable views that are descendants of this view (possibly 13633 * including this view if it is focusable itself) to views. This method 13634 * adds all focusable views regardless if we are in touch mode or 13635 * only views focusable in touch mode if we are in touch mode or 13636 * only views that can take accessibility focus if accessibility is enabled 13637 * depending on the focusable mode parameter. 13638 * 13639 * @param views Focusable views found so far or null if all we are interested is 13640 * the number of focusables. 13641 * @param direction The direction of the focus. 13642 * @param focusableMode The type of focusables to be added. 13643 * 13644 * @see #FOCUSABLES_ALL 13645 * @see #FOCUSABLES_TOUCH_MODE 13646 */ addFocusables(ArrayList<View> views, @FocusDirection int direction, @FocusableMode int focusableMode)13647 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 13648 @FocusableMode int focusableMode) { 13649 if (views == null) { 13650 return; 13651 } 13652 if (!canTakeFocus()) { 13653 return; 13654 } 13655 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 13656 && !isFocusableInTouchMode()) { 13657 return; 13658 } 13659 views.add(this); 13660 } 13661 13662 /** 13663 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 13664 * including this view if it is a cluster root itself) to views. 13665 * 13666 * @param views Keyboard navigation cluster roots found so far 13667 * @param direction Direction to look 13668 */ addKeyboardNavigationClusters( @onNull Collection<View> views, int direction)13669 public void addKeyboardNavigationClusters( 13670 @NonNull Collection<View> views, 13671 int direction) { 13672 if (!isKeyboardNavigationCluster()) { 13673 return; 13674 } 13675 if (!hasFocusable()) { 13676 return; 13677 } 13678 views.add(this); 13679 } 13680 13681 /** 13682 * Finds the Views that contain given text. The containment is case insensitive. 13683 * The search is performed by either the text that the View renders or the content 13684 * description that describes the view for accessibility purposes and the view does 13685 * not render or both. Clients can specify how the search is to be performed via 13686 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 13687 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 13688 * 13689 * @param outViews The output list of matching Views. 13690 * @param searched The text to match against. 13691 * 13692 * @see #FIND_VIEWS_WITH_TEXT 13693 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 13694 * @see #setContentDescription(CharSequence) 13695 */ findViewsWithText(ArrayList<View> outViews, CharSequence searched, @FindViewFlags int flags)13696 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 13697 @FindViewFlags int flags) { 13698 if (getAccessibilityNodeProvider() != null) { 13699 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 13700 outViews.add(this); 13701 } 13702 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 13703 && (searched != null && searched.length() > 0) 13704 && (mContentDescription != null && mContentDescription.length() > 0)) { 13705 String searchedLowerCase = searched.toString().toLowerCase(); 13706 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 13707 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 13708 outViews.add(this); 13709 } 13710 } 13711 } 13712 13713 /** 13714 * Find and return all touchable views that are descendants of this view, 13715 * possibly including this view if it is touchable itself. 13716 * 13717 * @return A list of touchable views 13718 */ getTouchables()13719 public ArrayList<View> getTouchables() { 13720 ArrayList<View> result = new ArrayList<View>(); 13721 addTouchables(result); 13722 return result; 13723 } 13724 13725 /** 13726 * Add any touchable views that are descendants of this view (possibly 13727 * including this view if it is touchable itself) to views. 13728 * 13729 * @param views Touchable views found so far 13730 */ addTouchables(ArrayList<View> views)13731 public void addTouchables(ArrayList<View> views) { 13732 final int viewFlags = mViewFlags; 13733 13734 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 13735 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 13736 && (viewFlags & ENABLED_MASK) == ENABLED) { 13737 views.add(this); 13738 } 13739 } 13740 13741 /** 13742 * Returns whether this View is accessibility focused. 13743 * 13744 * @return True if this View is accessibility focused. 13745 */ 13746 @InspectableProperty(hasAttributeId = false) isAccessibilityFocused()13747 public boolean isAccessibilityFocused() { 13748 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 13749 } 13750 13751 /** 13752 * Call this to try to give accessibility focus to this view. 13753 * 13754 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 13755 * returns false or the view is no visible or the view already has accessibility 13756 * focus. 13757 * 13758 * See also {@link #focusSearch(int)}, which is what you call to say that you 13759 * have focus, and you want your parent to look for the next one. 13760 * 13761 * @return Whether this view actually took accessibility focus. 13762 * 13763 * @hide 13764 */ 13765 @UnsupportedAppUsage requestAccessibilityFocus()13766 public boolean requestAccessibilityFocus() { 13767 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 13768 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 13769 return false; 13770 } 13771 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 13772 return false; 13773 } 13774 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 13775 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 13776 ViewRootImpl viewRootImpl = getViewRootImpl(); 13777 if (viewRootImpl != null) { 13778 viewRootImpl.setAccessibilityFocus(this, null); 13779 } 13780 invalidate(); 13781 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 13782 return true; 13783 } 13784 return false; 13785 } 13786 13787 /** 13788 * Call this to try to clear accessibility focus of this view. 13789 * 13790 * See also {@link #focusSearch(int)}, which is what you call to say that you 13791 * have focus, and you want your parent to look for the next one. 13792 * 13793 * @hide 13794 */ 13795 @UnsupportedAppUsage clearAccessibilityFocus()13796 public void clearAccessibilityFocus() { 13797 clearAccessibilityFocusNoCallbacks(0); 13798 13799 // Clear the global reference of accessibility focus if this view or 13800 // any of its descendants had accessibility focus. This will NOT send 13801 // an event or update internal state if focus is cleared from a 13802 // descendant view, which may leave views in inconsistent states. 13803 final ViewRootImpl viewRootImpl = getViewRootImpl(); 13804 if (viewRootImpl != null) { 13805 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 13806 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13807 viewRootImpl.setAccessibilityFocus(null, null); 13808 } 13809 } 13810 } 13811 sendAccessibilityHoverEvent(int eventType)13812 private void sendAccessibilityHoverEvent(int eventType) { 13813 // Since we are not delivering to a client accessibility events from not 13814 // important views (unless the clinet request that) we need to fire the 13815 // event from the deepest view exposed to the client. As a consequence if 13816 // the user crosses a not exposed view the client will see enter and exit 13817 // of the exposed predecessor followed by and enter and exit of that same 13818 // predecessor when entering and exiting the not exposed descendant. This 13819 // is fine since the client has a clear idea which view is hovered at the 13820 // price of a couple more events being sent. This is a simple and 13821 // working solution. 13822 View source = this; 13823 while (true) { 13824 if (source.includeForAccessibility()) { 13825 source.sendAccessibilityEvent(eventType); 13826 return; 13827 } 13828 ViewParent parent = source.getParent(); 13829 if (parent instanceof View) { 13830 source = (View) parent; 13831 } else { 13832 return; 13833 } 13834 } 13835 } 13836 13837 /** 13838 * Clears accessibility focus without calling any callback methods 13839 * normally invoked in {@link #clearAccessibilityFocus()}. This method 13840 * is used separately from that one for clearing accessibility focus when 13841 * giving this focus to another view. 13842 * 13843 * @param action The action, if any, that led to focus being cleared. Set to 13844 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 13845 * the window. 13846 */ clearAccessibilityFocusNoCallbacks(int action)13847 void clearAccessibilityFocusNoCallbacks(int action) { 13848 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 13849 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 13850 invalidate(); 13851 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13852 AccessibilityEvent event = AccessibilityEvent.obtain( 13853 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 13854 event.setAction(action); 13855 if (mAccessibilityDelegate != null) { 13856 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 13857 } else { 13858 sendAccessibilityEventUnchecked(event); 13859 } 13860 } 13861 13862 updatePreferKeepClearForFocus(); 13863 } 13864 } 13865 13866 /** 13867 * Call this to try to give focus to a specific view or to one of its 13868 * descendants. 13869 * 13870 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13871 * false), or if it can't be focused due to other conditions (not focusable in touch mode 13872 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 13873 * enabled, or has no size). 13874 * 13875 * See also {@link #focusSearch(int)}, which is what you call to say that you 13876 * have focus, and you want your parent to look for the next one. 13877 * 13878 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 13879 * {@link #FOCUS_DOWN} and <code>null</code>. 13880 * 13881 * @return Whether this view or one of its descendants actually took focus. 13882 */ requestFocus()13883 public final boolean requestFocus() { 13884 return requestFocus(View.FOCUS_DOWN); 13885 } 13886 13887 /** 13888 * This will request focus for whichever View was last focused within this 13889 * cluster before a focus-jump out of it. 13890 * 13891 * @hide 13892 */ 13893 @TestApi restoreFocusInCluster(@ocusRealDirection int direction)13894 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 13895 // Prioritize focusableByDefault over algorithmic focus selection. 13896 if (restoreDefaultFocus()) { 13897 return true; 13898 } 13899 return requestFocus(direction); 13900 } 13901 13902 /** 13903 * This will request focus for whichever View not in a cluster was last focused before a 13904 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 13905 * the "first" focusable view it finds. 13906 * 13907 * @hide 13908 */ 13909 @TestApi restoreFocusNotInCluster()13910 public boolean restoreFocusNotInCluster() { 13911 return requestFocus(View.FOCUS_DOWN); 13912 } 13913 13914 /** 13915 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 13916 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 13917 * 13918 * @return Whether this view or one of its descendants actually took focus 13919 */ restoreDefaultFocus()13920 public boolean restoreDefaultFocus() { 13921 return requestFocus(View.FOCUS_DOWN); 13922 } 13923 13924 /** 13925 * Call this to try to give focus to a specific view or to one of its 13926 * descendants and give it a hint about what direction focus is heading. 13927 * 13928 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13929 * false), or if it is focusable and it is not focusable in touch mode 13930 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13931 * 13932 * See also {@link #focusSearch(int)}, which is what you call to say that you 13933 * have focus, and you want your parent to look for the next one. 13934 * 13935 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 13936 * <code>null</code> set for the previously focused rectangle. 13937 * 13938 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13939 * @return Whether this view or one of its descendants actually took focus. 13940 */ requestFocus(int direction)13941 public final boolean requestFocus(int direction) { 13942 return requestFocus(direction, null); 13943 } 13944 13945 /** 13946 * Call this to try to give focus to a specific view or to one of its descendants 13947 * and give it hints about the direction and a specific rectangle that the focus 13948 * is coming from. The rectangle can help give larger views a finer grained hint 13949 * about where focus is coming from, and therefore, where to show selection, or 13950 * forward focus change internally. 13951 * 13952 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13953 * false), or if it is focusable and it is not focusable in touch mode 13954 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13955 * 13956 * A View will not take focus if it is not visible. 13957 * 13958 * A View will not take focus if one of its parents has 13959 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 13960 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 13961 * 13962 * See also {@link #focusSearch(int)}, which is what you call to say that you 13963 * have focus, and you want your parent to look for the next one. 13964 * 13965 * You may wish to override this method if your custom {@link View} has an internal 13966 * {@link View} that it wishes to forward the request to. 13967 * 13968 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13969 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 13970 * to give a finer grained hint about where focus is coming from. May be null 13971 * if there is no hint. 13972 * @return Whether this view or one of its descendants actually took focus. 13973 */ requestFocus(int direction, Rect previouslyFocusedRect)13974 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 13975 return requestFocusNoSearch(direction, previouslyFocusedRect); 13976 } 13977 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)13978 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 13979 // need to be focusable 13980 if (!canTakeFocus()) { 13981 return false; 13982 } 13983 13984 // need to be focusable in touch mode if in touch mode 13985 if (isInTouchMode() && 13986 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 13987 return false; 13988 } 13989 13990 // need to not have any parents blocking us 13991 if (hasAncestorThatBlocksDescendantFocus()) { 13992 return false; 13993 } 13994 13995 if (!isLayoutValid()) { 13996 mPrivateFlags |= PFLAG_WANTS_FOCUS; 13997 } else { 13998 clearParentsWantFocus(); 13999 } 14000 14001 handleFocusGainInternal(direction, previouslyFocusedRect); 14002 return true; 14003 } 14004 clearParentsWantFocus()14005 void clearParentsWantFocus() { 14006 if (mParent instanceof View) { 14007 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 14008 ((View) mParent).clearParentsWantFocus(); 14009 } 14010 } 14011 14012 /** 14013 * Call this to try to give focus to a specific view or to one of its descendants. This is a 14014 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 14015 * touch mode to request focus when they are touched. 14016 * 14017 * @return Whether this view or one of its descendants actually took focus. 14018 * 14019 * @see #isInTouchMode() 14020 * 14021 */ requestFocusFromTouch()14022 public final boolean requestFocusFromTouch() { 14023 // Leave touch mode if we need to 14024 if (isInTouchMode()) { 14025 ViewRootImpl viewRoot = getViewRootImpl(); 14026 if (viewRoot != null) { 14027 viewRoot.ensureTouchMode(false); 14028 } 14029 } 14030 return requestFocus(View.FOCUS_DOWN); 14031 } 14032 14033 /** 14034 * @return Whether any ancestor of this view blocks descendant focus. 14035 */ hasAncestorThatBlocksDescendantFocus()14036 private boolean hasAncestorThatBlocksDescendantFocus() { 14037 final boolean focusableInTouchMode = isFocusableInTouchMode(); 14038 ViewParent ancestor = mParent; 14039 while (ancestor instanceof ViewGroup) { 14040 final ViewGroup vgAncestor = (ViewGroup) ancestor; 14041 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 14042 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 14043 return true; 14044 } else { 14045 ancestor = vgAncestor.getParent(); 14046 } 14047 } 14048 return false; 14049 } 14050 14051 /** 14052 * Gets the mode for determining whether this View is important for accessibility. 14053 * A view is important for accessibility if it fires accessibility events and if it 14054 * is reported to accessibility services that query the screen. 14055 * 14056 * @return The mode for determining whether a view is important for accessibility, one 14057 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 14058 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 14059 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 14060 * 14061 * @attr ref android.R.styleable#View_importantForAccessibility 14062 * 14063 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 14064 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 14065 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 14066 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 14067 */ 14068 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 14069 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 14070 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 14071 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 14072 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 14073 to = "noHideDescendants") 14074 }) 14075 @InspectableProperty(enumMapping = { 14076 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 14077 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 14078 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 14079 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 14080 name = "noHideDescendants"), 14081 }) getImportantForAccessibility()14082 public int getImportantForAccessibility() { 14083 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 14084 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 14085 } 14086 14087 /** 14088 * Sets the live region mode for this view. This indicates to accessibility 14089 * services whether they should automatically notify the user about changes 14090 * to the view's content description or text, or to the content descriptions 14091 * or text of the view's children (where applicable). 14092 * <p> 14093 * For example, in a login screen with a TextView that displays an "incorrect 14094 * password" notification, that view should be marked as a live region with 14095 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 14096 * <p> 14097 * To disable change notifications for this view, use 14098 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 14099 * mode for most views. 14100 * <p> 14101 * To indicate that the user should be notified of changes, use 14102 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 14103 * <p> 14104 * If the view's changes should interrupt ongoing speech and notify the user 14105 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 14106 * 14107 * @param mode The live region mode for this view, one of: 14108 * <ul> 14109 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 14110 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 14111 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 14112 * </ul> 14113 * @attr ref android.R.styleable#View_accessibilityLiveRegion 14114 */ setAccessibilityLiveRegion(int mode)14115 public void setAccessibilityLiveRegion(int mode) { 14116 if (mode != getAccessibilityLiveRegion()) { 14117 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 14118 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 14119 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 14120 notifyViewAccessibilityStateChangedIfNeeded( 14121 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14122 } 14123 } 14124 14125 /** 14126 * Gets the live region mode for this View. 14127 * 14128 * @return The live region mode for the view. 14129 * 14130 * @attr ref android.R.styleable#View_accessibilityLiveRegion 14131 * 14132 * @see #setAccessibilityLiveRegion(int) 14133 */ 14134 @InspectableProperty(enumMapping = { 14135 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 14136 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 14137 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 14138 }) getAccessibilityLiveRegion()14139 public int getAccessibilityLiveRegion() { 14140 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 14141 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 14142 } 14143 14144 /** 14145 * Sets how to determine whether this view is important for accessibility 14146 * which is if it fires accessibility events and if it is reported to 14147 * accessibility services that query the screen. 14148 * 14149 * @param mode How to determine whether this view is important for accessibility. 14150 * 14151 * @attr ref android.R.styleable#View_importantForAccessibility 14152 * 14153 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 14154 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 14155 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 14156 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 14157 */ setImportantForAccessibility(int mode)14158 public void setImportantForAccessibility(int mode) { 14159 final int oldMode = getImportantForAccessibility(); 14160 if (mode != oldMode) { 14161 final boolean hideDescendants = 14162 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 14163 14164 // If this node or its descendants are no longer important, try to 14165 // clear accessibility focus. 14166 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 14167 final View focusHost = findAccessibilityFocusHost(hideDescendants); 14168 if (focusHost != null) { 14169 focusHost.clearAccessibilityFocus(); 14170 } 14171 } 14172 14173 // If we're moving between AUTO and another state, we might not need 14174 // to send a subtree changed notification. We'll store the computed 14175 // importance, since we'll need to check it later to make sure. 14176 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 14177 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 14178 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 14179 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 14180 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 14181 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 14182 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 14183 notifySubtreeAccessibilityStateChangedIfNeeded(); 14184 } else { 14185 notifyViewAccessibilityStateChangedIfNeeded( 14186 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14187 } 14188 } 14189 } 14190 14191 /** 14192 * Returns the view within this view's hierarchy that is hosting 14193 * accessibility focus. 14194 * 14195 * @param searchDescendants whether to search for focus in descendant views 14196 * @return the view hosting accessibility focus, or {@code null} 14197 */ findAccessibilityFocusHost(boolean searchDescendants)14198 private View findAccessibilityFocusHost(boolean searchDescendants) { 14199 if (isAccessibilityFocusedViewOrHost()) { 14200 return this; 14201 } 14202 14203 if (searchDescendants) { 14204 final ViewRootImpl viewRoot = getViewRootImpl(); 14205 if (viewRoot != null) { 14206 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 14207 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 14208 return focusHost; 14209 } 14210 } 14211 } 14212 14213 return null; 14214 } 14215 14216 /** 14217 * Computes whether this view should be exposed for accessibility. In 14218 * general, views that are interactive or provide information are exposed 14219 * while views that serve only as containers are hidden. 14220 * <p> 14221 * If an ancestor of this view has importance 14222 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 14223 * returns <code>false</code>. 14224 * <p> 14225 * Otherwise, the value is computed according to the view's 14226 * {@link #getImportantForAccessibility()} value: 14227 * <ol> 14228 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 14229 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 14230 * </code> 14231 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 14232 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 14233 * view satisfies any of the following: 14234 * <ul> 14235 * <li>Is actionable, e.g. {@link #isClickable()}, 14236 * {@link #isLongClickable()}, or {@link #isFocusable()} 14237 * <li>Has an {@link AccessibilityDelegate} 14238 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 14239 * {@link OnKeyListener}, etc. 14240 * <li>Is an accessibility live region, e.g. 14241 * {@link #getAccessibilityLiveRegion()} is not 14242 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 14243 * </ul> 14244 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 14245 * </ol> 14246 * 14247 * @return Whether the view is exposed for accessibility. 14248 * @see #setImportantForAccessibility(int) 14249 * @see #getImportantForAccessibility() 14250 */ isImportantForAccessibility()14251 public boolean isImportantForAccessibility() { 14252 final int mode = getImportantForAccessibility(); 14253 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 14254 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 14255 return false; 14256 } 14257 14258 // Check parent mode to ensure we're not hidden. 14259 ViewParent parent = mParent; 14260 while (parent instanceof View) { 14261 if (((View) parent).getImportantForAccessibility() 14262 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 14263 return false; 14264 } 14265 parent = parent.getParent(); 14266 } 14267 14268 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 14269 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 14270 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 14271 || isAccessibilityPane(); 14272 } 14273 14274 /** 14275 * Gets the parent for accessibility purposes. Note that the parent for 14276 * accessibility is not necessary the immediate parent. It is the first 14277 * predecessor that is important for accessibility. 14278 * 14279 * @return The parent for accessibility purposes. 14280 */ getParentForAccessibility()14281 public ViewParent getParentForAccessibility() { 14282 if (mParent instanceof View) { 14283 View parentView = (View) mParent; 14284 if (parentView.includeForAccessibility()) { 14285 return mParent; 14286 } else { 14287 return mParent.getParentForAccessibility(); 14288 } 14289 } 14290 return null; 14291 } 14292 14293 /** @hide */ getSelfOrParentImportantForA11y()14294 View getSelfOrParentImportantForA11y() { 14295 if (isImportantForAccessibility()) return this; 14296 ViewParent parent = getParentForAccessibility(); 14297 if (parent instanceof View) return (View) parent; 14298 return null; 14299 } 14300 14301 /** 14302 * Adds the children of this View relevant for accessibility to the given list 14303 * as output. Since some Views are not important for accessibility the added 14304 * child views are not necessarily direct children of this view, rather they are 14305 * the first level of descendants important for accessibility. 14306 * 14307 * @param outChildren The output list that will receive children for accessibility. 14308 */ addChildrenForAccessibility(ArrayList<View> outChildren)14309 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 14310 14311 } 14312 14313 /** 14314 * Whether to regard this view for accessibility. A view is regarded for 14315 * accessibility if it is important for accessibility or the querying 14316 * accessibility service has explicitly requested that view not 14317 * important for accessibility are regarded. 14318 * 14319 * @return Whether to regard the view for accessibility. 14320 * 14321 * @hide 14322 */ 14323 @UnsupportedAppUsage includeForAccessibility()14324 public boolean includeForAccessibility() { 14325 if (mAttachInfo != null) { 14326 return (mAttachInfo.mAccessibilityFetchFlags 14327 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 14328 || isImportantForAccessibility(); 14329 } 14330 return false; 14331 } 14332 14333 /** 14334 * Returns whether the View is considered actionable from 14335 * accessibility perspective. Such view are important for 14336 * accessibility. 14337 * 14338 * @return True if the view is actionable for accessibility. 14339 * 14340 * @hide 14341 */ isActionableForAccessibility()14342 public boolean isActionableForAccessibility() { 14343 return (isClickable() || isLongClickable() || isFocusable()); 14344 } 14345 14346 /** 14347 * Returns whether the View has registered callbacks which makes it 14348 * important for accessibility. 14349 * 14350 * @return True if the view is actionable for accessibility. 14351 */ hasListenersForAccessibility()14352 private boolean hasListenersForAccessibility() { 14353 ListenerInfo info = getListenerInfo(); 14354 return mTouchDelegate != null || info.mOnKeyListener != null 14355 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 14356 || info.mOnHoverListener != null || info.mOnDragListener != null; 14357 } 14358 14359 /** 14360 * Notifies that the accessibility state of this view changed. The change 14361 * is local to this view and does not represent structural changes such 14362 * as children and parent. For example, the view became focusable. The 14363 * notification is at at most once every 14364 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 14365 * to avoid unnecessary load to the system. Also once a view has a pending 14366 * notification this method is a NOP until the notification has been sent. 14367 * 14368 * @hide 14369 */ 14370 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) notifyViewAccessibilityStateChangedIfNeeded(int changeType)14371 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 14372 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 14373 return; 14374 } 14375 14376 // Changes to views with a pane title count as window state changes, as the pane title 14377 // marks them as significant parts of the UI. A visible view with a nulled title may send 14378 // a disappeared event. 14379 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 14380 && (isAccessibilityPane() 14381 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) 14382 && isAggregatedVisible())) { 14383 // If the pane isn't visible, content changed events are sufficient unless we're 14384 // reporting that the view just disappeared 14385 if ((isAggregatedVisible()) 14386 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 14387 final AccessibilityEvent event = AccessibilityEvent.obtain(); 14388 onInitializeAccessibilityEvent(event); 14389 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 14390 event.setContentChangeTypes(changeType); 14391 event.setSource(this); 14392 onPopulateAccessibilityEvent(event); 14393 if (mParent != null) { 14394 try { 14395 mParent.requestSendAccessibilityEvent(this, event); 14396 } catch (AbstractMethodError e) { 14397 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 14398 + " does not fully implement ViewParent", e); 14399 } 14400 } 14401 return; 14402 } 14403 } 14404 14405 // If this is a live region, we should send a subtree change event 14406 // from this view immediately. Otherwise, we can let it propagate up. 14407 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 14408 final AccessibilityEvent event = AccessibilityEvent.obtain(); 14409 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 14410 event.setContentChangeTypes(changeType); 14411 sendAccessibilityEventUnchecked(event); 14412 } else if (mParent != null) { 14413 try { 14414 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 14415 } catch (AbstractMethodError e) { 14416 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 14417 " does not fully implement ViewParent", e); 14418 } 14419 } 14420 } 14421 14422 /** 14423 * Notifies that the accessibility state of this view changed. The change 14424 * is *not* local to this view and does represent structural changes such 14425 * as children and parent. For example, the view size changed. The 14426 * notification is at at most once every 14427 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 14428 * to avoid unnecessary load to the system. Also once a view has a pending 14429 * notification this method is a NOP until the notification has been sent. 14430 * 14431 * @hide 14432 */ 14433 @UnsupportedAppUsage notifySubtreeAccessibilityStateChangedIfNeeded()14434 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 14435 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 14436 return; 14437 } 14438 14439 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 14440 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 14441 if (mParent != null) { 14442 try { 14443 mParent.notifySubtreeAccessibilityStateChanged( 14444 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 14445 } catch (AbstractMethodError e) { 14446 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 14447 " does not fully implement ViewParent", e); 14448 } 14449 } 14450 } 14451 } 14452 notifySubtreeAccessibilityStateChangedByParentIfNeeded()14453 private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { 14454 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 14455 return; 14456 } 14457 14458 final View sendA11yEventView = (View) getParentForAccessibility(); 14459 if (sendA11yEventView != null && sendA11yEventView.isShown()) { 14460 sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); 14461 } 14462 } 14463 14464 /** 14465 * Changes the visibility of this View without triggering any other changes. This should only 14466 * be used by animation frameworks, such as {@link android.transition.Transition}, where 14467 * visibility changes should not adjust focus or trigger a new layout. Application developers 14468 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 14469 * 14470 * <p>Only call this method when a temporary visibility must be applied during an 14471 * animation and the original visibility value is guaranteed to be reset after the 14472 * animation completes. Use {@link #setVisibility} in all other cases.</p> 14473 * 14474 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 14475 * @see #setVisibility(int) 14476 */ setTransitionVisibility(@isibility int visibility)14477 public void setTransitionVisibility(@Visibility int visibility) { 14478 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 14479 } 14480 14481 /** 14482 * Reset the flag indicating the accessibility state of the subtree rooted 14483 * at this view changed. 14484 */ resetSubtreeAccessibilityStateChanged()14485 void resetSubtreeAccessibilityStateChanged() { 14486 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 14487 } 14488 14489 /** 14490 * Report an accessibility action to this view's parents for delegated processing. 14491 * 14492 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 14493 * call this method to delegate an accessibility action to a supporting parent. If the parent 14494 * returns true from its 14495 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 14496 * method this method will return true to signify that the action was consumed.</p> 14497 * 14498 * <p>This method is useful for implementing nested scrolling child views. If 14499 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 14500 * a custom view implementation may invoke this method to allow a parent to consume the 14501 * scroll first. If this method returns true the custom view should skip its own scrolling 14502 * behavior.</p> 14503 * 14504 * @param action Accessibility action to delegate 14505 * @param arguments Optional action arguments 14506 * @return true if the action was consumed by a parent 14507 */ dispatchNestedPrePerformAccessibilityAction(int action, @Nullable Bundle arguments)14508 public boolean dispatchNestedPrePerformAccessibilityAction(int action, 14509 @Nullable Bundle arguments) { 14510 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 14511 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 14512 return true; 14513 } 14514 } 14515 return false; 14516 } 14517 14518 /** 14519 * Performs the specified accessibility action on the view. For 14520 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 14521 * <p> 14522 * If an {@link AccessibilityDelegate} has been specified via calling 14523 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 14524 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 14525 * is responsible for handling this call. 14526 * </p> 14527 * 14528 * <p>The default implementation will delegate 14529 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 14530 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 14531 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 14532 * 14533 * @param action The action to perform. 14534 * @param arguments Optional action arguments. 14535 * @return Whether the action was performed. 14536 */ performAccessibilityAction(int action, @Nullable Bundle arguments)14537 public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) { 14538 if (mAccessibilityDelegate != null) { 14539 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 14540 } else { 14541 return performAccessibilityActionInternal(action, arguments); 14542 } 14543 } 14544 14545 /** 14546 * @see #performAccessibilityAction(int, Bundle) 14547 * 14548 * Note: Called from the default {@link AccessibilityDelegate}. 14549 * 14550 * @hide 14551 */ 14552 @UnsupportedAppUsage performAccessibilityActionInternal(int action, @Nullable Bundle arguments)14553 public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) { 14554 if (isNestedScrollingEnabled() 14555 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 14556 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 14557 || action == R.id.accessibilityActionScrollUp 14558 || action == R.id.accessibilityActionScrollLeft 14559 || action == R.id.accessibilityActionScrollDown 14560 || action == R.id.accessibilityActionScrollRight)) { 14561 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 14562 return true; 14563 } 14564 } 14565 14566 switch (action) { 14567 case AccessibilityNodeInfo.ACTION_CLICK: { 14568 if (isClickable()) { 14569 performClickInternal(); 14570 return true; 14571 } 14572 } break; 14573 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 14574 if (isLongClickable()) { 14575 performLongClick(); 14576 return true; 14577 } 14578 } break; 14579 case AccessibilityNodeInfo.ACTION_FOCUS: { 14580 if (!hasFocus()) { 14581 // Get out of touch mode since accessibility 14582 // wants to move focus around. 14583 getViewRootImpl().ensureTouchMode(false); 14584 return requestFocus(); 14585 } 14586 } break; 14587 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 14588 if (hasFocus()) { 14589 clearFocus(); 14590 return !isFocused(); 14591 } 14592 } break; 14593 case AccessibilityNodeInfo.ACTION_SELECT: { 14594 if (!isSelected()) { 14595 setSelected(true); 14596 return isSelected(); 14597 } 14598 } break; 14599 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 14600 if (isSelected()) { 14601 setSelected(false); 14602 return !isSelected(); 14603 } 14604 } break; 14605 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 14606 if (!isAccessibilityFocused()) { 14607 return requestAccessibilityFocus(); 14608 } 14609 } break; 14610 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 14611 if (isAccessibilityFocused()) { 14612 clearAccessibilityFocus(); 14613 return true; 14614 } 14615 } break; 14616 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 14617 if (arguments != null) { 14618 final int granularity = arguments.getInt( 14619 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 14620 final boolean extendSelection = arguments.getBoolean( 14621 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 14622 return traverseAtGranularity(granularity, true, extendSelection); 14623 } 14624 } break; 14625 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 14626 if (arguments != null) { 14627 final int granularity = arguments.getInt( 14628 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 14629 final boolean extendSelection = arguments.getBoolean( 14630 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 14631 return traverseAtGranularity(granularity, false, extendSelection); 14632 } 14633 } break; 14634 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 14635 CharSequence text = getIterableTextForAccessibility(); 14636 if (text == null) { 14637 return false; 14638 } 14639 final int start = (arguments != null) ? arguments.getInt( 14640 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 14641 final int end = (arguments != null) ? arguments.getInt( 14642 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 14643 // Only cursor position can be specified (selection length == 0) 14644 if ((getAccessibilitySelectionStart() != start 14645 || getAccessibilitySelectionEnd() != end) 14646 && (start == end)) { 14647 setAccessibilitySelection(start, end); 14648 notifyViewAccessibilityStateChangedIfNeeded( 14649 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14650 return true; 14651 } 14652 } break; 14653 case R.id.accessibilityActionShowOnScreen: { 14654 if (mAttachInfo != null) { 14655 final Rect r = mAttachInfo.mTmpInvalRect; 14656 getDrawingRect(r); 14657 return requestRectangleOnScreen(r, true); 14658 } 14659 } break; 14660 case R.id.accessibilityActionContextClick: { 14661 if (isContextClickable()) { 14662 performContextClick(); 14663 return true; 14664 } 14665 } break; 14666 case R.id.accessibilityActionShowTooltip: { 14667 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 14668 // Tooltip already showing 14669 return false; 14670 } 14671 return showLongClickTooltip(0, 0); 14672 } 14673 case R.id.accessibilityActionHideTooltip: { 14674 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 14675 // No tooltip showing 14676 return false; 14677 } 14678 hideTooltip(); 14679 return true; 14680 } 14681 case R.id.accessibilityActionDragDrop: { 14682 if (!canAcceptAccessibilityDrop()) { 14683 return false; 14684 } 14685 try { 14686 if (mAttachInfo != null && mAttachInfo.mSession != null) { 14687 final int[] location = new int[2]; 14688 getLocationInWindow(location); 14689 final int centerX = location[0] + getWidth() / 2; 14690 final int centerY = location[1] + getHeight() / 2; 14691 return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, 14692 centerX, centerY); 14693 } 14694 } catch (RemoteException e) { 14695 Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); 14696 } 14697 return false; 14698 } 14699 case R.id.accessibilityActionDragCancel: { 14700 if (!startedSystemDragForAccessibility()) { 14701 return false; 14702 } 14703 if (mAttachInfo != null && mAttachInfo.mDragToken != null) { 14704 cancelDragAndDrop(); 14705 return true; 14706 } 14707 return false; 14708 } 14709 } 14710 return false; 14711 } 14712 canAcceptAccessibilityDrop()14713 private boolean canAcceptAccessibilityDrop() { 14714 if (!canAcceptDrag()) { 14715 return false; 14716 } 14717 ListenerInfo li = mListenerInfo; 14718 return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); 14719 } 14720 traverseAtGranularity(int granularity, boolean forward, boolean extendSelection)14721 private boolean traverseAtGranularity(int granularity, boolean forward, 14722 boolean extendSelection) { 14723 CharSequence text = getIterableTextForAccessibility(); 14724 if (text == null || text.length() == 0) { 14725 return false; 14726 } 14727 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 14728 if (iterator == null) { 14729 return false; 14730 } 14731 int current = getAccessibilitySelectionEnd(); 14732 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14733 current = forward ? 0 : text.length(); 14734 } 14735 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 14736 if (range == null) { 14737 return false; 14738 } 14739 final int segmentStart = range[0]; 14740 final int segmentEnd = range[1]; 14741 int selectionStart; 14742 int selectionEnd; 14743 if (extendSelection && isAccessibilitySelectionExtendable()) { 14744 prepareForExtendedAccessibilitySelection(); 14745 selectionStart = getAccessibilitySelectionStart(); 14746 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14747 selectionStart = forward ? segmentStart : segmentEnd; 14748 } 14749 selectionEnd = forward ? segmentEnd : segmentStart; 14750 } else { 14751 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 14752 } 14753 setAccessibilitySelection(selectionStart, selectionEnd); 14754 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 14755 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 14756 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 14757 return true; 14758 } 14759 14760 /** 14761 * Gets the text reported for accessibility purposes. 14762 * 14763 * @return The accessibility text. 14764 * 14765 * @hide 14766 */ 14767 @UnsupportedAppUsage getIterableTextForAccessibility()14768 public CharSequence getIterableTextForAccessibility() { 14769 return getContentDescription(); 14770 } 14771 14772 /** 14773 * Gets whether accessibility selection can be extended. 14774 * 14775 * @return If selection is extensible. 14776 * 14777 * @hide 14778 */ isAccessibilitySelectionExtendable()14779 public boolean isAccessibilitySelectionExtendable() { 14780 return false; 14781 } 14782 14783 /** 14784 * Prepare for extended selection. 14785 * @hide 14786 */ prepareForExtendedAccessibilitySelection()14787 public void prepareForExtendedAccessibilitySelection() { 14788 return; 14789 } 14790 14791 /** 14792 * @hide 14793 */ getAccessibilitySelectionStart()14794 public int getAccessibilitySelectionStart() { 14795 return mAccessibilityCursorPosition; 14796 } 14797 14798 /** 14799 * @hide 14800 */ getAccessibilitySelectionEnd()14801 public int getAccessibilitySelectionEnd() { 14802 return getAccessibilitySelectionStart(); 14803 } 14804 14805 /** 14806 * @hide 14807 */ setAccessibilitySelection(int start, int end)14808 public void setAccessibilitySelection(int start, int end) { 14809 if (start == end && end == mAccessibilityCursorPosition) { 14810 return; 14811 } 14812 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 14813 mAccessibilityCursorPosition = start; 14814 } else { 14815 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 14816 } 14817 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 14818 } 14819 sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex)14820 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 14821 int fromIndex, int toIndex) { 14822 if (mParent == null) { 14823 return; 14824 } 14825 AccessibilityEvent event = AccessibilityEvent.obtain( 14826 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 14827 onInitializeAccessibilityEvent(event); 14828 onPopulateAccessibilityEvent(event); 14829 event.setFromIndex(fromIndex); 14830 event.setToIndex(toIndex); 14831 event.setAction(action); 14832 event.setMovementGranularity(granularity); 14833 mParent.requestSendAccessibilityEvent(this, event); 14834 } 14835 14836 /** 14837 * @hide 14838 */ 14839 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getIteratorForGranularity(int granularity)14840 public TextSegmentIterator getIteratorForGranularity(int granularity) { 14841 switch (granularity) { 14842 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 14843 CharSequence text = getIterableTextForAccessibility(); 14844 if (text != null && text.length() > 0) { 14845 CharacterTextSegmentIterator iterator = 14846 CharacterTextSegmentIterator.getInstance( 14847 mContext.getResources().getConfiguration().locale); 14848 iterator.initialize(text.toString()); 14849 return iterator; 14850 } 14851 } break; 14852 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 14853 CharSequence text = getIterableTextForAccessibility(); 14854 if (text != null && text.length() > 0) { 14855 WordTextSegmentIterator iterator = 14856 WordTextSegmentIterator.getInstance( 14857 mContext.getResources().getConfiguration().locale); 14858 iterator.initialize(text.toString()); 14859 return iterator; 14860 } 14861 } break; 14862 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 14863 CharSequence text = getIterableTextForAccessibility(); 14864 if (text != null && text.length() > 0) { 14865 ParagraphTextSegmentIterator iterator = 14866 ParagraphTextSegmentIterator.getInstance(); 14867 iterator.initialize(text.toString()); 14868 return iterator; 14869 } 14870 } break; 14871 } 14872 return null; 14873 } 14874 14875 /** 14876 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 14877 * and {@link #onFinishTemporaryDetach()}. 14878 * 14879 * <p>This method always returns {@code true} when called directly or indirectly from 14880 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 14881 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 14882 * <ul> 14883 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 14884 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 14885 * </ul> 14886 * </p> 14887 * 14888 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 14889 * and {@link #onFinishTemporaryDetach()}. 14890 */ isTemporarilyDetached()14891 public final boolean isTemporarilyDetached() { 14892 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 14893 } 14894 14895 /** 14896 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 14897 * a container View. 14898 */ 14899 @CallSuper dispatchStartTemporaryDetach()14900 public void dispatchStartTemporaryDetach() { 14901 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 14902 notifyEnterOrExitForAutoFillIfNeeded(false); 14903 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 14904 onStartTemporaryDetach(); 14905 } 14906 14907 /** 14908 * This is called when a container is going to temporarily detach a child, with 14909 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 14910 * It will either be followed by {@link #onFinishTemporaryDetach()} or 14911 * {@link #onDetachedFromWindow()} when the container is done. 14912 */ onStartTemporaryDetach()14913 public void onStartTemporaryDetach() { 14914 removeUnsetPressCallback(); 14915 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 14916 } 14917 14918 /** 14919 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 14920 * a container View. 14921 */ 14922 @CallSuper dispatchFinishTemporaryDetach()14923 public void dispatchFinishTemporaryDetach() { 14924 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 14925 onFinishTemporaryDetach(); 14926 if (hasWindowFocus() && hasFocus()) { 14927 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14928 } 14929 notifyEnterOrExitForAutoFillIfNeeded(true); 14930 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 14931 } 14932 14933 /** 14934 * Called after {@link #onStartTemporaryDetach} when the container is done 14935 * changing the view. 14936 */ onFinishTemporaryDetach()14937 public void onFinishTemporaryDetach() { 14938 } 14939 14940 /** 14941 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 14942 * for this view's window. Returns null if the view is not currently attached 14943 * to the window. Normally you will not need to use this directly, but 14944 * just use the standard high-level event callbacks like 14945 * {@link #onKeyDown(int, KeyEvent)}. 14946 */ getKeyDispatcherState()14947 public KeyEvent.DispatcherState getKeyDispatcherState() { 14948 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 14949 } 14950 14951 /** 14952 * Dispatch a key event before it is processed by any input method 14953 * associated with the view hierarchy. This can be used to intercept 14954 * key events in special situations before the IME consumes them; a 14955 * typical example would be handling the BACK key to update the application's 14956 * UI instead of allowing the IME to see it and close itself. 14957 * 14958 * @param event The key event to be dispatched. 14959 * @return True if the event was handled, false otherwise. 14960 */ dispatchKeyEventPreIme(KeyEvent event)14961 public boolean dispatchKeyEventPreIme(KeyEvent event) { 14962 return onKeyPreIme(event.getKeyCode(), event); 14963 } 14964 14965 /** 14966 * Dispatch a key event to the next view on the focus path. This path runs 14967 * from the top of the view tree down to the currently focused view. If this 14968 * view has focus, it will dispatch to itself. Otherwise it will dispatch 14969 * the next node down the focus path. This method also fires any key 14970 * listeners. 14971 * 14972 * @param event The key event to be dispatched. 14973 * @return True if the event was handled, false otherwise. 14974 */ dispatchKeyEvent(KeyEvent event)14975 public boolean dispatchKeyEvent(KeyEvent event) { 14976 if (mInputEventConsistencyVerifier != null) { 14977 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 14978 } 14979 14980 // Give any attached key listener a first crack at the event. 14981 //noinspection SimplifiableIfStatement 14982 ListenerInfo li = mListenerInfo; 14983 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 14984 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 14985 return true; 14986 } 14987 14988 if (event.dispatch(this, mAttachInfo != null 14989 ? mAttachInfo.mKeyDispatchState : null, this)) { 14990 return true; 14991 } 14992 14993 if (mInputEventConsistencyVerifier != null) { 14994 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14995 } 14996 return false; 14997 } 14998 14999 /** 15000 * Dispatches a key shortcut event. 15001 * 15002 * @param event The key event to be dispatched. 15003 * @return True if the event was handled by the view, false otherwise. 15004 */ dispatchKeyShortcutEvent(KeyEvent event)15005 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 15006 return onKeyShortcut(event.getKeyCode(), event); 15007 } 15008 15009 /** 15010 * Pass the touch screen motion event down to the target view, or this 15011 * view if it is the target. 15012 * 15013 * @param event The motion event to be dispatched. 15014 * @return True if the event was handled by the view, false otherwise. 15015 */ dispatchTouchEvent(MotionEvent event)15016 public boolean dispatchTouchEvent(MotionEvent event) { 15017 // If the event should be handled by accessibility focus first. 15018 if (event.isTargetAccessibilityFocus()) { 15019 // We don't have focus or no virtual descendant has it, do not handle the event. 15020 if (!isAccessibilityFocusedViewOrHost()) { 15021 return false; 15022 } 15023 // We have focus and got the event, then use normal event dispatch. 15024 event.setTargetAccessibilityFocus(false); 15025 } 15026 boolean result = false; 15027 15028 if (mInputEventConsistencyVerifier != null) { 15029 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 15030 } 15031 15032 final int actionMasked = event.getActionMasked(); 15033 if (actionMasked == MotionEvent.ACTION_DOWN) { 15034 // Defensive cleanup for new gesture 15035 stopNestedScroll(); 15036 } 15037 15038 if (onFilterTouchEventForSecurity(event)) { 15039 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 15040 result = true; 15041 } 15042 //noinspection SimplifiableIfStatement 15043 ListenerInfo li = mListenerInfo; 15044 if (li != null && li.mOnTouchListener != null 15045 && (mViewFlags & ENABLED_MASK) == ENABLED 15046 && li.mOnTouchListener.onTouch(this, event)) { 15047 result = true; 15048 } 15049 15050 if (!result && onTouchEvent(event)) { 15051 result = true; 15052 } 15053 } 15054 15055 if (!result && mInputEventConsistencyVerifier != null) { 15056 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15057 } 15058 15059 // Clean up after nested scrolls if this is the end of a gesture; 15060 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 15061 // of the gesture. 15062 if (actionMasked == MotionEvent.ACTION_UP || 15063 actionMasked == MotionEvent.ACTION_CANCEL || 15064 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 15065 stopNestedScroll(); 15066 } 15067 15068 return result; 15069 } 15070 isAccessibilityFocusedViewOrHost()15071 boolean isAccessibilityFocusedViewOrHost() { 15072 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 15073 .getAccessibilityFocusedHost() == this); 15074 } 15075 15076 /** 15077 * Returns whether this view can receive pointer events. 15078 * 15079 * @return {@code true} if this view can receive pointer events. 15080 * @hide 15081 */ canReceivePointerEvents()15082 protected boolean canReceivePointerEvents() { 15083 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 15084 } 15085 15086 /** 15087 * Filter the touch event to apply security policies. 15088 * 15089 * @param event The motion event to be filtered. 15090 * @return True if the event should be dispatched, false if the event should be dropped. 15091 * 15092 * @see #getFilterTouchesWhenObscured 15093 */ onFilterTouchEventForSecurity(MotionEvent event)15094 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 15095 //noinspection RedundantIfStatement 15096 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 15097 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 15098 // Window is obscured, drop this touch. 15099 return false; 15100 } 15101 return true; 15102 } 15103 15104 /** 15105 * Pass a trackball motion event down to the focused view. 15106 * 15107 * @param event The motion event to be dispatched. 15108 * @return True if the event was handled by the view, false otherwise. 15109 */ dispatchTrackballEvent(MotionEvent event)15110 public boolean dispatchTrackballEvent(MotionEvent event) { 15111 if (mInputEventConsistencyVerifier != null) { 15112 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 15113 } 15114 15115 return onTrackballEvent(event); 15116 } 15117 15118 /** 15119 * Pass a captured pointer event down to the focused view. 15120 * 15121 * @param event The motion event to be dispatched. 15122 * @return True if the event was handled by the view, false otherwise. 15123 */ dispatchCapturedPointerEvent(MotionEvent event)15124 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 15125 if (!hasPointerCapture()) { 15126 return false; 15127 } 15128 //noinspection SimplifiableIfStatement 15129 ListenerInfo li = mListenerInfo; 15130 if (li != null && li.mOnCapturedPointerListener != null 15131 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 15132 return true; 15133 } 15134 return onCapturedPointerEvent(event); 15135 } 15136 15137 /** 15138 * Dispatch a generic motion event. 15139 * <p> 15140 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 15141 * are delivered to the view under the pointer. All other generic motion events are 15142 * delivered to the focused view. Hover events are handled specially and are delivered 15143 * to {@link #onHoverEvent(MotionEvent)}. 15144 * </p> 15145 * 15146 * @param event The motion event to be dispatched. 15147 * @return True if the event was handled by the view, false otherwise. 15148 */ dispatchGenericMotionEvent(MotionEvent event)15149 public boolean dispatchGenericMotionEvent(MotionEvent event) { 15150 if (mInputEventConsistencyVerifier != null) { 15151 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 15152 } 15153 15154 final int source = event.getSource(); 15155 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 15156 final int action = event.getAction(); 15157 if (action == MotionEvent.ACTION_HOVER_ENTER 15158 || action == MotionEvent.ACTION_HOVER_MOVE 15159 || action == MotionEvent.ACTION_HOVER_EXIT) { 15160 if (dispatchHoverEvent(event)) { 15161 return true; 15162 } 15163 } else if (dispatchGenericPointerEvent(event)) { 15164 return true; 15165 } 15166 } else if (dispatchGenericFocusedEvent(event)) { 15167 return true; 15168 } 15169 15170 if (dispatchGenericMotionEventInternal(event)) { 15171 return true; 15172 } 15173 15174 if (mInputEventConsistencyVerifier != null) { 15175 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15176 } 15177 return false; 15178 } 15179 dispatchGenericMotionEventInternal(MotionEvent event)15180 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 15181 //noinspection SimplifiableIfStatement 15182 ListenerInfo li = mListenerInfo; 15183 if (li != null && li.mOnGenericMotionListener != null 15184 && (mViewFlags & ENABLED_MASK) == ENABLED 15185 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 15186 return true; 15187 } 15188 15189 if (onGenericMotionEvent(event)) { 15190 return true; 15191 } 15192 15193 final int actionButton = event.getActionButton(); 15194 switch (event.getActionMasked()) { 15195 case MotionEvent.ACTION_BUTTON_PRESS: 15196 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 15197 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 15198 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 15199 if (performContextClick(event.getX(), event.getY())) { 15200 mInContextButtonPress = true; 15201 setPressed(true, event.getX(), event.getY()); 15202 removeTapCallback(); 15203 removeLongPressCallback(); 15204 return true; 15205 } 15206 } 15207 break; 15208 15209 case MotionEvent.ACTION_BUTTON_RELEASE: 15210 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 15211 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 15212 mInContextButtonPress = false; 15213 mIgnoreNextUpEvent = true; 15214 } 15215 break; 15216 } 15217 15218 if (mInputEventConsistencyVerifier != null) { 15219 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15220 } 15221 return false; 15222 } 15223 15224 /** 15225 * Dispatch a hover event. 15226 * <p> 15227 * Do not call this method directly. 15228 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 15229 * </p> 15230 * 15231 * @param event The motion event to be dispatched. 15232 * @return True if the event was handled by the view, false otherwise. 15233 */ dispatchHoverEvent(MotionEvent event)15234 protected boolean dispatchHoverEvent(MotionEvent event) { 15235 ListenerInfo li = mListenerInfo; 15236 //noinspection SimplifiableIfStatement 15237 if (li != null && li.mOnHoverListener != null 15238 && (mViewFlags & ENABLED_MASK) == ENABLED 15239 && li.mOnHoverListener.onHover(this, event)) { 15240 return true; 15241 } 15242 15243 return onHoverEvent(event); 15244 } 15245 15246 /** 15247 * Returns true if the view has a child to which it has recently sent 15248 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 15249 * it does not have a hovered child, then it must be the innermost hovered view. 15250 * @hide 15251 */ hasHoveredChild()15252 protected boolean hasHoveredChild() { 15253 return false; 15254 } 15255 15256 /** 15257 * Returns true if the given point, in local coordinates, is inside the hovered child. 15258 * 15259 * @hide 15260 */ pointInHoveredChild(MotionEvent event)15261 protected boolean pointInHoveredChild(MotionEvent event) { 15262 return false; 15263 } 15264 15265 /** 15266 * Dispatch a generic motion event to the view under the first pointer. 15267 * <p> 15268 * Do not call this method directly. 15269 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 15270 * </p> 15271 * 15272 * @param event The motion event to be dispatched. 15273 * @return True if the event was handled by the view, false otherwise. 15274 */ dispatchGenericPointerEvent(MotionEvent event)15275 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 15276 return false; 15277 } 15278 15279 /** 15280 * Dispatch a generic motion event to the currently focused view. 15281 * <p> 15282 * Do not call this method directly. 15283 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 15284 * </p> 15285 * 15286 * @param event The motion event to be dispatched. 15287 * @return True if the event was handled by the view, false otherwise. 15288 */ dispatchGenericFocusedEvent(MotionEvent event)15289 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 15290 return false; 15291 } 15292 15293 /** 15294 * Dispatch a pointer event. 15295 * <p> 15296 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 15297 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 15298 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 15299 * and should not be expected to handle other pointing device features. 15300 * </p> 15301 * 15302 * @param event The motion event to be dispatched. 15303 * @return True if the event was handled by the view, false otherwise. 15304 * @hide 15305 */ 15306 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchPointerEvent(MotionEvent event)15307 public final boolean dispatchPointerEvent(MotionEvent event) { 15308 if (event.isTouchEvent()) { 15309 return dispatchTouchEvent(event); 15310 } else { 15311 return dispatchGenericMotionEvent(event); 15312 } 15313 } 15314 15315 /** 15316 * Called when the window containing this view gains or loses window focus. 15317 * ViewGroups should override to route to their children. 15318 * 15319 * @param hasFocus True if the window containing this view now has focus, 15320 * false otherwise. 15321 */ dispatchWindowFocusChanged(boolean hasFocus)15322 public void dispatchWindowFocusChanged(boolean hasFocus) { 15323 onWindowFocusChanged(hasFocus); 15324 } 15325 15326 /** 15327 * Called when the window containing this view gains or loses focus. Note 15328 * that this is separate from view focus: to receive key events, both 15329 * your view and its window must have focus. If a window is displayed 15330 * on top of yours that takes input focus, then your own window will lose 15331 * focus but the view focus will remain unchanged. 15332 * 15333 * @param hasWindowFocus True if the window containing this view now has 15334 * focus, false otherwise. 15335 */ onWindowFocusChanged(boolean hasWindowFocus)15336 public void onWindowFocusChanged(boolean hasWindowFocus) { 15337 if (!hasWindowFocus) { 15338 if (isPressed()) { 15339 setPressed(false); 15340 } 15341 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15342 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 15343 notifyFocusChangeToImeFocusController(false /* hasFocus */); 15344 } 15345 removeLongPressCallback(); 15346 removeTapCallback(); 15347 onFocusLost(); 15348 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 15349 notifyFocusChangeToImeFocusController(true /* hasFocus */); 15350 } 15351 15352 refreshDrawableState(); 15353 } 15354 15355 /** 15356 * Returns true if this view is in a window that currently has window focus. 15357 * Note that this is not the same as the view itself having focus. 15358 * 15359 * @return True if this view is in a window that currently has window focus. 15360 */ hasWindowFocus()15361 public boolean hasWindowFocus() { 15362 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 15363 } 15364 15365 /** 15366 * @return {@code true} if this view is in a window that currently has IME focusable state. 15367 * @hide 15368 */ hasImeFocus()15369 public boolean hasImeFocus() { 15370 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 15371 } 15372 15373 /** 15374 * Dispatch a view visibility change down the view hierarchy. 15375 * ViewGroups should override to route to their children. 15376 * @param changedView The view whose visibility changed. Could be 'this' or 15377 * an ancestor view. 15378 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 15379 * {@link #INVISIBLE} or {@link #GONE}. 15380 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)15381 protected void dispatchVisibilityChanged(@NonNull View changedView, 15382 @Visibility int visibility) { 15383 onVisibilityChanged(changedView, visibility); 15384 } 15385 15386 /** 15387 * Called when the visibility of the view or an ancestor of the view has 15388 * changed. 15389 * 15390 * @param changedView The view whose visibility changed. May be 15391 * {@code this} or an ancestor view. 15392 * @param visibility The new visibility, one of {@link #VISIBLE}, 15393 * {@link #INVISIBLE} or {@link #GONE}. 15394 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)15395 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 15396 } 15397 15398 /** 15399 * Dispatch a hint about whether this view is displayed. For instance, when 15400 * a View moves out of the screen, it might receives a display hint indicating 15401 * the view is not displayed. Applications should not <em>rely</em> on this hint 15402 * as there is no guarantee that they will receive one. 15403 * 15404 * @param hint A hint about whether or not this view is displayed: 15405 * {@link #VISIBLE} or {@link #INVISIBLE}. 15406 */ dispatchDisplayHint(@isibility int hint)15407 public void dispatchDisplayHint(@Visibility int hint) { 15408 onDisplayHint(hint); 15409 } 15410 15411 /** 15412 * Gives this view a hint about whether is displayed or not. For instance, when 15413 * a View moves out of the screen, it might receives a display hint indicating 15414 * the view is not displayed. Applications should not <em>rely</em> on this hint 15415 * as there is no guarantee that they will receive one. 15416 * 15417 * @param hint A hint about whether or not this view is displayed: 15418 * {@link #VISIBLE} or {@link #INVISIBLE}. 15419 */ onDisplayHint(@isibility int hint)15420 protected void onDisplayHint(@Visibility int hint) { 15421 } 15422 15423 /** 15424 * Dispatch a window visibility change down the view hierarchy. 15425 * ViewGroups should override to route to their children. 15426 * 15427 * @param visibility The new visibility of the window. 15428 * 15429 * @see #onWindowVisibilityChanged(int) 15430 */ dispatchWindowVisibilityChanged(@isibility int visibility)15431 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 15432 onWindowVisibilityChanged(visibility); 15433 } 15434 15435 /** 15436 * Called when the window containing has change its visibility 15437 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 15438 * that this tells you whether or not your window is being made visible 15439 * to the window manager; this does <em>not</em> tell you whether or not 15440 * your window is obscured by other windows on the screen, even if it 15441 * is itself visible. 15442 * 15443 * @param visibility The new visibility of the window. 15444 */ onWindowVisibilityChanged(@isibility int visibility)15445 protected void onWindowVisibilityChanged(@Visibility int visibility) { 15446 if (visibility == VISIBLE) { 15447 initialAwakenScrollBars(); 15448 } 15449 } 15450 15451 /** 15452 * @return true if this view and all ancestors are visible as of the last 15453 * {@link #onVisibilityAggregated(boolean)} call. 15454 * 15455 * @hide 15456 */ isAggregatedVisible()15457 public boolean isAggregatedVisible() { 15458 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 15459 } 15460 15461 /** 15462 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 15463 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 15464 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 15465 * 15466 * @param isVisible true if this view's visibility to the user is uninterrupted by its 15467 * ancestors or by window visibility 15468 * @return true if this view is visible to the user, not counting clipping or overlapping 15469 */ dispatchVisibilityAggregated(boolean isVisible)15470 boolean dispatchVisibilityAggregated(boolean isVisible) { 15471 final boolean thisVisible = getVisibility() == VISIBLE; 15472 // If we're not visible but something is telling us we are, ignore it. 15473 if (thisVisible || !isVisible) { 15474 onVisibilityAggregated(isVisible); 15475 } 15476 return thisVisible && isVisible; 15477 } 15478 15479 /** 15480 * Called when the user-visibility of this View is potentially affected by a change 15481 * to this view itself, an ancestor view or the window this view is attached to. 15482 * 15483 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 15484 * and this view's window is also visible 15485 */ 15486 @CallSuper onVisibilityAggregated(boolean isVisible)15487 public void onVisibilityAggregated(boolean isVisible) { 15488 // Update our internal visibility tracking so we can detect changes 15489 boolean oldVisible = isAggregatedVisible(); 15490 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 15491 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 15492 if (isVisible && mAttachInfo != null) { 15493 initialAwakenScrollBars(); 15494 } 15495 15496 final Drawable dr = mBackground; 15497 if (dr != null && isVisible != dr.isVisible()) { 15498 dr.setVisible(isVisible, false); 15499 } 15500 final Drawable hl = mDefaultFocusHighlight; 15501 if (hl != null && isVisible != hl.isVisible()) { 15502 hl.setVisible(isVisible, false); 15503 } 15504 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 15505 if (fg != null && isVisible != fg.isVisible()) { 15506 fg.setVisible(isVisible, false); 15507 } 15508 15509 if (isAutofillable()) { 15510 AutofillManager afm = getAutofillManager(); 15511 15512 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 15513 if (mVisibilityChangeForAutofillHandler != null) { 15514 mVisibilityChangeForAutofillHandler.removeMessages(0); 15515 } 15516 15517 // If the view is in the background but still part of the hierarchy this is called 15518 // with isVisible=false. Hence visibility==false requires further checks 15519 if (isVisible) { 15520 afm.notifyViewVisibilityChanged(this, true); 15521 } else { 15522 if (mVisibilityChangeForAutofillHandler == null) { 15523 mVisibilityChangeForAutofillHandler = 15524 new VisibilityChangeForAutofillHandler(afm, this); 15525 } 15526 // Let current operation (e.g. removal of the view from the hierarchy) 15527 // finish before checking state 15528 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 15529 } 15530 } 15531 } 15532 15533 if (isVisible != oldVisible) { 15534 if (isAccessibilityPane()) { 15535 notifyViewAccessibilityStateChangedIfNeeded(isVisible 15536 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 15537 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 15538 } 15539 15540 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 15541 15542 if (!getSystemGestureExclusionRects().isEmpty()) { 15543 postUpdate(this::updateSystemGestureExclusionRects); 15544 } 15545 15546 if (!collectPreferKeepClearRects().isEmpty()) { 15547 postUpdate(this::updateKeepClearRects); 15548 } 15549 } 15550 } 15551 15552 /** 15553 * Returns the current visibility of the window this view is attached to 15554 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 15555 * 15556 * @return Returns the current visibility of the view's window. 15557 */ 15558 @Visibility getWindowVisibility()15559 public int getWindowVisibility() { 15560 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 15561 } 15562 15563 /** 15564 * Retrieve the overall visible display size in which the window this view is 15565 * attached to has been positioned in. This takes into account screen 15566 * decorations above the window, for both cases where the window itself 15567 * is being position inside of them or the window is being placed under 15568 * then and covered insets are used for the window to position its content 15569 * inside. In effect, this tells you the available area where content can 15570 * be placed and remain visible to users. 15571 * 15572 * @param outRect Filled in with the visible display frame. If the view 15573 * is not attached to a window, this is simply the raw display size. 15574 */ getWindowVisibleDisplayFrame(Rect outRect)15575 public void getWindowVisibleDisplayFrame(Rect outRect) { 15576 if (mAttachInfo != null) { 15577 mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); 15578 return; 15579 } 15580 // The view is not attached to a display so we don't have a context. 15581 // Make a best guess about the display size. 15582 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 15583 d.getRectSize(outRect); 15584 } 15585 15586 /** 15587 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 15588 * is currently in without any insets. 15589 * 15590 * @hide 15591 */ 15592 @UnsupportedAppUsage 15593 @TestApi getWindowDisplayFrame(@onNull Rect outRect)15594 public void getWindowDisplayFrame(@NonNull Rect outRect) { 15595 if (mAttachInfo != null) { 15596 mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); 15597 return; 15598 } 15599 // The view is not attached to a display so we don't have a context. 15600 // Make a best guess about the display size. 15601 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 15602 d.getRectSize(outRect); 15603 } 15604 15605 /** 15606 * Dispatch a notification about a resource configuration change down 15607 * the view hierarchy. 15608 * ViewGroups should override to route to their children. 15609 * 15610 * @param newConfig The new resource configuration. 15611 * 15612 * @see #onConfigurationChanged(android.content.res.Configuration) 15613 */ dispatchConfigurationChanged(Configuration newConfig)15614 public void dispatchConfigurationChanged(Configuration newConfig) { 15615 onConfigurationChanged(newConfig); 15616 } 15617 15618 /** 15619 * Called when the current configuration of the resources being used 15620 * by the application have changed. You can use this to decide when 15621 * to reload resources that can changed based on orientation and other 15622 * configuration characteristics. You only need to use this if you are 15623 * not relying on the normal {@link android.app.Activity} mechanism of 15624 * recreating the activity instance upon a configuration change. 15625 * 15626 * @param newConfig The new resource configuration. 15627 */ onConfigurationChanged(Configuration newConfig)15628 protected void onConfigurationChanged(Configuration newConfig) { 15629 } 15630 15631 /** 15632 * Private function to aggregate all per-view attributes in to the view 15633 * root. 15634 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)15635 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 15636 performCollectViewAttributes(attachInfo, visibility); 15637 } 15638 performCollectViewAttributes(AttachInfo attachInfo, int visibility)15639 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 15640 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 15641 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 15642 attachInfo.mKeepScreenOn = true; 15643 } 15644 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 15645 ListenerInfo li = mListenerInfo; 15646 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 15647 attachInfo.mHasSystemUiListeners = true; 15648 } 15649 } 15650 } 15651 needGlobalAttributesUpdate(boolean force)15652 void needGlobalAttributesUpdate(boolean force) { 15653 final AttachInfo ai = mAttachInfo; 15654 if (ai != null && !ai.mRecomputeGlobalAttributes) { 15655 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 15656 || ai.mHasSystemUiListeners) { 15657 ai.mRecomputeGlobalAttributes = true; 15658 } 15659 } 15660 } 15661 15662 /** 15663 * Returns whether the device is currently in touch mode. Touch mode is entered 15664 * once the user begins interacting with the device by touch, and affects various 15665 * things like whether focus is always visible to the user. 15666 * 15667 * @return Whether the device is in touch mode. 15668 */ 15669 @ViewDebug.ExportedProperty isInTouchMode()15670 public boolean isInTouchMode() { 15671 if (mAttachInfo != null) { 15672 return mAttachInfo.mInTouchMode; 15673 } else { 15674 return ViewRootImpl.isInTouchMode(); 15675 } 15676 } 15677 15678 /** 15679 * Returns the context the view is running in, through which it can 15680 * access the current theme, resources, etc. 15681 * 15682 * @return The view's Context. 15683 */ 15684 @ViewDebug.CapturedViewProperty 15685 @UiContext getContext()15686 public final Context getContext() { 15687 return mContext; 15688 } 15689 15690 /** 15691 * Handle a key event before it is processed by any input method 15692 * associated with the view hierarchy. This can be used to intercept 15693 * key events in special situations before the IME consumes them; a 15694 * typical example would be handling the BACK key to update the application's 15695 * UI instead of allowing the IME to see it and close itself. 15696 * 15697 * @param keyCode The value in event.getKeyCode(). 15698 * @param event Description of the key event. 15699 * @return If you handled the event, return true. If you want to allow the 15700 * event to be handled by the next receiver, return false. 15701 */ onKeyPreIme(int keyCode, KeyEvent event)15702 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 15703 return false; 15704 } 15705 15706 /** 15707 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 15708 * KeyEvent.Callback.onKeyDown()}: perform press of the view 15709 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 15710 * is released, if the view is enabled and clickable. 15711 * <p> 15712 * Key presses in software keyboards will generally NOT trigger this 15713 * listener, although some may elect to do so in some situations. Do not 15714 * rely on this to catch software key presses. 15715 * 15716 * @param keyCode a key code that represents the button pressed, from 15717 * {@link android.view.KeyEvent} 15718 * @param event the KeyEvent object that defines the button action 15719 */ onKeyDown(int keyCode, KeyEvent event)15720 public boolean onKeyDown(int keyCode, KeyEvent event) { 15721 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 15722 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15723 return true; 15724 } 15725 15726 if (event.getRepeatCount() == 0) { 15727 // Long clickable items don't necessarily have to be clickable. 15728 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 15729 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 15730 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 15731 // For the purposes of menu anchoring and drawable hotspots, 15732 // key events are considered to be at the center of the view. 15733 final float x = getWidth() / 2f; 15734 final float y = getHeight() / 2f; 15735 if (clickable) { 15736 setPressed(true, x, y); 15737 } 15738 checkForLongClick( 15739 ViewConfiguration.getLongPressTimeout(), 15740 x, 15741 y, 15742 // This is not a touch gesture -- do not classify it as one. 15743 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 15744 return true; 15745 } 15746 } 15747 } 15748 15749 return false; 15750 } 15751 15752 /** 15753 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 15754 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 15755 * the event). 15756 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15757 * although some may elect to do so in some situations. Do not rely on this to 15758 * catch software key presses. 15759 */ onKeyLongPress(int keyCode, KeyEvent event)15760 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 15761 return false; 15762 } 15763 15764 /** 15765 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 15766 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 15767 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 15768 * or {@link KeyEvent#KEYCODE_SPACE} is released. 15769 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15770 * although some may elect to do so in some situations. Do not rely on this to 15771 * catch software key presses. 15772 * 15773 * @param keyCode A key code that represents the button pressed, from 15774 * {@link android.view.KeyEvent}. 15775 * @param event The KeyEvent object that defines the button action. 15776 */ onKeyUp(int keyCode, KeyEvent event)15777 public boolean onKeyUp(int keyCode, KeyEvent event) { 15778 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 15779 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15780 return true; 15781 } 15782 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 15783 setPressed(false); 15784 15785 if (!mHasPerformedLongPress) { 15786 // This is a tap, so remove the longpress check 15787 removeLongPressCallback(); 15788 if (!event.isCanceled()) { 15789 return performClickInternal(); 15790 } 15791 } 15792 } 15793 } 15794 return false; 15795 } 15796 15797 /** 15798 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 15799 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 15800 * the event). 15801 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15802 * although some may elect to do so in some situations. Do not rely on this to 15803 * catch software key presses. 15804 * 15805 * @param keyCode A key code that represents the button pressed, from 15806 * {@link android.view.KeyEvent}. 15807 * @param repeatCount The number of times the action was made. 15808 * @param event The KeyEvent object that defines the button action. 15809 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)15810 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 15811 return false; 15812 } 15813 15814 /** 15815 * Called on the focused view when a key shortcut event is not handled. 15816 * Override this method to implement local key shortcuts for the View. 15817 * Key shortcuts can also be implemented by setting the 15818 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 15819 * 15820 * @param keyCode The value in event.getKeyCode(). 15821 * @param event Description of the key event. 15822 * @return If you handled the event, return true. If you want to allow the 15823 * event to be handled by the next receiver, return false. 15824 */ onKeyShortcut(int keyCode, KeyEvent event)15825 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 15826 return false; 15827 } 15828 15829 /** 15830 * Check whether the called view is a text editor, in which case it 15831 * would make sense to automatically display a soft input window for 15832 * it. Subclasses should override this if they implement 15833 * {@link #onCreateInputConnection(EditorInfo)} to return true if 15834 * a call on that method would return a non-null InputConnection, and 15835 * they are really a first-class editor that the user would normally 15836 * start typing on when the go into a window containing your view. 15837 * 15838 * <p>The default implementation always returns false. This does 15839 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 15840 * will not be called or the user can not otherwise perform edits on your 15841 * view; it is just a hint to the system that this is not the primary 15842 * purpose of this view. 15843 * 15844 * @return Returns true if this view is a text editor, else false. 15845 */ onCheckIsTextEditor()15846 public boolean onCheckIsTextEditor() { 15847 return false; 15848 } 15849 15850 /** 15851 * Create a new InputConnection for an InputMethod to interact 15852 * with the view. The default implementation returns null, since it doesn't 15853 * support input methods. You can override this to implement such support. 15854 * This is only needed for views that take focus and text input. 15855 * 15856 * <p>When implementing this, you probably also want to implement 15857 * {@link #onCheckIsTextEditor()} to indicate you will return a 15858 * non-null InputConnection.</p> 15859 * 15860 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 15861 * object correctly and in its entirety, so that the connected IME can rely 15862 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 15863 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 15864 * must be filled in with the correct cursor position for IMEs to work correctly 15865 * with your application.</p> 15866 * 15867 * @param outAttrs Fill in with attribute information about the connection. 15868 */ onCreateInputConnection(EditorInfo outAttrs)15869 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 15870 return null; 15871 } 15872 15873 /** 15874 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 15875 * that the system has successfully initialized an {@link InputConnection} and it is ready for 15876 * use. 15877 * 15878 * <p>The default implementation does nothing, since a view doesn't support input methods by 15879 * default (see {@link #onCreateInputConnection}). 15880 * 15881 * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, 15882 * after it's been fully initialized by the system. 15883 * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. 15884 * @param handler The dedicated {@link Handler} on which IPC method calls from input methods 15885 * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If 15886 * that method returns null, this parameter will be null also. 15887 * 15888 * @hide 15889 */ onInputConnectionOpenedInternal(@onNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler)15890 public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, 15891 @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} 15892 15893 /** 15894 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 15895 * that the {@link InputConnection} has been closed. 15896 * 15897 * <p>The default implementation does nothing, since a view doesn't support input methods by 15898 * default (see {@link #onCreateInputConnection}). 15899 * 15900 * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when 15901 * the {@link InputConnection} is closed or the connection is not valid and managed by 15902 * {@link com.android.server.inputmethod.InputMethodManagerService}. 15903 * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. 15904 * 15905 * @hide 15906 */ onInputConnectionClosedInternal()15907 public void onInputConnectionClosedInternal() {} 15908 15909 /** 15910 * Called by the {@link android.view.inputmethod.InputMethodManager} 15911 * when a view who is not the current 15912 * input connection target is trying to make a call on the manager. The 15913 * default implementation returns false; you can override this to return 15914 * true for certain views if you are performing InputConnection proxying 15915 * to them. 15916 * @param view The View that is making the InputMethodManager call. 15917 * @return Return true to allow the call, false to reject. 15918 */ checkInputConnectionProxy(View view)15919 public boolean checkInputConnectionProxy(View view) { 15920 return false; 15921 } 15922 15923 /** 15924 * Show the context menu for this view. It is not safe to hold on to the 15925 * menu after returning from this method. 15926 * 15927 * You should normally not overload this method. Overload 15928 * {@link #onCreateContextMenu(ContextMenu)} or define an 15929 * {@link OnCreateContextMenuListener} to add items to the context menu. 15930 * 15931 * @param menu The context menu to populate 15932 */ createContextMenu(ContextMenu menu)15933 public void createContextMenu(ContextMenu menu) { 15934 ContextMenuInfo menuInfo = getContextMenuInfo(); 15935 15936 // Sets the current menu info so all items added to menu will have 15937 // my extra info set. 15938 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 15939 15940 onCreateContextMenu(menu); 15941 ListenerInfo li = mListenerInfo; 15942 if (li != null && li.mOnCreateContextMenuListener != null) { 15943 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 15944 } 15945 15946 // Clear the extra information so subsequent items that aren't mine don't 15947 // have my extra info. 15948 ((MenuBuilder)menu).setCurrentMenuInfo(null); 15949 15950 if (mParent != null) { 15951 mParent.createContextMenu(menu); 15952 } 15953 } 15954 15955 /** 15956 * Views should implement this if they have extra information to associate 15957 * with the context menu. The return result is supplied as a parameter to 15958 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 15959 * callback. 15960 * 15961 * @return Extra information about the item for which the context menu 15962 * should be shown. This information will vary across different 15963 * subclasses of View. 15964 */ getContextMenuInfo()15965 protected ContextMenuInfo getContextMenuInfo() { 15966 return null; 15967 } 15968 15969 /** 15970 * Views should implement this if the view itself is going to add items to 15971 * the context menu. 15972 * 15973 * @param menu the context menu to populate 15974 */ onCreateContextMenu(ContextMenu menu)15975 protected void onCreateContextMenu(ContextMenu menu) { 15976 } 15977 15978 /** 15979 * Implement this method to handle trackball motion events. The 15980 * <em>relative</em> movement of the trackball since the last event 15981 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 15982 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 15983 * that a movement of 1 corresponds to the user pressing one DPAD key (so 15984 * they will often be fractional values, representing the more fine-grained 15985 * movement information available from a trackball). 15986 * 15987 * @param event The motion event. 15988 * @return True if the event was handled, false otherwise. 15989 */ onTrackballEvent(MotionEvent event)15990 public boolean onTrackballEvent(MotionEvent event) { 15991 return false; 15992 } 15993 15994 /** 15995 * Implement this method to handle generic motion events. 15996 * <p> 15997 * Generic motion events describe joystick movements, mouse hovers, track pad 15998 * touches, scroll wheel movements and other input events. The 15999 * {@link MotionEvent#getSource() source} of the motion event specifies 16000 * the class of input that was received. Implementations of this method 16001 * must examine the bits in the source before processing the event. 16002 * The following code example shows how this is done. 16003 * </p><p> 16004 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 16005 * are delivered to the view under the pointer. All other generic motion events are 16006 * delivered to the focused view. 16007 * </p> 16008 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 16009 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 16010 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 16011 * // process the joystick movement... 16012 * return true; 16013 * } 16014 * } 16015 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 16016 * switch (event.getAction()) { 16017 * case MotionEvent.ACTION_HOVER_MOVE: 16018 * // process the mouse hover movement... 16019 * return true; 16020 * case MotionEvent.ACTION_SCROLL: 16021 * // process the scroll wheel movement... 16022 * return true; 16023 * } 16024 * } 16025 * return super.onGenericMotionEvent(event); 16026 * }</pre> 16027 * 16028 * @param event The generic motion event being processed. 16029 * @return True if the event was handled, false otherwise. 16030 */ onGenericMotionEvent(MotionEvent event)16031 public boolean onGenericMotionEvent(MotionEvent event) { 16032 return false; 16033 } 16034 16035 /** 16036 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 16037 * <p> 16038 * This method is dispatching hover events to the delegate target to support explore by touch. 16039 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 16040 * the delegate target according to the pointer and the touch area of the delegate while touch 16041 * exploration enabled. 16042 * </p> 16043 * 16044 * @param event The motion event dispatch to the delegate target. 16045 * @return True if the event was handled, false otherwise. 16046 * 16047 * @see #onHoverEvent 16048 */ dispatchTouchExplorationHoverEvent(MotionEvent event)16049 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 16050 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 16051 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 16052 return false; 16053 } 16054 16055 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 16056 final int action = event.getActionMasked(); 16057 boolean pointInDelegateRegion = false; 16058 boolean handled = false; 16059 16060 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 16061 for (int i = 0; i < info.getRegionCount(); i++) { 16062 Region r = info.getRegionAt(i); 16063 if (r.contains((int) event.getX(), (int) event.getY())) { 16064 pointInDelegateRegion = true; 16065 } 16066 } 16067 16068 // Explore by touch should dispatch events to children under the pointer first if any 16069 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 16070 // hover events but receive accessibility focus, it should also not delegate to these 16071 // views when hovered. 16072 if (!oldHoveringTouchDelegate) { 16073 if ((action == MotionEvent.ACTION_HOVER_ENTER 16074 || action == MotionEvent.ACTION_HOVER_MOVE) 16075 && !pointInHoveredChild(event) 16076 && pointInDelegateRegion) { 16077 mHoveringTouchDelegate = true; 16078 } 16079 } else { 16080 if (action == MotionEvent.ACTION_HOVER_EXIT 16081 || (action == MotionEvent.ACTION_HOVER_MOVE 16082 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 16083 mHoveringTouchDelegate = false; 16084 } 16085 } 16086 switch (action) { 16087 case MotionEvent.ACTION_HOVER_MOVE: 16088 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 16089 // Inside bounds, dispatch as is. 16090 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 16091 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 16092 // Moving inbound, synthesize hover enter. 16093 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 16094 ? event : MotionEvent.obtainNoHistory(event); 16095 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 16096 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 16097 eventNoHistory.setAction(action); 16098 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 16099 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 16100 // Moving outbound, synthesize hover exit. 16101 final boolean hoverExitPending = event.isHoverExitPending(); 16102 event.setHoverExitPending(true); 16103 mTouchDelegate.onTouchExplorationHoverEvent(event); 16104 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 16105 ? event : MotionEvent.obtainNoHistory(event); 16106 eventNoHistory.setHoverExitPending(hoverExitPending); 16107 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 16108 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 16109 } // else: outside bounds, do nothing. 16110 break; 16111 case MotionEvent.ACTION_HOVER_ENTER: 16112 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 16113 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 16114 } 16115 break; 16116 case MotionEvent.ACTION_HOVER_EXIT: 16117 if (oldHoveringTouchDelegate) { 16118 mTouchDelegate.onTouchExplorationHoverEvent(event); 16119 } 16120 break; 16121 } 16122 return handled; 16123 } 16124 16125 /** 16126 * Implement this method to handle hover events. 16127 * <p> 16128 * This method is called whenever a pointer is hovering into, over, or out of the 16129 * bounds of a view and the view is not currently being touched. 16130 * Hover events are represented as pointer events with action 16131 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 16132 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 16133 * </p> 16134 * <ul> 16135 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 16136 * when the pointer enters the bounds of the view.</li> 16137 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 16138 * when the pointer has already entered the bounds of the view and has moved.</li> 16139 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 16140 * when the pointer has exited the bounds of the view or when the pointer is 16141 * about to go down due to a button click, tap, or similar user action that 16142 * causes the view to be touched.</li> 16143 * </ul> 16144 * <p> 16145 * The view should implement this method to return true to indicate that it is 16146 * handling the hover event, such as by changing its drawable state. 16147 * </p><p> 16148 * The default implementation calls {@link #setHovered} to update the hovered state 16149 * of the view when a hover enter or hover exit event is received, if the view 16150 * is enabled and is clickable. The default implementation also sends hover 16151 * accessibility events. 16152 * </p> 16153 * 16154 * @param event The motion event that describes the hover. 16155 * @return True if the view handled the hover event. 16156 * 16157 * @see #isHovered 16158 * @see #setHovered 16159 * @see #onHoverChanged 16160 */ onHoverEvent(MotionEvent event)16161 public boolean onHoverEvent(MotionEvent event) { 16162 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 16163 return true; 16164 } 16165 16166 // The root view may receive hover (or touch) events that are outside the bounds of 16167 // the window. This code ensures that we only send accessibility events for 16168 // hovers that are actually within the bounds of the root view. 16169 final int action = event.getActionMasked(); 16170 if (!mSendingHoverAccessibilityEvents) { 16171 if ((action == MotionEvent.ACTION_HOVER_ENTER 16172 || action == MotionEvent.ACTION_HOVER_MOVE) 16173 && !hasHoveredChild() 16174 && pointInView(event.getX(), event.getY())) { 16175 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 16176 mSendingHoverAccessibilityEvents = true; 16177 } 16178 } else { 16179 if (action == MotionEvent.ACTION_HOVER_EXIT 16180 || (action == MotionEvent.ACTION_HOVER_MOVE 16181 && !pointInView(event.getX(), event.getY()))) { 16182 mSendingHoverAccessibilityEvents = false; 16183 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 16184 } 16185 } 16186 16187 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 16188 && event.isFromSource(InputDevice.SOURCE_MOUSE) 16189 && isOnScrollbar(event.getX(), event.getY())) { 16190 awakenScrollBars(); 16191 } 16192 16193 // If we consider ourself hoverable, or if we we're already hovered, 16194 // handle changing state in response to ENTER and EXIT events. 16195 if (isHoverable() || isHovered()) { 16196 switch (action) { 16197 case MotionEvent.ACTION_HOVER_ENTER: 16198 setHovered(true); 16199 break; 16200 case MotionEvent.ACTION_HOVER_EXIT: 16201 setHovered(false); 16202 break; 16203 } 16204 16205 // Dispatch the event to onGenericMotionEvent before returning true. 16206 // This is to provide compatibility with existing applications that 16207 // handled HOVER_MOVE events in onGenericMotionEvent and that would 16208 // break because of the new default handling for hoverable views 16209 // in onHoverEvent. 16210 // Note that onGenericMotionEvent will be called by default when 16211 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 16212 dispatchGenericMotionEventInternal(event); 16213 // The event was already handled by calling setHovered(), so always 16214 // return true. 16215 return true; 16216 } 16217 16218 return false; 16219 } 16220 16221 /** 16222 * Returns true if the view should handle {@link #onHoverEvent} 16223 * by calling {@link #setHovered} to change its hovered state. 16224 * 16225 * @return True if the view is hoverable. 16226 */ isHoverable()16227 private boolean isHoverable() { 16228 final int viewFlags = mViewFlags; 16229 if ((viewFlags & ENABLED_MASK) == DISABLED) { 16230 return false; 16231 } 16232 16233 return (viewFlags & CLICKABLE) == CLICKABLE 16234 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 16235 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 16236 } 16237 16238 /** 16239 * Returns true if the view is currently hovered. 16240 * 16241 * @return True if the view is currently hovered. 16242 * 16243 * @see #setHovered 16244 * @see #onHoverChanged 16245 */ 16246 @ViewDebug.ExportedProperty isHovered()16247 public boolean isHovered() { 16248 return (mPrivateFlags & PFLAG_HOVERED) != 0; 16249 } 16250 16251 /** 16252 * Sets whether the view is currently hovered. 16253 * <p> 16254 * Calling this method also changes the drawable state of the view. This 16255 * enables the view to react to hover by using different drawable resources 16256 * to change its appearance. 16257 * </p><p> 16258 * The {@link #onHoverChanged} method is called when the hovered state changes. 16259 * </p> 16260 * 16261 * @param hovered True if the view is hovered. 16262 * 16263 * @see #isHovered 16264 * @see #onHoverChanged 16265 */ setHovered(boolean hovered)16266 public void setHovered(boolean hovered) { 16267 if (hovered) { 16268 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 16269 mPrivateFlags |= PFLAG_HOVERED; 16270 refreshDrawableState(); 16271 onHoverChanged(true); 16272 } 16273 } else { 16274 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 16275 mPrivateFlags &= ~PFLAG_HOVERED; 16276 refreshDrawableState(); 16277 onHoverChanged(false); 16278 } 16279 } 16280 } 16281 16282 /** 16283 * Implement this method to handle hover state changes. 16284 * <p> 16285 * This method is called whenever the hover state changes as a result of a 16286 * call to {@link #setHovered}. 16287 * </p> 16288 * 16289 * @param hovered The current hover state, as returned by {@link #isHovered}. 16290 * 16291 * @see #isHovered 16292 * @see #setHovered 16293 */ onHoverChanged(boolean hovered)16294 public void onHoverChanged(boolean hovered) { 16295 } 16296 16297 /** 16298 * Handles scroll bar dragging by mouse input. 16299 * 16300 * @hide 16301 * @param event The motion event. 16302 * 16303 * @return true if the event was handled as a scroll bar dragging, false otherwise. 16304 */ handleScrollBarDragging(MotionEvent event)16305 protected boolean handleScrollBarDragging(MotionEvent event) { 16306 if (mScrollCache == null) { 16307 return false; 16308 } 16309 final float x = event.getX(); 16310 final float y = event.getY(); 16311 final int action = event.getAction(); 16312 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 16313 && action != MotionEvent.ACTION_DOWN) 16314 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 16315 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 16316 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 16317 return false; 16318 } 16319 16320 switch (action) { 16321 case MotionEvent.ACTION_MOVE: 16322 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 16323 return false; 16324 } 16325 if (mScrollCache.mScrollBarDraggingState 16326 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 16327 final Rect bounds = mScrollCache.mScrollBarBounds; 16328 getVerticalScrollBarBounds(bounds, null); 16329 final int range = computeVerticalScrollRange(); 16330 final int offset = computeVerticalScrollOffset(); 16331 final int extent = computeVerticalScrollExtent(); 16332 16333 final int thumbLength = ScrollBarUtils.getThumbLength( 16334 bounds.height(), bounds.width(), extent, range); 16335 final int thumbOffset = ScrollBarUtils.getThumbOffset( 16336 bounds.height(), thumbLength, extent, range, offset); 16337 16338 final float diff = y - mScrollCache.mScrollBarDraggingPos; 16339 final float maxThumbOffset = bounds.height() - thumbLength; 16340 final float newThumbOffset = 16341 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 16342 final int height = getHeight(); 16343 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 16344 && height > 0 && extent > 0) { 16345 final int newY = Math.round((range - extent) 16346 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 16347 if (newY != getScrollY()) { 16348 mScrollCache.mScrollBarDraggingPos = y; 16349 setScrollY(newY); 16350 } 16351 } 16352 return true; 16353 } 16354 if (mScrollCache.mScrollBarDraggingState 16355 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 16356 final Rect bounds = mScrollCache.mScrollBarBounds; 16357 getHorizontalScrollBarBounds(bounds, null); 16358 final int range = computeHorizontalScrollRange(); 16359 final int offset = computeHorizontalScrollOffset(); 16360 final int extent = computeHorizontalScrollExtent(); 16361 16362 final int thumbLength = ScrollBarUtils.getThumbLength( 16363 bounds.width(), bounds.height(), extent, range); 16364 final int thumbOffset = ScrollBarUtils.getThumbOffset( 16365 bounds.width(), thumbLength, extent, range, offset); 16366 16367 final float diff = x - mScrollCache.mScrollBarDraggingPos; 16368 final float maxThumbOffset = bounds.width() - thumbLength; 16369 final float newThumbOffset = 16370 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 16371 final int width = getWidth(); 16372 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 16373 && width > 0 && extent > 0) { 16374 final int newX = Math.round((range - extent) 16375 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 16376 if (newX != getScrollX()) { 16377 mScrollCache.mScrollBarDraggingPos = x; 16378 setScrollX(newX); 16379 } 16380 } 16381 return true; 16382 } 16383 case MotionEvent.ACTION_DOWN: 16384 if (mScrollCache.state == ScrollabilityCache.OFF) { 16385 return false; 16386 } 16387 if (isOnVerticalScrollbarThumb(x, y)) { 16388 mScrollCache.mScrollBarDraggingState = 16389 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 16390 mScrollCache.mScrollBarDraggingPos = y; 16391 return true; 16392 } 16393 if (isOnHorizontalScrollbarThumb(x, y)) { 16394 mScrollCache.mScrollBarDraggingState = 16395 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 16396 mScrollCache.mScrollBarDraggingPos = x; 16397 return true; 16398 } 16399 } 16400 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 16401 return false; 16402 } 16403 16404 /** 16405 * Implement this method to handle touch screen motion events. 16406 * <p> 16407 * If this method is used to detect click actions, it is recommended that 16408 * the actions be performed by implementing and calling 16409 * {@link #performClick()}. This will ensure consistent system behavior, 16410 * including: 16411 * <ul> 16412 * <li>obeying click sound preferences 16413 * <li>dispatching OnClickListener calls 16414 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 16415 * accessibility features are enabled 16416 * </ul> 16417 * 16418 * @param event The motion event. 16419 * @return True if the event was handled, false otherwise. 16420 */ onTouchEvent(MotionEvent event)16421 public boolean onTouchEvent(MotionEvent event) { 16422 final float x = event.getX(); 16423 final float y = event.getY(); 16424 final int viewFlags = mViewFlags; 16425 final int action = event.getAction(); 16426 16427 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 16428 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 16429 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 16430 16431 if ((viewFlags & ENABLED_MASK) == DISABLED 16432 && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { 16433 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 16434 setPressed(false); 16435 } 16436 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16437 // A disabled view that is clickable still consumes the touch 16438 // events, it just doesn't respond to them. 16439 return clickable; 16440 } 16441 if (mTouchDelegate != null) { 16442 if (mTouchDelegate.onTouchEvent(event)) { 16443 return true; 16444 } 16445 } 16446 16447 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 16448 switch (action) { 16449 case MotionEvent.ACTION_UP: 16450 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16451 if ((viewFlags & TOOLTIP) == TOOLTIP) { 16452 handleTooltipUp(); 16453 } 16454 if (!clickable) { 16455 removeTapCallback(); 16456 removeLongPressCallback(); 16457 mInContextButtonPress = false; 16458 mHasPerformedLongPress = false; 16459 mIgnoreNextUpEvent = false; 16460 break; 16461 } 16462 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 16463 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 16464 // take focus if we don't have it already and we should in 16465 // touch mode. 16466 boolean focusTaken = false; 16467 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 16468 focusTaken = requestFocus(); 16469 } 16470 16471 if (prepressed) { 16472 // The button is being released before we actually 16473 // showed it as pressed. Make it show the pressed 16474 // state now (before scheduling the click) to ensure 16475 // the user sees it. 16476 setPressed(true, x, y); 16477 } 16478 16479 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 16480 // This is a tap, so remove the longpress check 16481 removeLongPressCallback(); 16482 16483 // Only perform take click actions if we were in the pressed state 16484 if (!focusTaken) { 16485 // Use a Runnable and post this rather than calling 16486 // performClick directly. This lets other visual state 16487 // of the view update before click actions start. 16488 if (mPerformClick == null) { 16489 mPerformClick = new PerformClick(); 16490 } 16491 if (!post(mPerformClick)) { 16492 performClickInternal(); 16493 } 16494 } 16495 } 16496 16497 if (mUnsetPressedState == null) { 16498 mUnsetPressedState = new UnsetPressedState(); 16499 } 16500 16501 if (prepressed) { 16502 postDelayed(mUnsetPressedState, 16503 ViewConfiguration.getPressedStateDuration()); 16504 } else if (!post(mUnsetPressedState)) { 16505 // If the post failed, unpress right now 16506 mUnsetPressedState.run(); 16507 } 16508 16509 removeTapCallback(); 16510 } 16511 mIgnoreNextUpEvent = false; 16512 break; 16513 16514 case MotionEvent.ACTION_DOWN: 16515 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 16516 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 16517 } 16518 mHasPerformedLongPress = false; 16519 16520 if (!clickable) { 16521 checkForLongClick( 16522 ViewConfiguration.getLongPressTimeout(), 16523 x, 16524 y, 16525 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16526 break; 16527 } 16528 16529 if (performButtonActionOnTouchDown(event)) { 16530 break; 16531 } 16532 16533 // Walk up the hierarchy to determine if we're inside a scrolling container. 16534 boolean isInScrollingContainer = isInScrollingContainer(); 16535 16536 // For views inside a scrolling container, delay the pressed feedback for 16537 // a short period in case this is a scroll. 16538 if (isInScrollingContainer) { 16539 mPrivateFlags |= PFLAG_PREPRESSED; 16540 if (mPendingCheckForTap == null) { 16541 mPendingCheckForTap = new CheckForTap(); 16542 } 16543 mPendingCheckForTap.x = event.getX(); 16544 mPendingCheckForTap.y = event.getY(); 16545 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 16546 } else { 16547 // Not inside a scrolling container, so show the feedback right away 16548 setPressed(true, x, y); 16549 checkForLongClick( 16550 ViewConfiguration.getLongPressTimeout(), 16551 x, 16552 y, 16553 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16554 } 16555 break; 16556 16557 case MotionEvent.ACTION_CANCEL: 16558 if (clickable) { 16559 setPressed(false); 16560 } 16561 removeTapCallback(); 16562 removeLongPressCallback(); 16563 mInContextButtonPress = false; 16564 mHasPerformedLongPress = false; 16565 mIgnoreNextUpEvent = false; 16566 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16567 break; 16568 16569 case MotionEvent.ACTION_MOVE: 16570 if (clickable) { 16571 drawableHotspotChanged(x, y); 16572 } 16573 16574 final int motionClassification = event.getClassification(); 16575 final boolean ambiguousGesture = 16576 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 16577 int touchSlop = mTouchSlop; 16578 if (ambiguousGesture && hasPendingLongPressCallback()) { 16579 if (!pointInView(x, y, touchSlop)) { 16580 // The default action here is to cancel long press. But instead, we 16581 // just extend the timeout here, in case the classification 16582 // stays ambiguous. 16583 removeLongPressCallback(); 16584 long delay = (long) (ViewConfiguration.getLongPressTimeout() 16585 * mAmbiguousGestureMultiplier); 16586 // Subtract the time already spent 16587 delay -= event.getEventTime() - event.getDownTime(); 16588 checkForLongClick( 16589 delay, 16590 x, 16591 y, 16592 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16593 } 16594 touchSlop *= mAmbiguousGestureMultiplier; 16595 } 16596 16597 // Be lenient about moving outside of buttons 16598 if (!pointInView(x, y, touchSlop)) { 16599 // Outside button 16600 // Remove any future long press/tap checks 16601 removeTapCallback(); 16602 removeLongPressCallback(); 16603 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 16604 setPressed(false); 16605 } 16606 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16607 } 16608 16609 final boolean deepPress = 16610 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 16611 if (deepPress && hasPendingLongPressCallback()) { 16612 // process the long click action immediately 16613 removeLongPressCallback(); 16614 checkForLongClick( 16615 0 /* send immediately */, 16616 x, 16617 y, 16618 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 16619 } 16620 16621 break; 16622 } 16623 16624 return true; 16625 } 16626 16627 return false; 16628 } 16629 16630 /** 16631 * @hide 16632 */ 16633 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isInScrollingContainer()16634 public boolean isInScrollingContainer() { 16635 ViewParent p = getParent(); 16636 while (p != null && p instanceof ViewGroup) { 16637 if (((ViewGroup) p).shouldDelayChildPressedState()) { 16638 return true; 16639 } 16640 p = p.getParent(); 16641 } 16642 return false; 16643 } 16644 16645 /** 16646 * Remove the longpress detection timer. 16647 */ removeLongPressCallback()16648 private void removeLongPressCallback() { 16649 if (mPendingCheckForLongPress != null) { 16650 removeCallbacks(mPendingCheckForLongPress); 16651 } 16652 } 16653 16654 /** 16655 * Return true if the long press callback is scheduled to run sometime in the future. 16656 * Return false if there is no scheduled long press callback at the moment. 16657 */ hasPendingLongPressCallback()16658 private boolean hasPendingLongPressCallback() { 16659 if (mPendingCheckForLongPress == null) { 16660 return false; 16661 } 16662 final AttachInfo attachInfo = mAttachInfo; 16663 if (attachInfo == null) { 16664 return false; 16665 } 16666 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 16667 } 16668 16669 /** 16670 * Remove the pending click action 16671 */ 16672 @UnsupportedAppUsage removePerformClickCallback()16673 private void removePerformClickCallback() { 16674 if (mPerformClick != null) { 16675 removeCallbacks(mPerformClick); 16676 } 16677 } 16678 16679 /** 16680 * Remove the prepress detection timer. 16681 */ removeUnsetPressCallback()16682 private void removeUnsetPressCallback() { 16683 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 16684 setPressed(false); 16685 removeCallbacks(mUnsetPressedState); 16686 } 16687 } 16688 16689 /** 16690 * Remove the tap detection timer. 16691 */ removeTapCallback()16692 private void removeTapCallback() { 16693 if (mPendingCheckForTap != null) { 16694 mPrivateFlags &= ~PFLAG_PREPRESSED; 16695 removeCallbacks(mPendingCheckForTap); 16696 } 16697 } 16698 16699 /** 16700 * Cancels a pending long press. Your subclass can use this if you 16701 * want the context menu to come up if the user presses and holds 16702 * at the same place, but you don't want it to come up if they press 16703 * and then move around enough to cause scrolling. 16704 */ cancelLongPress()16705 public void cancelLongPress() { 16706 removeLongPressCallback(); 16707 16708 /* 16709 * The prepressed state handled by the tap callback is a display 16710 * construct, but the tap callback will post a long press callback 16711 * less its own timeout. Remove it here. 16712 */ 16713 removeTapCallback(); 16714 } 16715 16716 /** 16717 * Sets the TouchDelegate for this View. 16718 */ setTouchDelegate(TouchDelegate delegate)16719 public void setTouchDelegate(TouchDelegate delegate) { 16720 mTouchDelegate = delegate; 16721 } 16722 16723 /** 16724 * Gets the TouchDelegate for this View. 16725 */ getTouchDelegate()16726 public TouchDelegate getTouchDelegate() { 16727 return mTouchDelegate; 16728 } 16729 16730 /** 16731 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 16732 * 16733 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 16734 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 16735 * available. This method should only be called for touch events. 16736 * 16737 * <p class="note">This API is not intended for most applications. Buffered dispatch 16738 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 16739 * streams will not improve your input latency. Side effects include: increased latency, 16740 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 16741 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 16742 * you.</p> 16743 * 16744 * To receive unbuffered events for arbitrary input device source classes, use 16745 * {@link #requestUnbufferedDispatch(int)}, 16746 * 16747 * @see View#requestUnbufferedDispatch(int) 16748 */ requestUnbufferedDispatch(MotionEvent event)16749 public final void requestUnbufferedDispatch(MotionEvent event) { 16750 final int action = event.getAction(); 16751 if (mAttachInfo == null 16752 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 16753 || !event.isTouchEvent()) { 16754 return; 16755 } 16756 mAttachInfo.mUnbufferedDispatchRequested = true; 16757 } 16758 16759 /** 16760 * Request unbuffered dispatch of the given event source class to this view. 16761 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 16762 * automatically terminate, and allows the specification of arbitrary input source classes. 16763 * 16764 * @param source The combined input source class to request unbuffered dispatch for. All 16765 * events coming from these source classes will not be buffered. Set to 16766 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 16767 * 16768 * @see View#requestUnbufferedDispatch(MotionEvent) 16769 */ requestUnbufferedDispatch(@nputSourceClass int source)16770 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 16771 if (mUnbufferedInputSource == source) { 16772 return; 16773 } 16774 mUnbufferedInputSource = source; 16775 if (mParent != null) { 16776 mParent.onDescendantUnbufferedRequested(); 16777 } 16778 } 16779 hasSize()16780 private boolean hasSize() { 16781 return (mBottom > mTop) && (mRight > mLeft); 16782 } 16783 canTakeFocus()16784 private boolean canTakeFocus() { 16785 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 16786 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 16787 && ((mViewFlags & ENABLED_MASK) == ENABLED) 16788 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 16789 } 16790 16791 /** 16792 * Set flags controlling behavior of this view. 16793 * 16794 * @param flags Constant indicating the value which should be set 16795 * @param mask Constant indicating the bit range that should be changed 16796 */ 16797 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)16798 void setFlags(int flags, int mask) { 16799 final boolean accessibilityEnabled = 16800 AccessibilityManager.getInstance(mContext).isEnabled(); 16801 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 16802 16803 int old = mViewFlags; 16804 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 16805 16806 int changed = mViewFlags ^ old; 16807 if (changed == 0) { 16808 return; 16809 } 16810 int privateFlags = mPrivateFlags; 16811 boolean shouldNotifyFocusableAvailable = false; 16812 16813 // If focusable is auto, update the FOCUSABLE bit. 16814 int focusableChangedByAuto = 0; 16815 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 16816 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 16817 // Heuristic only takes into account whether view is clickable. 16818 final int newFocus; 16819 if ((mViewFlags & CLICKABLE) != 0) { 16820 newFocus = FOCUSABLE; 16821 } else { 16822 newFocus = NOT_FOCUSABLE; 16823 } 16824 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 16825 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 16826 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 16827 } 16828 16829 /* Check if the FOCUSABLE bit has changed */ 16830 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 16831 if (((old & FOCUSABLE) == FOCUSABLE) 16832 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 16833 /* Give up focus if we are no longer focusable */ 16834 clearFocus(); 16835 if (mParent instanceof ViewGroup) { 16836 ((ViewGroup) mParent).clearFocusedInCluster(); 16837 } 16838 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 16839 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 16840 /* 16841 * Tell the view system that we are now available to take focus 16842 * if no one else already has it. 16843 */ 16844 if (mParent != null) { 16845 ViewRootImpl viewRootImpl = getViewRootImpl(); 16846 if (!sAutoFocusableOffUIThreadWontNotifyParents 16847 || focusableChangedByAuto == 0 16848 || viewRootImpl == null 16849 || viewRootImpl.mThread == Thread.currentThread()) { 16850 shouldNotifyFocusableAvailable = canTakeFocus(); 16851 } 16852 } 16853 } 16854 } 16855 16856 final int newVisibility = flags & VISIBILITY_MASK; 16857 if (newVisibility == VISIBLE) { 16858 if ((changed & VISIBILITY_MASK) != 0) { 16859 /* 16860 * If this view is becoming visible, invalidate it in case it changed while 16861 * it was not visible. Marking it drawn ensures that the invalidation will 16862 * go through. 16863 */ 16864 mPrivateFlags |= PFLAG_DRAWN; 16865 invalidate(true); 16866 16867 needGlobalAttributesUpdate(true); 16868 16869 // a view becoming visible is worth notifying the parent about in case nothing has 16870 // focus. Even if this specific view isn't focusable, it may contain something that 16871 // is, so let the root view try to give this focus if nothing else does. 16872 shouldNotifyFocusableAvailable = hasSize(); 16873 } 16874 } 16875 16876 if ((changed & ENABLED_MASK) != 0) { 16877 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 16878 // a view becoming enabled should notify the parent as long as the view is also 16879 // visible and the parent wasn't already notified by becoming visible during this 16880 // setFlags invocation. 16881 shouldNotifyFocusableAvailable = canTakeFocus(); 16882 } else { 16883 if (isFocused()) clearFocus(); 16884 } 16885 } 16886 16887 if (shouldNotifyFocusableAvailable && mParent != null) { 16888 mParent.focusableViewAvailable(this); 16889 } 16890 16891 /* Check if the GONE bit has changed */ 16892 if ((changed & GONE) != 0) { 16893 needGlobalAttributesUpdate(false); 16894 requestLayout(); 16895 16896 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 16897 if (hasFocus()) { 16898 clearFocus(); 16899 if (mParent instanceof ViewGroup) { 16900 ((ViewGroup) mParent).clearFocusedInCluster(); 16901 } 16902 } 16903 clearAccessibilityFocus(); 16904 destroyDrawingCache(); 16905 if (mParent instanceof View) { 16906 // GONE views noop invalidation, so invalidate the parent 16907 ((View) mParent).invalidate(true); 16908 } 16909 // Mark the view drawn to ensure that it gets invalidated properly the next 16910 // time it is visible and gets invalidated 16911 mPrivateFlags |= PFLAG_DRAWN; 16912 } 16913 if (mAttachInfo != null) { 16914 mAttachInfo.mViewVisibilityChanged = true; 16915 } 16916 } 16917 16918 /* Check if the VISIBLE bit has changed */ 16919 if ((changed & INVISIBLE) != 0) { 16920 needGlobalAttributesUpdate(false); 16921 /* 16922 * If this view is becoming invisible, set the DRAWN flag so that 16923 * the next invalidate() will not be skipped. 16924 */ 16925 mPrivateFlags |= PFLAG_DRAWN; 16926 16927 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 16928 // root view becoming invisible shouldn't clear focus and accessibility focus 16929 if (getRootView() != this) { 16930 if (hasFocus()) { 16931 clearFocus(); 16932 if (mParent instanceof ViewGroup) { 16933 ((ViewGroup) mParent).clearFocusedInCluster(); 16934 } 16935 } 16936 clearAccessibilityFocus(); 16937 } 16938 } 16939 if (mAttachInfo != null) { 16940 mAttachInfo.mViewVisibilityChanged = true; 16941 } 16942 } 16943 16944 if ((changed & VISIBILITY_MASK) != 0) { 16945 // If the view is invisible, cleanup its display list to free up resources 16946 if (newVisibility != VISIBLE && mAttachInfo != null) { 16947 cleanupDraw(); 16948 } 16949 16950 if (mParent instanceof ViewGroup) { 16951 ViewGroup parent = (ViewGroup) mParent; 16952 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 16953 newVisibility); 16954 parent.invalidate(true); 16955 } else if (mParent != null) { 16956 mParent.invalidateChild(this, null); 16957 } 16958 16959 if (mAttachInfo != null) { 16960 dispatchVisibilityChanged(this, newVisibility); 16961 16962 // Aggregated visibility changes are dispatched to attached views 16963 // in visible windows where the parent is currently shown/drawn 16964 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 16965 // discounting clipping or overlapping. This makes it a good place 16966 // to change animation states. 16967 if (mParent != null && getWindowVisibility() == VISIBLE && 16968 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 16969 dispatchVisibilityAggregated(newVisibility == VISIBLE); 16970 } 16971 // If this view is invisible from visible, then sending the A11y event by its 16972 // parent which is shown and has the accessibility important. 16973 if ((old & VISIBILITY_MASK) == VISIBLE) { 16974 notifySubtreeAccessibilityStateChangedByParentIfNeeded(); 16975 } else { 16976 notifySubtreeAccessibilityStateChangedIfNeeded(); 16977 } 16978 } 16979 } 16980 16981 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 16982 destroyDrawingCache(); 16983 } 16984 16985 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 16986 destroyDrawingCache(); 16987 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16988 invalidateParentCaches(); 16989 } 16990 16991 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 16992 destroyDrawingCache(); 16993 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16994 } 16995 16996 if ((changed & DRAW_MASK) != 0) { 16997 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 16998 if (mBackground != null 16999 || mDefaultFocusHighlight != null 17000 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 17001 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 17002 } else { 17003 mPrivateFlags |= PFLAG_SKIP_DRAW; 17004 } 17005 } else { 17006 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 17007 } 17008 requestLayout(); 17009 invalidate(true); 17010 } 17011 17012 if ((changed & KEEP_SCREEN_ON) != 0) { 17013 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 17014 mParent.recomputeViewAttributes(this); 17015 } 17016 } 17017 17018 if (accessibilityEnabled) { 17019 // If we're an accessibility pane and the visibility changed, we already have sent 17020 // a state change, so we really don't need to report other changes. 17021 if (isAccessibilityPane()) { 17022 changed &= ~VISIBILITY_MASK; 17023 } 17024 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 17025 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 17026 || (changed & CONTEXT_CLICKABLE) != 0) { 17027 if (oldIncludeForAccessibility != includeForAccessibility()) { 17028 notifySubtreeAccessibilityStateChangedIfNeeded(); 17029 } else { 17030 notifyViewAccessibilityStateChangedIfNeeded( 17031 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 17032 } 17033 } else if ((changed & ENABLED_MASK) != 0) { 17034 notifyViewAccessibilityStateChangedIfNeeded( 17035 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 17036 } 17037 } 17038 } 17039 17040 /** 17041 * Change the view's z order in the tree, so it's on top of other sibling 17042 * views. This ordering change may affect layout, if the parent container 17043 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 17044 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 17045 * method should be followed by calls to {@link #requestLayout()} and 17046 * {@link View#invalidate()} on the view's parent to force the parent to redraw 17047 * with the new child ordering. 17048 * 17049 * @see ViewGroup#bringChildToFront(View) 17050 */ bringToFront()17051 public void bringToFront() { 17052 if (mParent != null) { 17053 mParent.bringChildToFront(this); 17054 } 17055 } 17056 17057 /** 17058 * This is called in response to an internal scroll in this view (i.e., the 17059 * view scrolled its own contents). This is typically as a result of 17060 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 17061 * called. 17062 * 17063 * @param l Current horizontal scroll origin. 17064 * @param t Current vertical scroll origin. 17065 * @param oldl Previous horizontal scroll origin. 17066 * @param oldt Previous vertical scroll origin. 17067 */ onScrollChanged(int l, int t, int oldl, int oldt)17068 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 17069 notifySubtreeAccessibilityStateChangedIfNeeded(); 17070 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 17071 17072 mBackgroundSizeChanged = true; 17073 mDefaultFocusHighlightSizeChanged = true; 17074 if (mForegroundInfo != null) { 17075 mForegroundInfo.mBoundsChanged = true; 17076 } 17077 17078 final AttachInfo ai = mAttachInfo; 17079 if (ai != null) { 17080 ai.mViewScrollChanged = true; 17081 } 17082 17083 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 17084 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 17085 } 17086 } 17087 17088 /** 17089 * Interface definition for a callback to be invoked when the scroll 17090 * X or Y positions of a view change. 17091 * <p> 17092 * <b>Note:</b> Some views handle scrolling independently from View and may 17093 * have their own separate listeners for scroll-type events. For example, 17094 * {@link android.widget.ListView ListView} allows clients to register an 17095 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 17096 * to listen for changes in list scroll position. 17097 * 17098 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 17099 */ 17100 public interface OnScrollChangeListener { 17101 /** 17102 * Called when the scroll position of a view changes. 17103 * 17104 * @param v The view whose scroll position has changed. 17105 * @param scrollX Current horizontal scroll origin. 17106 * @param scrollY Current vertical scroll origin. 17107 * @param oldScrollX Previous horizontal scroll origin. 17108 * @param oldScrollY Previous vertical scroll origin. 17109 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)17110 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 17111 } 17112 17113 /** 17114 * Interface definition for a callback to be invoked when the layout bounds of a view 17115 * changes due to layout processing. 17116 */ 17117 public interface OnLayoutChangeListener { 17118 /** 17119 * Called when the layout bounds of a view changes due to layout processing. 17120 * 17121 * @param v The view whose bounds have changed. 17122 * @param left The new value of the view's left property. 17123 * @param top The new value of the view's top property. 17124 * @param right The new value of the view's right property. 17125 * @param bottom The new value of the view's bottom property. 17126 * @param oldLeft The previous value of the view's left property. 17127 * @param oldTop The previous value of the view's top property. 17128 * @param oldRight The previous value of the view's right property. 17129 * @param oldBottom The previous value of the view's bottom property. 17130 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)17131 void onLayoutChange(View v, int left, int top, int right, int bottom, 17132 int oldLeft, int oldTop, int oldRight, int oldBottom); 17133 } 17134 17135 /** 17136 * This is called during layout when the size of this view has changed. If 17137 * you were just added to the view hierarchy, you're called with the old 17138 * values of 0. 17139 * 17140 * @param w Current width of this view. 17141 * @param h Current height of this view. 17142 * @param oldw Old width of this view. 17143 * @param oldh Old height of this view. 17144 */ onSizeChanged(int w, int h, int oldw, int oldh)17145 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 17146 } 17147 17148 /** 17149 * Called by draw to draw the child views. This may be overridden 17150 * by derived classes to gain control just before its children are drawn 17151 * (but after its own view has been drawn). 17152 * @param canvas the canvas on which to draw the view 17153 */ dispatchDraw(Canvas canvas)17154 protected void dispatchDraw(Canvas canvas) { 17155 17156 } 17157 17158 /** 17159 * Gets the parent of this view. Note that the parent is a 17160 * ViewParent and not necessarily a View. 17161 * 17162 * @return Parent of this view. 17163 */ getParent()17164 public final ViewParent getParent() { 17165 return mParent; 17166 } 17167 17168 /** 17169 * Set the horizontal scrolled position of your view. This will cause a call to 17170 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17171 * invalidated. 17172 * @param value the x position to scroll to 17173 */ setScrollX(int value)17174 public void setScrollX(int value) { 17175 scrollTo(value, mScrollY); 17176 } 17177 17178 /** 17179 * Set the vertical scrolled position of your view. This will cause a call to 17180 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17181 * invalidated. 17182 * @param value the y position to scroll to 17183 */ setScrollY(int value)17184 public void setScrollY(int value) { 17185 scrollTo(mScrollX, value); 17186 } 17187 17188 /** 17189 * Return the scrolled left position of this view. This is the left edge of 17190 * the displayed part of your view. You do not need to draw any pixels 17191 * farther left, since those are outside of the frame of your view on 17192 * screen. 17193 * 17194 * @return The left edge of the displayed part of your view, in pixels. 17195 */ 17196 @InspectableProperty getScrollX()17197 public final int getScrollX() { 17198 return mScrollX; 17199 } 17200 17201 /** 17202 * Return the scrolled top position of this view. This is the top edge of 17203 * the displayed part of your view. You do not need to draw any pixels above 17204 * it, since those are outside of the frame of your view on screen. 17205 * 17206 * @return The top edge of the displayed part of your view, in pixels. 17207 */ 17208 @InspectableProperty getScrollY()17209 public final int getScrollY() { 17210 return mScrollY; 17211 } 17212 17213 /** 17214 * Return the width of your view. 17215 * 17216 * @return The width of your view, in pixels. 17217 */ 17218 @ViewDebug.ExportedProperty(category = "layout") getWidth()17219 public final int getWidth() { 17220 return mRight - mLeft; 17221 } 17222 17223 /** 17224 * Return the height of your view. 17225 * 17226 * @return The height of your view, in pixels. 17227 */ 17228 @ViewDebug.ExportedProperty(category = "layout") getHeight()17229 public final int getHeight() { 17230 return mBottom - mTop; 17231 } 17232 17233 /** 17234 * Return the visible drawing bounds of your view. Fills in the output 17235 * rectangle with the values from getScrollX(), getScrollY(), 17236 * getWidth(), and getHeight(). These bounds do not account for any 17237 * transformation properties currently set on the view, such as 17238 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 17239 * 17240 * @param outRect The (scrolled) drawing bounds of the view. 17241 */ getDrawingRect(Rect outRect)17242 public void getDrawingRect(Rect outRect) { 17243 outRect.left = mScrollX; 17244 outRect.top = mScrollY; 17245 outRect.right = mScrollX + (mRight - mLeft); 17246 outRect.bottom = mScrollY + (mBottom - mTop); 17247 } 17248 17249 /** 17250 * Like {@link #getMeasuredWidthAndState()}, but only returns the 17251 * raw width component (that is the result is masked by 17252 * {@link #MEASURED_SIZE_MASK}). 17253 * 17254 * @return The raw measured width of this view. 17255 */ getMeasuredWidth()17256 public final int getMeasuredWidth() { 17257 return mMeasuredWidth & MEASURED_SIZE_MASK; 17258 } 17259 17260 /** 17261 * Return the full width measurement information for this view as computed 17262 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 17263 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 17264 * This should be used during measurement and layout calculations only. Use 17265 * {@link #getWidth()} to see how wide a view is after layout. 17266 * 17267 * @return The measured width of this view as a bit mask. 17268 */ 17269 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 17270 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 17271 name = "MEASURED_STATE_TOO_SMALL"), 17272 }) getMeasuredWidthAndState()17273 public final int getMeasuredWidthAndState() { 17274 return mMeasuredWidth; 17275 } 17276 17277 /** 17278 * Like {@link #getMeasuredHeightAndState()}, but only returns the 17279 * raw height component (that is the result is masked by 17280 * {@link #MEASURED_SIZE_MASK}). 17281 * 17282 * @return The raw measured height of this view. 17283 */ getMeasuredHeight()17284 public final int getMeasuredHeight() { 17285 return mMeasuredHeight & MEASURED_SIZE_MASK; 17286 } 17287 17288 /** 17289 * Return the full height measurement information for this view as computed 17290 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 17291 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 17292 * This should be used during measurement and layout calculations only. Use 17293 * {@link #getHeight()} to see how high a view is after layout. 17294 * 17295 * @return The measured height of this view as a bit mask. 17296 */ 17297 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 17298 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 17299 name = "MEASURED_STATE_TOO_SMALL"), 17300 }) getMeasuredHeightAndState()17301 public final int getMeasuredHeightAndState() { 17302 return mMeasuredHeight; 17303 } 17304 17305 /** 17306 * Return only the state bits of {@link #getMeasuredWidthAndState()} 17307 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 17308 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 17309 * and the height component is at the shifted bits 17310 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 17311 */ getMeasuredState()17312 public final int getMeasuredState() { 17313 return (mMeasuredWidth&MEASURED_STATE_MASK) 17314 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 17315 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 17316 } 17317 17318 /** 17319 * The transform matrix of this view, which is calculated based on the current 17320 * rotation, scale, and pivot properties. 17321 * 17322 * @see #getRotation() 17323 * @see #getScaleX() 17324 * @see #getScaleY() 17325 * @see #getPivotX() 17326 * @see #getPivotY() 17327 * @return The current transform matrix for the view 17328 */ getMatrix()17329 public Matrix getMatrix() { 17330 ensureTransformationInfo(); 17331 final Matrix matrix = mTransformationInfo.mMatrix; 17332 mRenderNode.getMatrix(matrix); 17333 return matrix; 17334 } 17335 17336 /** 17337 * Returns true if the transform matrix is the identity matrix. 17338 * Recomputes the matrix if necessary. 17339 * 17340 * @return True if the transform matrix is the identity matrix, false otherwise. 17341 * @hide 17342 */ 17343 @UnsupportedAppUsage hasIdentityMatrix()17344 public final boolean hasIdentityMatrix() { 17345 return mRenderNode.hasIdentityMatrix(); 17346 } 17347 17348 @UnsupportedAppUsage ensureTransformationInfo()17349 void ensureTransformationInfo() { 17350 if (mTransformationInfo == null) { 17351 mTransformationInfo = new TransformationInfo(); 17352 } 17353 } 17354 17355 /** 17356 * Utility method to retrieve the inverse of the current mMatrix property. 17357 * We cache the matrix to avoid recalculating it when transform properties 17358 * have not changed. 17359 * 17360 * @return The inverse of the current matrix of this view. 17361 * @hide 17362 */ 17363 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getInverseMatrix()17364 public final Matrix getInverseMatrix() { 17365 ensureTransformationInfo(); 17366 if (mTransformationInfo.mInverseMatrix == null) { 17367 mTransformationInfo.mInverseMatrix = new Matrix(); 17368 } 17369 final Matrix matrix = mTransformationInfo.mInverseMatrix; 17370 mRenderNode.getInverseMatrix(matrix); 17371 return matrix; 17372 } 17373 17374 /** 17375 * Gets the distance along the Z axis from the camera to this view. 17376 * 17377 * @see #setCameraDistance(float) 17378 * 17379 * @return The distance along the Z axis. 17380 */ getCameraDistance()17381 public float getCameraDistance() { 17382 final float dpi = mResources.getDisplayMetrics().densityDpi; 17383 return mRenderNode.getCameraDistance() * dpi; 17384 } 17385 17386 /** 17387 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 17388 * views are drawn) from the camera to this view. The camera's distance 17389 * affects 3D transformations, for instance rotations around the X and Y 17390 * axis. If the rotationX or rotationY properties are changed and this view is 17391 * large (more than half the size of the screen), it is recommended to always 17392 * use a camera distance that's greater than the height (X axis rotation) or 17393 * the width (Y axis rotation) of this view.</p> 17394 * 17395 * <p>The distance of the camera from the view plane can have an affect on the 17396 * perspective distortion of the view when it is rotated around the x or y axis. 17397 * For example, a large distance will result in a large viewing angle, and there 17398 * will not be much perspective distortion of the view as it rotates. A short 17399 * distance may cause much more perspective distortion upon rotation, and can 17400 * also result in some drawing artifacts if the rotated view ends up partially 17401 * behind the camera (which is why the recommendation is to use a distance at 17402 * least as far as the size of the view, if the view is to be rotated.)</p> 17403 * 17404 * <p>The distance is expressed in "depth pixels." The default distance depends 17405 * on the screen density. For instance, on a medium density display, the 17406 * default distance is 1280. On a high density display, the default distance 17407 * is 1920.</p> 17408 * 17409 * <p>If you want to specify a distance that leads to visually consistent 17410 * results across various densities, use the following formula:</p> 17411 * <pre> 17412 * float scale = context.getResources().getDisplayMetrics().density; 17413 * view.setCameraDistance(distance * scale); 17414 * </pre> 17415 * 17416 * <p>The density scale factor of a high density display is 1.5, 17417 * and 1920 = 1280 * 1.5.</p> 17418 * 17419 * @param distance The distance in "depth pixels", if negative the opposite 17420 * value is used 17421 * 17422 * @see #setRotationX(float) 17423 * @see #setRotationY(float) 17424 */ setCameraDistance(float distance)17425 public void setCameraDistance(float distance) { 17426 final float dpi = mResources.getDisplayMetrics().densityDpi; 17427 17428 invalidateViewProperty(true, false); 17429 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 17430 invalidateViewProperty(false, false); 17431 17432 invalidateParentIfNeededAndWasQuickRejected(); 17433 } 17434 17435 /** 17436 * The degrees that the view is rotated around the pivot point. 17437 * 17438 * @see #setRotation(float) 17439 * @see #getPivotX() 17440 * @see #getPivotY() 17441 * 17442 * @return The degrees of rotation. 17443 */ 17444 @ViewDebug.ExportedProperty(category = "drawing") 17445 @InspectableProperty getRotation()17446 public float getRotation() { 17447 return mRenderNode.getRotationZ(); 17448 } 17449 17450 /** 17451 * Sets the degrees that the view is rotated around the pivot point. Increasing values 17452 * result in clockwise rotation. 17453 * 17454 * @param rotation The degrees of rotation. 17455 * 17456 * @see #getRotation() 17457 * @see #getPivotX() 17458 * @see #getPivotY() 17459 * @see #setRotationX(float) 17460 * @see #setRotationY(float) 17461 * 17462 * @attr ref android.R.styleable#View_rotation 17463 */ 17464 @RemotableViewMethod setRotation(float rotation)17465 public void setRotation(float rotation) { 17466 if (rotation != getRotation()) { 17467 // Double-invalidation is necessary to capture view's old and new areas 17468 invalidateViewProperty(true, false); 17469 mRenderNode.setRotationZ(rotation); 17470 invalidateViewProperty(false, true); 17471 17472 invalidateParentIfNeededAndWasQuickRejected(); 17473 notifySubtreeAccessibilityStateChangedIfNeeded(); 17474 } 17475 } 17476 17477 /** 17478 * The degrees that the view is rotated around the vertical axis through the pivot point. 17479 * 17480 * @see #getPivotX() 17481 * @see #getPivotY() 17482 * @see #setRotationY(float) 17483 * 17484 * @return The degrees of Y rotation. 17485 */ 17486 @ViewDebug.ExportedProperty(category = "drawing") 17487 @InspectableProperty getRotationY()17488 public float getRotationY() { 17489 return mRenderNode.getRotationY(); 17490 } 17491 17492 /** 17493 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 17494 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 17495 * down the y axis. 17496 * 17497 * When rotating large views, it is recommended to adjust the camera distance 17498 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 17499 * 17500 * @param rotationY The degrees of Y rotation. 17501 * 17502 * @see #getRotationY() 17503 * @see #getPivotX() 17504 * @see #getPivotY() 17505 * @see #setRotation(float) 17506 * @see #setRotationX(float) 17507 * @see #setCameraDistance(float) 17508 * 17509 * @attr ref android.R.styleable#View_rotationY 17510 */ 17511 @RemotableViewMethod setRotationY(float rotationY)17512 public void setRotationY(float rotationY) { 17513 if (rotationY != getRotationY()) { 17514 invalidateViewProperty(true, false); 17515 mRenderNode.setRotationY(rotationY); 17516 invalidateViewProperty(false, true); 17517 17518 invalidateParentIfNeededAndWasQuickRejected(); 17519 notifySubtreeAccessibilityStateChangedIfNeeded(); 17520 } 17521 } 17522 17523 /** 17524 * The degrees that the view is rotated around the horizontal axis through the pivot point. 17525 * 17526 * @see #getPivotX() 17527 * @see #getPivotY() 17528 * @see #setRotationX(float) 17529 * 17530 * @return The degrees of X rotation. 17531 */ 17532 @ViewDebug.ExportedProperty(category = "drawing") 17533 @InspectableProperty getRotationX()17534 public float getRotationX() { 17535 return mRenderNode.getRotationX(); 17536 } 17537 17538 /** 17539 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 17540 * Increasing values result in clockwise rotation from the viewpoint of looking down the 17541 * x axis. 17542 * 17543 * When rotating large views, it is recommended to adjust the camera distance 17544 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 17545 * 17546 * @param rotationX The degrees of X rotation. 17547 * 17548 * @see #getRotationX() 17549 * @see #getPivotX() 17550 * @see #getPivotY() 17551 * @see #setRotation(float) 17552 * @see #setRotationY(float) 17553 * @see #setCameraDistance(float) 17554 * 17555 * @attr ref android.R.styleable#View_rotationX 17556 */ 17557 @RemotableViewMethod setRotationX(float rotationX)17558 public void setRotationX(float rotationX) { 17559 if (rotationX != getRotationX()) { 17560 invalidateViewProperty(true, false); 17561 mRenderNode.setRotationX(rotationX); 17562 invalidateViewProperty(false, true); 17563 17564 invalidateParentIfNeededAndWasQuickRejected(); 17565 notifySubtreeAccessibilityStateChangedIfNeeded(); 17566 } 17567 } 17568 17569 /** 17570 * The amount that the view is scaled in x around the pivot point, as a proportion of 17571 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 17572 * 17573 * <p>By default, this is 1.0f. 17574 * 17575 * @see #getPivotX() 17576 * @see #getPivotY() 17577 * @return The scaling factor. 17578 */ 17579 @ViewDebug.ExportedProperty(category = "drawing") 17580 @InspectableProperty getScaleX()17581 public float getScaleX() { 17582 return mRenderNode.getScaleX(); 17583 } 17584 17585 /** 17586 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 17587 * the view's unscaled width. A value of 1 means that no scaling is applied. 17588 * 17589 * @param scaleX The scaling factor. 17590 * @see #getPivotX() 17591 * @see #getPivotY() 17592 * 17593 * @attr ref android.R.styleable#View_scaleX 17594 */ 17595 @RemotableViewMethod setScaleX(float scaleX)17596 public void setScaleX(float scaleX) { 17597 if (scaleX != getScaleX()) { 17598 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 17599 invalidateViewProperty(true, false); 17600 mRenderNode.setScaleX(scaleX); 17601 invalidateViewProperty(false, true); 17602 17603 invalidateParentIfNeededAndWasQuickRejected(); 17604 notifySubtreeAccessibilityStateChangedIfNeeded(); 17605 } 17606 } 17607 17608 /** 17609 * The amount that the view is scaled in y around the pivot point, as a proportion of 17610 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 17611 * 17612 * <p>By default, this is 1.0f. 17613 * 17614 * @see #getPivotX() 17615 * @see #getPivotY() 17616 * @return The scaling factor. 17617 */ 17618 @ViewDebug.ExportedProperty(category = "drawing") 17619 @InspectableProperty getScaleY()17620 public float getScaleY() { 17621 return mRenderNode.getScaleY(); 17622 } 17623 17624 /** 17625 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 17626 * the view's unscaled width. A value of 1 means that no scaling is applied. 17627 * 17628 * @param scaleY The scaling factor. 17629 * @see #getPivotX() 17630 * @see #getPivotY() 17631 * 17632 * @attr ref android.R.styleable#View_scaleY 17633 */ 17634 @RemotableViewMethod setScaleY(float scaleY)17635 public void setScaleY(float scaleY) { 17636 if (scaleY != getScaleY()) { 17637 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 17638 invalidateViewProperty(true, false); 17639 mRenderNode.setScaleY(scaleY); 17640 invalidateViewProperty(false, true); 17641 17642 invalidateParentIfNeededAndWasQuickRejected(); 17643 notifySubtreeAccessibilityStateChangedIfNeeded(); 17644 } 17645 } 17646 17647 /** 17648 * The x location of the point around which the view is {@link #setRotation(float) rotated} 17649 * and {@link #setScaleX(float) scaled}. 17650 * 17651 * @see #getRotation() 17652 * @see #getScaleX() 17653 * @see #getScaleY() 17654 * @see #getPivotY() 17655 * @return The x location of the pivot point. 17656 * 17657 * @attr ref android.R.styleable#View_transformPivotX 17658 */ 17659 @ViewDebug.ExportedProperty(category = "drawing") 17660 @InspectableProperty(name = "transformPivotX") getPivotX()17661 public float getPivotX() { 17662 return mRenderNode.getPivotX(); 17663 } 17664 17665 /** 17666 * Sets the x location of the point around which the view is 17667 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 17668 * By default, the pivot point is centered on the object. 17669 * Setting this property disables this behavior and causes the view to use only the 17670 * explicitly set pivotX and pivotY values. 17671 * 17672 * @param pivotX The x location of the pivot point. 17673 * @see #getRotation() 17674 * @see #getScaleX() 17675 * @see #getScaleY() 17676 * @see #getPivotY() 17677 * 17678 * @attr ref android.R.styleable#View_transformPivotX 17679 */ 17680 @RemotableViewMethod setPivotX(float pivotX)17681 public void setPivotX(float pivotX) { 17682 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 17683 invalidateViewProperty(true, false); 17684 mRenderNode.setPivotX(pivotX); 17685 invalidateViewProperty(false, true); 17686 17687 invalidateParentIfNeededAndWasQuickRejected(); 17688 } 17689 } 17690 17691 /** 17692 * The y location of the point around which the view is {@link #setRotation(float) rotated} 17693 * and {@link #setScaleY(float) scaled}. 17694 * 17695 * @see #getRotation() 17696 * @see #getScaleX() 17697 * @see #getScaleY() 17698 * @see #getPivotY() 17699 * @return The y location of the pivot point. 17700 * 17701 * @attr ref android.R.styleable#View_transformPivotY 17702 */ 17703 @ViewDebug.ExportedProperty(category = "drawing") 17704 @InspectableProperty(name = "transformPivotY") getPivotY()17705 public float getPivotY() { 17706 return mRenderNode.getPivotY(); 17707 } 17708 17709 /** 17710 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 17711 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 17712 * Setting this property disables this behavior and causes the view to use only the 17713 * explicitly set pivotX and pivotY values. 17714 * 17715 * @param pivotY The y location of the pivot point. 17716 * @see #getRotation() 17717 * @see #getScaleX() 17718 * @see #getScaleY() 17719 * @see #getPivotY() 17720 * 17721 * @attr ref android.R.styleable#View_transformPivotY 17722 */ 17723 @RemotableViewMethod setPivotY(float pivotY)17724 public void setPivotY(float pivotY) { 17725 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 17726 invalidateViewProperty(true, false); 17727 mRenderNode.setPivotY(pivotY); 17728 invalidateViewProperty(false, true); 17729 17730 invalidateParentIfNeededAndWasQuickRejected(); 17731 } 17732 } 17733 17734 /** 17735 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 17736 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 17737 * of the view. 17738 * 17739 * @return True if a pivot has been set, false if the default pivot is being used 17740 */ isPivotSet()17741 public boolean isPivotSet() { 17742 return mRenderNode.isPivotExplicitlySet(); 17743 } 17744 17745 /** 17746 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 17747 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 17748 * and the pivot used for rotation will return to default of being centered on the view. 17749 */ resetPivot()17750 public void resetPivot() { 17751 if (mRenderNode.resetPivot()) { 17752 invalidateViewProperty(false, false); 17753 } 17754 } 17755 17756 /** 17757 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 17758 * completely transparent and 1 means the view is completely opaque. 17759 * 17760 * <p>By default this is 1.0f. 17761 * @return The opacity of the view. 17762 */ 17763 @ViewDebug.ExportedProperty(category = "drawing") 17764 @InspectableProperty getAlpha()17765 public float getAlpha() { 17766 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 17767 } 17768 17769 /** 17770 * Sets the behavior for overlapping rendering for this view (see {@link 17771 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 17772 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 17773 * providing the value which is then used internally. That is, when {@link 17774 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 17775 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 17776 * instead. 17777 * 17778 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 17779 * instead of that returned by {@link #hasOverlappingRendering()}. 17780 * 17781 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 17782 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)17783 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 17784 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 17785 if (hasOverlappingRendering) { 17786 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17787 } else { 17788 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17789 } 17790 } 17791 17792 /** 17793 * Returns the value for overlapping rendering that is used internally. This is either 17794 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 17795 * the return value of {@link #hasOverlappingRendering()}, otherwise. 17796 * 17797 * @return The value for overlapping rendering being used internally. 17798 */ getHasOverlappingRendering()17799 public final boolean getHasOverlappingRendering() { 17800 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 17801 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 17802 hasOverlappingRendering(); 17803 } 17804 17805 /** 17806 * Returns whether this View has content which overlaps. 17807 * 17808 * <p>This function, intended to be overridden by specific View types, is an optimization when 17809 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 17810 * an offscreen buffer and then composited into place, which can be expensive. If the view has 17811 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 17812 * directly. An example of overlapping rendering is a TextView with a background image, such as 17813 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 17814 * ImageView with only the foreground image. The default implementation returns true; subclasses 17815 * should override if they have cases which can be optimized.</p> 17816 * 17817 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 17818 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 17819 * 17820 * @return true if the content in this view might overlap, false otherwise. 17821 */ 17822 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()17823 public boolean hasOverlappingRendering() { 17824 return true; 17825 } 17826 17827 /** 17828 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 17829 * completely transparent and 1 means the view is completely opaque. 17830 * 17831 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 17832 * can have significant performance implications, especially for large views. It is best to use 17833 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 17834 * 17835 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 17836 * strongly recommended for performance reasons to either override 17837 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 17838 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 17839 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 17840 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 17841 * of rendering cost, even for simple or small views. Starting with 17842 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 17843 * applied to the view at the rendering level.</p> 17844 * 17845 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 17846 * responsible for applying the opacity itself.</p> 17847 * 17848 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 17849 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 17850 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 17851 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 17852 * 17853 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 17854 * value will clip a View to its bounds, unless the View returns <code>false</code> from 17855 * {@link #hasOverlappingRendering}.</p> 17856 * 17857 * @param alpha The opacity of the view. 17858 * 17859 * @see #hasOverlappingRendering() 17860 * @see #setLayerType(int, android.graphics.Paint) 17861 * 17862 * @attr ref android.R.styleable#View_alpha 17863 */ 17864 @RemotableViewMethod setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)17865 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 17866 ensureTransformationInfo(); 17867 if (mTransformationInfo.mAlpha != alpha) { 17868 setAlphaInternal(alpha); 17869 if (onSetAlpha((int) (alpha * 255))) { 17870 mPrivateFlags |= PFLAG_ALPHA_SET; 17871 // subclass is handling alpha - don't optimize rendering cache invalidation 17872 invalidateParentCaches(); 17873 invalidate(true); 17874 } else { 17875 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17876 invalidateViewProperty(true, false); 17877 mRenderNode.setAlpha(getFinalAlpha()); 17878 } 17879 } 17880 } 17881 17882 /** 17883 * Faster version of setAlpha() which performs the same steps except there are 17884 * no calls to invalidate(). The caller of this function should perform proper invalidation 17885 * on the parent and this object. The return value indicates whether the subclass handles 17886 * alpha (the return value for onSetAlpha()). 17887 * 17888 * @param alpha The new value for the alpha property 17889 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 17890 * the new value for the alpha property is different from the old value 17891 */ 17892 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)17893 boolean setAlphaNoInvalidation(float alpha) { 17894 ensureTransformationInfo(); 17895 if (mTransformationInfo.mAlpha != alpha) { 17896 setAlphaInternal(alpha); 17897 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 17898 if (subclassHandlesAlpha) { 17899 mPrivateFlags |= PFLAG_ALPHA_SET; 17900 return true; 17901 } else { 17902 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17903 mRenderNode.setAlpha(getFinalAlpha()); 17904 } 17905 } 17906 return false; 17907 } 17908 setAlphaInternal(float alpha)17909 void setAlphaInternal(float alpha) { 17910 float oldAlpha = mTransformationInfo.mAlpha; 17911 mTransformationInfo.mAlpha = alpha; 17912 // Report visibility changes, which can affect children, to accessibility 17913 if ((alpha == 0) ^ (oldAlpha == 0)) { 17914 notifySubtreeAccessibilityStateChangedIfNeeded(); 17915 } 17916 } 17917 17918 /** 17919 * This property is intended only for use by the Fade transition, which animates it 17920 * to produce a visual translucency that does not side-effect (or get affected by) 17921 * the real alpha property. This value is composited with the other alpha value 17922 * (and the AlphaAnimation value, when that is present) to produce a final visual 17923 * translucency result, which is what is passed into the DisplayList. 17924 */ setTransitionAlpha(float alpha)17925 public void setTransitionAlpha(float alpha) { 17926 ensureTransformationInfo(); 17927 if (mTransformationInfo.mTransitionAlpha != alpha) { 17928 mTransformationInfo.mTransitionAlpha = alpha; 17929 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17930 invalidateViewProperty(true, false); 17931 mRenderNode.setAlpha(getFinalAlpha()); 17932 } 17933 } 17934 17935 /** 17936 * Calculates the visual alpha of this view, which is a combination of the actual 17937 * alpha value and the transitionAlpha value (if set). 17938 */ getFinalAlpha()17939 private float getFinalAlpha() { 17940 if (mTransformationInfo != null) { 17941 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 17942 } 17943 return 1; 17944 } 17945 17946 /** 17947 * This property is intended only for use by the Fade transition, which animates 17948 * it to produce a visual translucency that does not side-effect (or get affected 17949 * by) the real alpha property. This value is composited with the other alpha 17950 * value (and the AlphaAnimation value, when that is present) to produce a final 17951 * visual translucency result, which is what is passed into the DisplayList. 17952 */ 17953 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()17954 public float getTransitionAlpha() { 17955 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 17956 } 17957 17958 /** 17959 * Sets whether or not to allow force dark to apply to this view. 17960 * 17961 * Setting this to false will disable the auto-dark feature on everything this view 17962 * draws, including any descendants. 17963 * 17964 * Setting this to true will allow this view to be automatically made dark, however 17965 * a value of 'true' will not override any 'false' value in its parent chain nor will 17966 * it prevent any 'false' in any of its children. 17967 * 17968 * The default behavior of force dark is also influenced by the Theme's 17969 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 17970 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 17971 * 17972 * @param allow Whether or not to allow force dark. 17973 */ setForceDarkAllowed(boolean allow)17974 public void setForceDarkAllowed(boolean allow) { 17975 if (mRenderNode.setForceDarkAllowed(allow)) { 17976 // Currently toggling force-dark requires a new display list push to apply 17977 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 17978 invalidate(); 17979 } 17980 } 17981 17982 /** 17983 * See {@link #setForceDarkAllowed(boolean)} 17984 * 17985 * @return true if force dark is allowed (default), false if it is disabled 17986 */ 17987 @ViewDebug.ExportedProperty(category = "drawing") 17988 @InspectableProperty isForceDarkAllowed()17989 public boolean isForceDarkAllowed() { 17990 return mRenderNode.isForceDarkAllowed(); 17991 } 17992 17993 /** 17994 * Top position of this view relative to its parent. 17995 * 17996 * @return The top of this view, in pixels. 17997 */ 17998 @ViewDebug.CapturedViewProperty getTop()17999 public final int getTop() { 18000 return mTop; 18001 } 18002 18003 /** 18004 * Sets the top position of this view relative to its parent. This method is meant to be called 18005 * by the layout system and should not generally be called otherwise, because the property 18006 * may be changed at any time by the layout. 18007 * 18008 * @param top The top of this view, in pixels. 18009 */ setTop(int top)18010 public final void setTop(int top) { 18011 if (top != mTop) { 18012 final boolean matrixIsIdentity = hasIdentityMatrix(); 18013 if (matrixIsIdentity) { 18014 if (mAttachInfo != null) { 18015 int minTop; 18016 int yLoc; 18017 if (top < mTop) { 18018 minTop = top; 18019 yLoc = top - mTop; 18020 } else { 18021 minTop = mTop; 18022 yLoc = 0; 18023 } 18024 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 18025 } 18026 } else { 18027 // Double-invalidation is necessary to capture view's old and new areas 18028 invalidate(true); 18029 } 18030 18031 int width = mRight - mLeft; 18032 int oldHeight = mBottom - mTop; 18033 18034 mTop = top; 18035 mRenderNode.setTop(mTop); 18036 18037 sizeChange(width, mBottom - mTop, width, oldHeight); 18038 18039 if (!matrixIsIdentity) { 18040 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18041 invalidate(true); 18042 } 18043 mBackgroundSizeChanged = true; 18044 mDefaultFocusHighlightSizeChanged = true; 18045 if (mForegroundInfo != null) { 18046 mForegroundInfo.mBoundsChanged = true; 18047 } 18048 invalidateParentIfNeeded(); 18049 } 18050 } 18051 18052 /** 18053 * Bottom position of this view relative to its parent. 18054 * 18055 * @return The bottom of this view, in pixels. 18056 */ 18057 @ViewDebug.CapturedViewProperty getBottom()18058 public final int getBottom() { 18059 return mBottom; 18060 } 18061 18062 /** 18063 * True if this view has changed since the last time being drawn. 18064 * 18065 * @return The dirty state of this view. 18066 */ isDirty()18067 public boolean isDirty() { 18068 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 18069 } 18070 18071 /** 18072 * Sets the bottom position of this view relative to its parent. This method is meant to be 18073 * called by the layout system and should not generally be called otherwise, because the 18074 * property may be changed at any time by the layout. 18075 * 18076 * @param bottom The bottom of this view, in pixels. 18077 */ setBottom(int bottom)18078 public final void setBottom(int bottom) { 18079 if (bottom != mBottom) { 18080 final boolean matrixIsIdentity = hasIdentityMatrix(); 18081 if (matrixIsIdentity) { 18082 if (mAttachInfo != null) { 18083 int maxBottom; 18084 if (bottom < mBottom) { 18085 maxBottom = mBottom; 18086 } else { 18087 maxBottom = bottom; 18088 } 18089 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 18090 } 18091 } else { 18092 // Double-invalidation is necessary to capture view's old and new areas 18093 invalidate(true); 18094 } 18095 18096 int width = mRight - mLeft; 18097 int oldHeight = mBottom - mTop; 18098 18099 mBottom = bottom; 18100 mRenderNode.setBottom(mBottom); 18101 18102 sizeChange(width, mBottom - mTop, width, oldHeight); 18103 18104 if (!matrixIsIdentity) { 18105 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18106 invalidate(true); 18107 } 18108 mBackgroundSizeChanged = true; 18109 mDefaultFocusHighlightSizeChanged = true; 18110 if (mForegroundInfo != null) { 18111 mForegroundInfo.mBoundsChanged = true; 18112 } 18113 invalidateParentIfNeeded(); 18114 } 18115 } 18116 18117 /** 18118 * Left position of this view relative to its parent. 18119 * 18120 * @return The left edge of this view, in pixels. 18121 */ 18122 @ViewDebug.CapturedViewProperty getLeft()18123 public final int getLeft() { 18124 return mLeft; 18125 } 18126 18127 /** 18128 * Sets the left position of this view relative to its parent. This method is meant to be called 18129 * by the layout system and should not generally be called otherwise, because the property 18130 * may be changed at any time by the layout. 18131 * 18132 * @param left The left of this view, in pixels. 18133 */ setLeft(int left)18134 public final void setLeft(int left) { 18135 if (left != mLeft) { 18136 final boolean matrixIsIdentity = hasIdentityMatrix(); 18137 if (matrixIsIdentity) { 18138 if (mAttachInfo != null) { 18139 int minLeft; 18140 int xLoc; 18141 if (left < mLeft) { 18142 minLeft = left; 18143 xLoc = left - mLeft; 18144 } else { 18145 minLeft = mLeft; 18146 xLoc = 0; 18147 } 18148 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 18149 } 18150 } else { 18151 // Double-invalidation is necessary to capture view's old and new areas 18152 invalidate(true); 18153 } 18154 18155 int oldWidth = mRight - mLeft; 18156 int height = mBottom - mTop; 18157 18158 mLeft = left; 18159 mRenderNode.setLeft(left); 18160 18161 sizeChange(mRight - mLeft, height, oldWidth, height); 18162 18163 if (!matrixIsIdentity) { 18164 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18165 invalidate(true); 18166 } 18167 mBackgroundSizeChanged = true; 18168 mDefaultFocusHighlightSizeChanged = true; 18169 if (mForegroundInfo != null) { 18170 mForegroundInfo.mBoundsChanged = true; 18171 } 18172 invalidateParentIfNeeded(); 18173 } 18174 } 18175 18176 /** 18177 * Right position of this view relative to its parent. 18178 * 18179 * @return The right edge of this view, in pixels. 18180 */ 18181 @ViewDebug.CapturedViewProperty getRight()18182 public final int getRight() { 18183 return mRight; 18184 } 18185 18186 /** 18187 * Sets the right position of this view relative to its parent. This method is meant to be called 18188 * by the layout system and should not generally be called otherwise, because the property 18189 * may be changed at any time by the layout. 18190 * 18191 * @param right The right of this view, in pixels. 18192 */ setRight(int right)18193 public final void setRight(int right) { 18194 if (right != mRight) { 18195 final boolean matrixIsIdentity = hasIdentityMatrix(); 18196 if (matrixIsIdentity) { 18197 if (mAttachInfo != null) { 18198 int maxRight; 18199 if (right < mRight) { 18200 maxRight = mRight; 18201 } else { 18202 maxRight = right; 18203 } 18204 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 18205 } 18206 } else { 18207 // Double-invalidation is necessary to capture view's old and new areas 18208 invalidate(true); 18209 } 18210 18211 int oldWidth = mRight - mLeft; 18212 int height = mBottom - mTop; 18213 18214 mRight = right; 18215 mRenderNode.setRight(mRight); 18216 18217 sizeChange(mRight - mLeft, height, oldWidth, height); 18218 18219 if (!matrixIsIdentity) { 18220 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18221 invalidate(true); 18222 } 18223 mBackgroundSizeChanged = true; 18224 mDefaultFocusHighlightSizeChanged = true; 18225 if (mForegroundInfo != null) { 18226 mForegroundInfo.mBoundsChanged = true; 18227 } 18228 invalidateParentIfNeeded(); 18229 } 18230 } 18231 sanitizeFloatPropertyValue(float value, String propertyName)18232 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 18233 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 18234 } 18235 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)18236 private static float sanitizeFloatPropertyValue(float value, String propertyName, 18237 float min, float max) { 18238 // The expected "nothing bad happened" path 18239 if (value >= min && value <= max) return value; 18240 18241 if (value < min || value == Float.NEGATIVE_INFINITY) { 18242 if (sThrowOnInvalidFloatProperties) { 18243 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 18244 + value + ", the value must be >= " + min); 18245 } 18246 return min; 18247 } 18248 18249 if (value > max || value == Float.POSITIVE_INFINITY) { 18250 if (sThrowOnInvalidFloatProperties) { 18251 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 18252 + value + ", the value must be <= " + max); 18253 } 18254 return max; 18255 } 18256 18257 if (Float.isNaN(value)) { 18258 if (sThrowOnInvalidFloatProperties) { 18259 throw new IllegalArgumentException( 18260 "Cannot set '" + propertyName + "' to Float.NaN"); 18261 } 18262 return 0; // Unclear which direction this NaN went so... 0? 18263 } 18264 18265 // Shouldn't be possible to reach this. 18266 throw new IllegalStateException("How do you get here?? " + value); 18267 } 18268 18269 /** 18270 * The visual x position of this view, in pixels. This is equivalent to the 18271 * {@link #setTranslationX(float) translationX} property plus the current 18272 * {@link #getLeft() left} property. 18273 * 18274 * @return The visual x position of this view, in pixels. 18275 */ 18276 @ViewDebug.ExportedProperty(category = "drawing") getX()18277 public float getX() { 18278 return mLeft + getTranslationX(); 18279 } 18280 18281 /** 18282 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 18283 * {@link #setTranslationX(float) translationX} property to be the difference between 18284 * the x value passed in and the current {@link #getLeft() left} property. 18285 * 18286 * @param x The visual x position of this view, in pixels. 18287 */ setX(float x)18288 public void setX(float x) { 18289 setTranslationX(x - mLeft); 18290 } 18291 18292 /** 18293 * The visual y position of this view, in pixels. This is equivalent to the 18294 * {@link #setTranslationY(float) translationY} property plus the current 18295 * {@link #getTop() top} property. 18296 * 18297 * @return The visual y position of this view, in pixels. 18298 */ 18299 @ViewDebug.ExportedProperty(category = "drawing") getY()18300 public float getY() { 18301 return mTop + getTranslationY(); 18302 } 18303 18304 /** 18305 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 18306 * {@link #setTranslationY(float) translationY} property to be the difference between 18307 * the y value passed in and the current {@link #getTop() top} property. 18308 * 18309 * @param y The visual y position of this view, in pixels. 18310 */ setY(float y)18311 public void setY(float y) { 18312 setTranslationY(y - mTop); 18313 } 18314 18315 /** 18316 * The visual z position of this view, in pixels. This is equivalent to the 18317 * {@link #setTranslationZ(float) translationZ} property plus the current 18318 * {@link #getElevation() elevation} property. 18319 * 18320 * @return The visual z position of this view, in pixels. 18321 */ 18322 @ViewDebug.ExportedProperty(category = "drawing") getZ()18323 public float getZ() { 18324 return getElevation() + getTranslationZ(); 18325 } 18326 18327 /** 18328 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 18329 * {@link #setTranslationZ(float) translationZ} property to be the difference between 18330 * the z value passed in and the current {@link #getElevation() elevation} property. 18331 * 18332 * @param z The visual z position of this view, in pixels. 18333 */ setZ(float z)18334 public void setZ(float z) { 18335 setTranslationZ(z - getElevation()); 18336 } 18337 18338 /** 18339 * The base elevation of this view relative to its parent, in pixels. 18340 * 18341 * @return The base depth position of the view, in pixels. 18342 */ 18343 @ViewDebug.ExportedProperty(category = "drawing") 18344 @InspectableProperty getElevation()18345 public float getElevation() { 18346 return mRenderNode.getElevation(); 18347 } 18348 18349 /** 18350 * Sets the base elevation of this view, in pixels. 18351 * 18352 * @attr ref android.R.styleable#View_elevation 18353 */ 18354 @RemotableViewMethod setElevation(float elevation)18355 public void setElevation(float elevation) { 18356 if (elevation != getElevation()) { 18357 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 18358 invalidateViewProperty(true, false); 18359 mRenderNode.setElevation(elevation); 18360 invalidateViewProperty(false, true); 18361 18362 invalidateParentIfNeededAndWasQuickRejected(); 18363 } 18364 } 18365 18366 /** 18367 * The horizontal location of this view relative to its {@link #getLeft() left} position. 18368 * This position is post-layout, in addition to wherever the object's 18369 * layout placed it. 18370 * 18371 * @return The horizontal position of this view relative to its left position, in pixels. 18372 */ 18373 @ViewDebug.ExportedProperty(category = "drawing") 18374 @InspectableProperty getTranslationX()18375 public float getTranslationX() { 18376 return mRenderNode.getTranslationX(); 18377 } 18378 18379 /** 18380 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 18381 * This effectively positions the object post-layout, in addition to wherever the object's 18382 * layout placed it. 18383 * 18384 * @param translationX The horizontal position of this view relative to its left position, 18385 * in pixels. 18386 * 18387 * @attr ref android.R.styleable#View_translationX 18388 */ 18389 @RemotableViewMethod setTranslationX(float translationX)18390 public void setTranslationX(float translationX) { 18391 if (translationX != getTranslationX()) { 18392 invalidateViewProperty(true, false); 18393 mRenderNode.setTranslationX(translationX); 18394 invalidateViewProperty(false, true); 18395 18396 invalidateParentIfNeededAndWasQuickRejected(); 18397 notifySubtreeAccessibilityStateChangedIfNeeded(); 18398 } 18399 } 18400 18401 /** 18402 * The vertical location of this view relative to its {@link #getTop() top} position. 18403 * This position is post-layout, in addition to wherever the object's 18404 * layout placed it. 18405 * 18406 * @return The vertical position of this view relative to its top position, 18407 * in pixels. 18408 */ 18409 @ViewDebug.ExportedProperty(category = "drawing") 18410 @InspectableProperty getTranslationY()18411 public float getTranslationY() { 18412 return mRenderNode.getTranslationY(); 18413 } 18414 18415 /** 18416 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 18417 * This effectively positions the object post-layout, in addition to wherever the object's 18418 * layout placed it. 18419 * 18420 * @param translationY The vertical position of this view relative to its top position, 18421 * in pixels. 18422 * 18423 * @attr ref android.R.styleable#View_translationY 18424 */ 18425 @RemotableViewMethod setTranslationY(float translationY)18426 public void setTranslationY(float translationY) { 18427 if (translationY != getTranslationY()) { 18428 invalidateViewProperty(true, false); 18429 mRenderNode.setTranslationY(translationY); 18430 invalidateViewProperty(false, true); 18431 18432 invalidateParentIfNeededAndWasQuickRejected(); 18433 notifySubtreeAccessibilityStateChangedIfNeeded(); 18434 } 18435 } 18436 18437 /** 18438 * The depth location of this view relative to its {@link #getElevation() elevation}. 18439 * 18440 * @return The depth of this view relative to its elevation. 18441 */ 18442 @ViewDebug.ExportedProperty(category = "drawing") 18443 @InspectableProperty getTranslationZ()18444 public float getTranslationZ() { 18445 return mRenderNode.getTranslationZ(); 18446 } 18447 18448 /** 18449 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 18450 * 18451 * @attr ref android.R.styleable#View_translationZ 18452 */ 18453 @RemotableViewMethod setTranslationZ(float translationZ)18454 public void setTranslationZ(float translationZ) { 18455 if (translationZ != getTranslationZ()) { 18456 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 18457 invalidateViewProperty(true, false); 18458 mRenderNode.setTranslationZ(translationZ); 18459 invalidateViewProperty(false, true); 18460 18461 invalidateParentIfNeededAndWasQuickRejected(); 18462 } 18463 } 18464 18465 /** 18466 * Changes the transformation matrix on the view. This is used in animation frameworks, 18467 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 18468 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 18469 * Application developers should use transformation methods like {@link #setRotation(float)}, 18470 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 18471 * and {@link #setTranslationY(float)} (float)}} instead. 18472 * 18473 * @param matrix The matrix, null indicates that the matrix should be cleared. 18474 * @see #getAnimationMatrix() 18475 */ setAnimationMatrix(@ullable Matrix matrix)18476 public void setAnimationMatrix(@Nullable Matrix matrix) { 18477 invalidateViewProperty(true, false); 18478 mRenderNode.setAnimationMatrix(matrix); 18479 invalidateViewProperty(false, true); 18480 18481 invalidateParentIfNeededAndWasQuickRejected(); 18482 } 18483 18484 /** 18485 * Return the current transformation matrix of the view. This is used in animation frameworks, 18486 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 18487 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 18488 * Application developers should use transformation methods like {@link #setRotation(float)}, 18489 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 18490 * and {@link #setTranslationY(float)} (float)}} instead. 18491 * 18492 * @return the Matrix, null indicates there is no transformation 18493 * @see #setAnimationMatrix(Matrix) 18494 */ 18495 @Nullable getAnimationMatrix()18496 public Matrix getAnimationMatrix() { 18497 return mRenderNode.getAnimationMatrix(); 18498 } 18499 18500 /** 18501 * Returns the current StateListAnimator if exists. 18502 * 18503 * @return StateListAnimator or null if it does not exists 18504 * @see #setStateListAnimator(android.animation.StateListAnimator) 18505 */ 18506 @InspectableProperty getStateListAnimator()18507 public StateListAnimator getStateListAnimator() { 18508 return mStateListAnimator; 18509 } 18510 18511 /** 18512 * Attaches the provided StateListAnimator to this View. 18513 * <p> 18514 * Any previously attached StateListAnimator will be detached. 18515 * 18516 * @param stateListAnimator The StateListAnimator to update the view 18517 * @see android.animation.StateListAnimator 18518 */ setStateListAnimator(StateListAnimator stateListAnimator)18519 public void setStateListAnimator(StateListAnimator stateListAnimator) { 18520 if (mStateListAnimator == stateListAnimator) { 18521 return; 18522 } 18523 if (mStateListAnimator != null) { 18524 mStateListAnimator.setTarget(null); 18525 } 18526 mStateListAnimator = stateListAnimator; 18527 if (stateListAnimator != null) { 18528 stateListAnimator.setTarget(this); 18529 if (isAttachedToWindow()) { 18530 stateListAnimator.setState(getDrawableState()); 18531 } 18532 } 18533 } 18534 18535 /** 18536 * Returns whether the Outline should be used to clip the contents of the View. 18537 * <p> 18538 * Note that this flag will only be respected if the View's Outline returns true from 18539 * {@link Outline#canClip()}. 18540 * 18541 * @see #setOutlineProvider(ViewOutlineProvider) 18542 * @see #setClipToOutline(boolean) 18543 */ getClipToOutline()18544 public final boolean getClipToOutline() { 18545 return mRenderNode.getClipToOutline(); 18546 } 18547 18548 /** 18549 * Sets whether the View's Outline should be used to clip the contents of the View. 18550 * <p> 18551 * Only a single non-rectangular clip can be applied on a View at any time. 18552 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 18553 * circular reveal} animation take priority over Outline clipping, and 18554 * child Outline clipping takes priority over Outline clipping done by a 18555 * parent. 18556 * <p> 18557 * Note that this flag will only be respected if the View's Outline returns true from 18558 * {@link Outline#canClip()}. 18559 * 18560 * @see #setOutlineProvider(ViewOutlineProvider) 18561 * @see #getClipToOutline() 18562 * 18563 * @attr ref android.R.styleable#View_clipToOutline 18564 */ 18565 @RemotableViewMethod setClipToOutline(boolean clipToOutline)18566 public void setClipToOutline(boolean clipToOutline) { 18567 damageInParent(); 18568 if (getClipToOutline() != clipToOutline) { 18569 mRenderNode.setClipToOutline(clipToOutline); 18570 } 18571 } 18572 18573 // correspond to the enum values of View_outlineProvider 18574 private static final int PROVIDER_BACKGROUND = 0; 18575 private static final int PROVIDER_NONE = 1; 18576 private static final int PROVIDER_BOUNDS = 2; 18577 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)18578 private void setOutlineProviderFromAttribute(int providerInt) { 18579 switch (providerInt) { 18580 case PROVIDER_BACKGROUND: 18581 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 18582 break; 18583 case PROVIDER_NONE: 18584 setOutlineProvider(null); 18585 break; 18586 case PROVIDER_BOUNDS: 18587 setOutlineProvider(ViewOutlineProvider.BOUNDS); 18588 break; 18589 case PROVIDER_PADDED_BOUNDS: 18590 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 18591 break; 18592 } 18593 } 18594 18595 /** 18596 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 18597 * the shape of the shadow it casts, and enables outline clipping. 18598 * <p> 18599 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 18600 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 18601 * outline provider with this method allows this behavior to be overridden. 18602 * <p> 18603 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 18604 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 18605 * <p> 18606 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 18607 * 18608 * @see #setClipToOutline(boolean) 18609 * @see #getClipToOutline() 18610 * @see #getOutlineProvider() 18611 */ setOutlineProvider(ViewOutlineProvider provider)18612 public void setOutlineProvider(ViewOutlineProvider provider) { 18613 mOutlineProvider = provider; 18614 invalidateOutline(); 18615 } 18616 18617 /** 18618 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 18619 * that defines the shape of the shadow it casts, and enables outline clipping. 18620 * 18621 * @see #setOutlineProvider(ViewOutlineProvider) 18622 */ 18623 @InspectableProperty getOutlineProvider()18624 public ViewOutlineProvider getOutlineProvider() { 18625 return mOutlineProvider; 18626 } 18627 18628 /** 18629 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 18630 * 18631 * @see #setOutlineProvider(ViewOutlineProvider) 18632 */ invalidateOutline()18633 public void invalidateOutline() { 18634 rebuildOutline(); 18635 18636 notifySubtreeAccessibilityStateChangedIfNeeded(); 18637 invalidateViewProperty(false, false); 18638 } 18639 18640 /** 18641 * Internal version of {@link #invalidateOutline()} which invalidates the 18642 * outline without invalidating the view itself. This is intended to be called from 18643 * within methods in the View class itself which are the result of the view being 18644 * invalidated already. For example, when we are drawing the background of a View, 18645 * we invalidate the outline in case it changed in the meantime, but we do not 18646 * need to invalidate the view because we're already drawing the background as part 18647 * of drawing the view in response to an earlier invalidation of the view. 18648 */ rebuildOutline()18649 private void rebuildOutline() { 18650 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 18651 if (mAttachInfo == null) return; 18652 18653 if (mOutlineProvider == null) { 18654 // no provider, remove outline 18655 mRenderNode.setOutline(null); 18656 } else { 18657 final Outline outline = mAttachInfo.mTmpOutline; 18658 outline.setEmpty(); 18659 outline.setAlpha(1.0f); 18660 18661 mOutlineProvider.getOutline(this, outline); 18662 mRenderNode.setOutline(outline); 18663 } 18664 } 18665 18666 /** 18667 * HierarchyViewer only 18668 * 18669 * @hide 18670 */ 18671 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()18672 public boolean hasShadow() { 18673 return mRenderNode.hasShadow(); 18674 } 18675 18676 /** 18677 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 18678 * elevation value. 18679 * <p> 18680 * By default the shadow color is black. Generally, this color will be opaque so the intensity 18681 * of the shadow is consistent between different views with different colors. 18682 * <p> 18683 * The opacity of the final spot shadow is a function of the shadow caster height, the 18684 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 18685 * {@link android.R.attr#spotShadowAlpha} theme attribute. 18686 * 18687 * @attr ref android.R.styleable#View_outlineSpotShadowColor 18688 * @param color The color this View will cast for its elevation spot shadow. 18689 */ setOutlineSpotShadowColor(@olorInt int color)18690 public void setOutlineSpotShadowColor(@ColorInt int color) { 18691 if (mRenderNode.setSpotShadowColor(color)) { 18692 invalidateViewProperty(true, true); 18693 } 18694 } 18695 18696 /** 18697 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 18698 * was set 18699 */ 18700 @InspectableProperty getOutlineSpotShadowColor()18701 public @ColorInt int getOutlineSpotShadowColor() { 18702 return mRenderNode.getSpotShadowColor(); 18703 } 18704 18705 /** 18706 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 18707 * elevation value. 18708 * <p> 18709 * By default the shadow color is black. Generally, this color will be opaque so the intensity 18710 * of the shadow is consistent between different views with different colors. 18711 * <p> 18712 * The opacity of the final ambient shadow is a function of the shadow caster height, the 18713 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 18714 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 18715 * 18716 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 18717 * @param color The color this View will cast for its elevation shadow. 18718 */ setOutlineAmbientShadowColor(@olorInt int color)18719 public void setOutlineAmbientShadowColor(@ColorInt int color) { 18720 if (mRenderNode.setAmbientShadowColor(color)) { 18721 invalidateViewProperty(true, true); 18722 } 18723 } 18724 18725 /** 18726 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 18727 * nothing was set 18728 */ 18729 @InspectableProperty getOutlineAmbientShadowColor()18730 public @ColorInt int getOutlineAmbientShadowColor() { 18731 return mRenderNode.getAmbientShadowColor(); 18732 } 18733 18734 18735 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)18736 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 18737 mRenderNode.setRevealClip(shouldClip, x, y, radius); 18738 invalidateViewProperty(false, false); 18739 } 18740 18741 /** 18742 * Hit rectangle in parent's coordinates 18743 * 18744 * @param outRect The hit rectangle of the view. 18745 */ getHitRect(Rect outRect)18746 public void getHitRect(Rect outRect) { 18747 if (hasIdentityMatrix() || mAttachInfo == null) { 18748 outRect.set(mLeft, mTop, mRight, mBottom); 18749 } else { 18750 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 18751 tmpRect.set(0, 0, getWidth(), getHeight()); 18752 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 18753 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 18754 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 18755 } 18756 } 18757 18758 /** 18759 * Determines whether the given point, in local coordinates is inside the view. 18760 */ pointInView(float localX, float localY)18761 /*package*/ final boolean pointInView(float localX, float localY) { 18762 return pointInView(localX, localY, 0); 18763 } 18764 18765 /** 18766 * Utility method to determine whether the given point, in local coordinates, 18767 * is inside the view, where the area of the view is expanded by the slop factor. 18768 * This method is called while processing touch-move events to determine if the event 18769 * is still within the view. 18770 * 18771 * @hide 18772 */ 18773 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)18774 public boolean pointInView(float localX, float localY, float slop) { 18775 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 18776 localY < ((mBottom - mTop) + slop); 18777 } 18778 18779 /** 18780 * When a view has focus and the user navigates away from it, the next view is searched for 18781 * starting from the rectangle filled in by this method. 18782 * 18783 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 18784 * of the view. However, if your view maintains some idea of internal selection, 18785 * such as a cursor, or a selected row or column, you should override this method and 18786 * fill in a more specific rectangle. 18787 * 18788 * @param r The rectangle to fill in, in this view's coordinates. 18789 */ getFocusedRect(Rect r)18790 public void getFocusedRect(Rect r) { 18791 getDrawingRect(r); 18792 } 18793 18794 /** 18795 * Sets {@code r} to the coordinates of the non-clipped area of this view in 18796 * the coordinate space of the view's root view. Sets {@code globalOffset} 18797 * to the offset of the view's x and y coordinates from the coordinate space 18798 * origin, which is the top left corner of the root view irrespective of 18799 * screen decorations and system UI elements. 18800 * 18801 * <p>To convert {@code r} to coordinates relative to the top left corner of 18802 * this view (without taking view rotations into account), offset {@code r} 18803 * by the inverse values of 18804 * {@code globalOffset}—{@code r.offset(-globalOffset.x, 18805 * -globalOffset.y)}—which is equivalent to calling 18806 * {@link #getLocalVisibleRect(Rect) getLocalVisibleRect(Rect)}. 18807 * 18808 * <p><b>Note:</b> Do not use this method to determine the size of a window 18809 * in multi-window mode; use 18810 * {@link WindowManager#getCurrentWindowMetrics()}. 18811 * 18812 * @param r If the method returns true, contains the coordinates of the 18813 * visible portion of this view in the coordinate space of the view's 18814 * root view. If the method returns false, the contents of {@code r} 18815 * are undefined. 18816 * @param globalOffset If the method returns true, contains the offset of 18817 * the x and y coordinates of this view from the top left corner of the 18818 * view's root view. If the method returns false, the contents of 18819 * {@code globalOffset} are undefined. The argument can be null (see 18820 * {@link #getGlobalVisibleRect(Rect) getGlobalVisibleRect(Rect)}. 18821 * @return true if at least part of the view is visible within the root 18822 * view; false if the view is completely clipped or translated out of 18823 * the visible area of the root view. 18824 * 18825 * @see #getLocalVisibleRect(Rect) 18826 */ getGlobalVisibleRect(Rect r, Point globalOffset)18827 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 18828 int width = mRight - mLeft; 18829 int height = mBottom - mTop; 18830 if (width > 0 && height > 0) { 18831 r.set(0, 0, width, height); 18832 if (globalOffset != null) { 18833 globalOffset.set(-mScrollX, -mScrollY); 18834 } 18835 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 18836 } 18837 return false; 18838 } 18839 18840 /** 18841 * Sets {@code r} to the coordinates of the non-clipped area of this view in 18842 * the coordinate space of the view's root view. 18843 * 18844 * <p>See {@link #getGlobalVisibleRect(Rect, Point) 18845 * getGlobalVisibleRect(Rect, Point)} for more information. 18846 * 18847 * @param r If the method returns true, contains the coordinates of the 18848 * visible portion of this view in the coordinate space of the view's 18849 * root view. If the method returns false, the contents of {@code r} 18850 * are undefined. 18851 * @return true if at least part of the view is visible within the root 18852 * view; otherwise false. 18853 */ getGlobalVisibleRect(Rect r)18854 public final boolean getGlobalVisibleRect(Rect r) { 18855 return getGlobalVisibleRect(r, null); 18856 } 18857 18858 /** 18859 * Sets {@code r} to the coordinates of the non-clipped area of this view 18860 * relative to the top left corner of the view. 18861 * 18862 * <p>If the view is clipped on the left or top, the left and top 18863 * coordinates are offset from 0 by the clipped amount. For example, if the 18864 * view is off screen 50px on the left and 30px at the top, the left and top 18865 * coordinates are 50 and 30 respectively. 18866 * 18867 * <p>If the view is clipped on the right or bottom, the right and bottom 18868 * coordinates are reduced by the clipped amount. For example, if the view 18869 * is off screen 40px on the right and 20px at the bottom, the right 18870 * coordinate is the view width - 40, and the bottom coordinate is the view 18871 * height - 20. 18872 * 18873 * @param r If the method returns true, contains the coordinates of the 18874 * visible portion of this view relative to the top left corner of the 18875 * view. If the method returns false, the contents of {@code r} are 18876 * undefined. 18877 * @return true if at least part of the view is visible; false if the view 18878 * is completely clipped or translated out of the visible area. 18879 * 18880 * @see #getGlobalVisibleRect(Rect, Point) 18881 */ getLocalVisibleRect(Rect r)18882 public final boolean getLocalVisibleRect(Rect r) { 18883 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 18884 if (getGlobalVisibleRect(r, offset)) { 18885 r.offset(-offset.x, -offset.y); // make r local 18886 return true; 18887 } 18888 return false; 18889 } 18890 18891 /** 18892 * Offset this view's vertical location by the specified number of pixels. 18893 * 18894 * @param offset the number of pixels to offset the view by 18895 */ offsetTopAndBottom(int offset)18896 public void offsetTopAndBottom(int offset) { 18897 if (offset != 0) { 18898 final boolean matrixIsIdentity = hasIdentityMatrix(); 18899 if (matrixIsIdentity) { 18900 if (isHardwareAccelerated()) { 18901 invalidateViewProperty(false, false); 18902 } else { 18903 final ViewParent p = mParent; 18904 if (p != null && mAttachInfo != null) { 18905 final Rect r = mAttachInfo.mTmpInvalRect; 18906 int minTop; 18907 int maxBottom; 18908 int yLoc; 18909 if (offset < 0) { 18910 minTop = mTop + offset; 18911 maxBottom = mBottom; 18912 yLoc = offset; 18913 } else { 18914 minTop = mTop; 18915 maxBottom = mBottom + offset; 18916 yLoc = 0; 18917 } 18918 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 18919 p.invalidateChild(this, r); 18920 } 18921 } 18922 } else { 18923 invalidateViewProperty(false, false); 18924 } 18925 18926 mTop += offset; 18927 mBottom += offset; 18928 mRenderNode.offsetTopAndBottom(offset); 18929 if (isHardwareAccelerated()) { 18930 invalidateViewProperty(false, false); 18931 invalidateParentIfNeededAndWasQuickRejected(); 18932 } else { 18933 if (!matrixIsIdentity) { 18934 invalidateViewProperty(false, true); 18935 } 18936 invalidateParentIfNeeded(); 18937 } 18938 notifySubtreeAccessibilityStateChangedIfNeeded(); 18939 } 18940 } 18941 18942 /** 18943 * Offset this view's horizontal location by the specified amount of pixels. 18944 * 18945 * @param offset the number of pixels to offset the view by 18946 */ offsetLeftAndRight(int offset)18947 public void offsetLeftAndRight(int offset) { 18948 if (offset != 0) { 18949 final boolean matrixIsIdentity = hasIdentityMatrix(); 18950 if (matrixIsIdentity) { 18951 if (isHardwareAccelerated()) { 18952 invalidateViewProperty(false, false); 18953 } else { 18954 final ViewParent p = mParent; 18955 if (p != null && mAttachInfo != null) { 18956 final Rect r = mAttachInfo.mTmpInvalRect; 18957 int minLeft; 18958 int maxRight; 18959 if (offset < 0) { 18960 minLeft = mLeft + offset; 18961 maxRight = mRight; 18962 } else { 18963 minLeft = mLeft; 18964 maxRight = mRight + offset; 18965 } 18966 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 18967 p.invalidateChild(this, r); 18968 } 18969 } 18970 } else { 18971 invalidateViewProperty(false, false); 18972 } 18973 18974 mLeft += offset; 18975 mRight += offset; 18976 mRenderNode.offsetLeftAndRight(offset); 18977 if (isHardwareAccelerated()) { 18978 invalidateViewProperty(false, false); 18979 invalidateParentIfNeededAndWasQuickRejected(); 18980 } else { 18981 if (!matrixIsIdentity) { 18982 invalidateViewProperty(false, true); 18983 } 18984 invalidateParentIfNeeded(); 18985 } 18986 notifySubtreeAccessibilityStateChangedIfNeeded(); 18987 } 18988 } 18989 18990 /** 18991 * Get the LayoutParams associated with this view. All views should have 18992 * layout parameters. These supply parameters to the <i>parent</i> of this 18993 * view specifying how it should be arranged. There are many subclasses of 18994 * ViewGroup.LayoutParams, and these correspond to the different subclasses 18995 * of ViewGroup that are responsible for arranging their children. 18996 * 18997 * This method may return null if this View is not attached to a parent 18998 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 18999 * was not invoked successfully. When a View is attached to a parent 19000 * ViewGroup, this method must not return null. 19001 * 19002 * @return The LayoutParams associated with this view, or null if no 19003 * parameters have been set yet 19004 */ 19005 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()19006 public ViewGroup.LayoutParams getLayoutParams() { 19007 return mLayoutParams; 19008 } 19009 19010 /** 19011 * Set the layout parameters associated with this view. These supply 19012 * parameters to the <i>parent</i> of this view specifying how it should be 19013 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 19014 * correspond to the different subclasses of ViewGroup that are responsible 19015 * for arranging their children. 19016 * 19017 * @param params The layout parameters for this view, cannot be null 19018 */ setLayoutParams(ViewGroup.LayoutParams params)19019 public void setLayoutParams(ViewGroup.LayoutParams params) { 19020 if (params == null) { 19021 throw new NullPointerException("Layout parameters cannot be null"); 19022 } 19023 mLayoutParams = params; 19024 resolveLayoutParams(); 19025 if (mParent instanceof ViewGroup) { 19026 ((ViewGroup) mParent).onSetLayoutParams(this, params); 19027 } 19028 requestLayout(); 19029 } 19030 19031 /** 19032 * Resolve the layout parameters depending on the resolved layout direction 19033 * 19034 * @hide 19035 */ resolveLayoutParams()19036 public void resolveLayoutParams() { 19037 if (mLayoutParams != null) { 19038 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 19039 } 19040 } 19041 19042 /** 19043 * Set the scrolled position of your view. This will cause a call to 19044 * {@link #onScrollChanged(int, int, int, int)} and the view will be 19045 * invalidated. 19046 * @param x the x position to scroll to 19047 * @param y the y position to scroll to 19048 */ scrollTo(int x, int y)19049 public void scrollTo(int x, int y) { 19050 if (mScrollX != x || mScrollY != y) { 19051 int oldX = mScrollX; 19052 int oldY = mScrollY; 19053 mScrollX = x; 19054 mScrollY = y; 19055 invalidateParentCaches(); 19056 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 19057 if (!awakenScrollBars()) { 19058 postInvalidateOnAnimation(); 19059 } 19060 } 19061 } 19062 19063 /** 19064 * Move the scrolled position of your view. This will cause a call to 19065 * {@link #onScrollChanged(int, int, int, int)} and the view will be 19066 * invalidated. 19067 * @param x the amount of pixels to scroll by horizontally 19068 * @param y the amount of pixels to scroll by vertically 19069 */ scrollBy(int x, int y)19070 public void scrollBy(int x, int y) { 19071 scrollTo(mScrollX + x, mScrollY + y); 19072 } 19073 19074 /** 19075 * <p>Trigger the scrollbars to draw. When invoked this method starts an 19076 * animation to fade the scrollbars out after a default delay. If a subclass 19077 * provides animated scrolling, the start delay should equal the duration 19078 * of the scrolling animation.</p> 19079 * 19080 * <p>The animation starts only if at least one of the scrollbars is 19081 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 19082 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 19083 * this method returns true, and false otherwise. If the animation is 19084 * started, this method calls {@link #invalidate()}; in that case the 19085 * caller should not call {@link #invalidate()}.</p> 19086 * 19087 * <p>This method should be invoked every time a subclass directly updates 19088 * the scroll parameters.</p> 19089 * 19090 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 19091 * and {@link #scrollTo(int, int)}.</p> 19092 * 19093 * @return true if the animation is played, false otherwise 19094 * 19095 * @see #awakenScrollBars(int) 19096 * @see #scrollBy(int, int) 19097 * @see #scrollTo(int, int) 19098 * @see #isHorizontalScrollBarEnabled() 19099 * @see #isVerticalScrollBarEnabled() 19100 * @see #setHorizontalScrollBarEnabled(boolean) 19101 * @see #setVerticalScrollBarEnabled(boolean) 19102 */ awakenScrollBars()19103 protected boolean awakenScrollBars() { 19104 return mScrollCache != null && 19105 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 19106 } 19107 19108 /** 19109 * Trigger the scrollbars to draw. 19110 * This method differs from awakenScrollBars() only in its default duration. 19111 * initialAwakenScrollBars() will show the scroll bars for longer than 19112 * usual to give the user more of a chance to notice them. 19113 * 19114 * @return true if the animation is played, false otherwise. 19115 */ initialAwakenScrollBars()19116 private boolean initialAwakenScrollBars() { 19117 return mScrollCache != null && 19118 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 19119 } 19120 19121 /** 19122 * <p> 19123 * Trigger the scrollbars to draw. When invoked this method starts an 19124 * animation to fade the scrollbars out after a fixed delay. If a subclass 19125 * provides animated scrolling, the start delay should equal the duration of 19126 * the scrolling animation. 19127 * </p> 19128 * 19129 * <p> 19130 * The animation starts only if at least one of the scrollbars is enabled, 19131 * as specified by {@link #isHorizontalScrollBarEnabled()} and 19132 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 19133 * this method returns true, and false otherwise. If the animation is 19134 * started, this method calls {@link #invalidate()}; in that case the caller 19135 * should not call {@link #invalidate()}. 19136 * </p> 19137 * 19138 * <p> 19139 * This method should be invoked every time a subclass directly updates the 19140 * scroll parameters. 19141 * </p> 19142 * 19143 * @param startDelay the delay, in milliseconds, after which the animation 19144 * should start; when the delay is 0, the animation starts 19145 * immediately 19146 * @return true if the animation is played, false otherwise 19147 * 19148 * @see #scrollBy(int, int) 19149 * @see #scrollTo(int, int) 19150 * @see #isHorizontalScrollBarEnabled() 19151 * @see #isVerticalScrollBarEnabled() 19152 * @see #setHorizontalScrollBarEnabled(boolean) 19153 * @see #setVerticalScrollBarEnabled(boolean) 19154 */ awakenScrollBars(int startDelay)19155 protected boolean awakenScrollBars(int startDelay) { 19156 return awakenScrollBars(startDelay, true); 19157 } 19158 19159 /** 19160 * <p> 19161 * Trigger the scrollbars to draw. When invoked this method starts an 19162 * animation to fade the scrollbars out after a fixed delay. If a subclass 19163 * provides animated scrolling, the start delay should equal the duration of 19164 * the scrolling animation. 19165 * </p> 19166 * 19167 * <p> 19168 * The animation starts only if at least one of the scrollbars is enabled, 19169 * as specified by {@link #isHorizontalScrollBarEnabled()} and 19170 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 19171 * this method returns true, and false otherwise. If the animation is 19172 * started, this method calls {@link #invalidate()} if the invalidate parameter 19173 * is set to true; in that case the caller 19174 * should not call {@link #invalidate()}. 19175 * </p> 19176 * 19177 * <p> 19178 * This method should be invoked every time a subclass directly updates the 19179 * scroll parameters. 19180 * </p> 19181 * 19182 * @param startDelay the delay, in milliseconds, after which the animation 19183 * should start; when the delay is 0, the animation starts 19184 * immediately 19185 * 19186 * @param invalidate Whether this method should call invalidate 19187 * 19188 * @return true if the animation is played, false otherwise 19189 * 19190 * @see #scrollBy(int, int) 19191 * @see #scrollTo(int, int) 19192 * @see #isHorizontalScrollBarEnabled() 19193 * @see #isVerticalScrollBarEnabled() 19194 * @see #setHorizontalScrollBarEnabled(boolean) 19195 * @see #setVerticalScrollBarEnabled(boolean) 19196 */ awakenScrollBars(int startDelay, boolean invalidate)19197 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 19198 final ScrollabilityCache scrollCache = mScrollCache; 19199 19200 if (scrollCache == null || !scrollCache.fadeScrollBars) { 19201 return false; 19202 } 19203 19204 if (scrollCache.scrollBar == null) { 19205 scrollCache.scrollBar = new ScrollBarDrawable(); 19206 scrollCache.scrollBar.setState(getDrawableState()); 19207 scrollCache.scrollBar.setCallback(this); 19208 } 19209 19210 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 19211 19212 if (invalidate) { 19213 // Invalidate to show the scrollbars 19214 postInvalidateOnAnimation(); 19215 } 19216 19217 if (scrollCache.state == ScrollabilityCache.OFF) { 19218 // FIXME: this is copied from WindowManagerService. 19219 // We should get this value from the system when it 19220 // is possible to do so. 19221 final int KEY_REPEAT_FIRST_DELAY = 750; 19222 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 19223 } 19224 19225 // Tell mScrollCache when we should start fading. This may 19226 // extend the fade start time if one was already scheduled 19227 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 19228 scrollCache.fadeStartTime = fadeStartTime; 19229 scrollCache.state = ScrollabilityCache.ON; 19230 19231 // Schedule our fader to run, unscheduling any old ones first 19232 if (mAttachInfo != null) { 19233 mAttachInfo.mHandler.removeCallbacks(scrollCache); 19234 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 19235 } 19236 19237 return true; 19238 } 19239 19240 return false; 19241 } 19242 19243 /** 19244 * Do not invalidate views which are not visible and which are not running an animation. They 19245 * will not get drawn and they should not set dirty flags as if they will be drawn 19246 */ skipInvalidate()19247 private boolean skipInvalidate() { 19248 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 19249 (!(mParent instanceof ViewGroup) || 19250 !((ViewGroup) mParent).isViewTransitioning(this)); 19251 } 19252 19253 /** 19254 * Mark the area defined by dirty as needing to be drawn. If the view is 19255 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 19256 * point in the future. 19257 * <p> 19258 * This must be called from a UI thread. To call from a non-UI thread, call 19259 * {@link #postInvalidate()}. 19260 * <p> 19261 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 19262 * {@code dirty}. 19263 * 19264 * @param dirty the rectangle representing the bounds of the dirty region 19265 * 19266 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 19267 * the importance of the dirty rectangle. In API 21 the given rectangle is 19268 * ignored entirely in favor of an internally-calculated area instead. 19269 * Because of this, clients are encouraged to just call {@link #invalidate()}. 19270 */ 19271 @Deprecated invalidate(Rect dirty)19272 public void invalidate(Rect dirty) { 19273 final int scrollX = mScrollX; 19274 final int scrollY = mScrollY; 19275 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 19276 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 19277 } 19278 19279 /** 19280 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 19281 * coordinates of the dirty rect are relative to the view. If the view is 19282 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 19283 * point in the future. 19284 * <p> 19285 * This must be called from a UI thread. To call from a non-UI thread, call 19286 * {@link #postInvalidate()}. 19287 * 19288 * @param l the left position of the dirty region 19289 * @param t the top position of the dirty region 19290 * @param r the right position of the dirty region 19291 * @param b the bottom position of the dirty region 19292 * 19293 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 19294 * the importance of the dirty rectangle. In API 21 the given rectangle is 19295 * ignored entirely in favor of an internally-calculated area instead. 19296 * Because of this, clients are encouraged to just call {@link #invalidate()}. 19297 */ 19298 @Deprecated invalidate(int l, int t, int r, int b)19299 public void invalidate(int l, int t, int r, int b) { 19300 final int scrollX = mScrollX; 19301 final int scrollY = mScrollY; 19302 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 19303 } 19304 19305 /** 19306 * Invalidate the whole view. If the view is visible, 19307 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 19308 * the future. 19309 * <p> 19310 * This must be called from a UI thread. To call from a non-UI thread, call 19311 * {@link #postInvalidate()}. 19312 */ invalidate()19313 public void invalidate() { 19314 invalidate(true); 19315 } 19316 19317 /** 19318 * This is where the invalidate() work actually happens. A full invalidate() 19319 * causes the drawing cache to be invalidated, but this function can be 19320 * called with invalidateCache set to false to skip that invalidation step 19321 * for cases that do not need it (for example, a component that remains at 19322 * the same dimensions with the same content). 19323 * 19324 * @param invalidateCache Whether the drawing cache for this view should be 19325 * invalidated as well. This is usually true for a full 19326 * invalidate, but may be set to false if the View's contents or 19327 * dimensions have not changed. 19328 * @hide 19329 */ 19330 @UnsupportedAppUsage invalidate(boolean invalidateCache)19331 public void invalidate(boolean invalidateCache) { 19332 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 19333 } 19334 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)19335 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 19336 boolean fullInvalidate) { 19337 if (mGhostView != null) { 19338 mGhostView.invalidate(true); 19339 return; 19340 } 19341 19342 if (skipInvalidate()) { 19343 return; 19344 } 19345 19346 // Reset content capture caches 19347 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 19348 mContentCaptureSessionCached = false; 19349 19350 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 19351 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 19352 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 19353 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 19354 if (fullInvalidate) { 19355 mLastIsOpaque = isOpaque(); 19356 mPrivateFlags &= ~PFLAG_DRAWN; 19357 } 19358 19359 mPrivateFlags |= PFLAG_DIRTY; 19360 19361 if (invalidateCache) { 19362 mPrivateFlags |= PFLAG_INVALIDATED; 19363 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 19364 } 19365 19366 // Propagate the damage rectangle to the parent view. 19367 final AttachInfo ai = mAttachInfo; 19368 final ViewParent p = mParent; 19369 if (p != null && ai != null && l < r && t < b) { 19370 final Rect damage = ai.mTmpInvalRect; 19371 damage.set(l, t, r, b); 19372 p.invalidateChild(this, damage); 19373 } 19374 19375 // Damage the entire projection receiver, if necessary. 19376 if (mBackground != null && mBackground.isProjected()) { 19377 final View receiver = getProjectionReceiver(); 19378 if (receiver != null) { 19379 receiver.damageInParent(); 19380 } 19381 } 19382 } 19383 } 19384 19385 /** 19386 * @return this view's projection receiver, or {@code null} if none exists 19387 */ getProjectionReceiver()19388 private View getProjectionReceiver() { 19389 ViewParent p = getParent(); 19390 while (p != null && p instanceof View) { 19391 final View v = (View) p; 19392 if (v.isProjectionReceiver()) { 19393 return v; 19394 } 19395 p = p.getParent(); 19396 } 19397 19398 return null; 19399 } 19400 19401 /** 19402 * @return whether the view is a projection receiver 19403 */ isProjectionReceiver()19404 private boolean isProjectionReceiver() { 19405 return mBackground != null; 19406 } 19407 19408 /** 19409 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 19410 * set any flags or handle all of the cases handled by the default invalidation methods. 19411 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 19412 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 19413 * walk up the hierarchy, transforming the dirty rect as necessary. 19414 * 19415 * The method also handles normal invalidation logic if display list properties are not 19416 * being used in this view. The invalidateParent and forceRedraw flags are used by that 19417 * backup approach, to handle these cases used in the various property-setting methods. 19418 * 19419 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 19420 * are not being used in this view 19421 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 19422 * list properties are not being used in this view 19423 */ 19424 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)19425 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 19426 if (!isHardwareAccelerated() 19427 || !mRenderNode.hasDisplayList() 19428 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 19429 if (invalidateParent) { 19430 invalidateParentCaches(); 19431 } 19432 if (forceRedraw) { 19433 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19434 } 19435 invalidate(false); 19436 } else { 19437 damageInParent(); 19438 } 19439 } 19440 19441 /** 19442 * Tells the parent view to damage this view's bounds. 19443 * 19444 * @hide 19445 */ damageInParent()19446 protected void damageInParent() { 19447 if (mParent != null && mAttachInfo != null) { 19448 mParent.onDescendantInvalidated(this, this); 19449 } 19450 } 19451 19452 /** 19453 * Used to indicate that the parent of this view should clear its caches. This functionality 19454 * is used to force the parent to rebuild its display list (when hardware-accelerated), 19455 * which is necessary when various parent-managed properties of the view change, such as 19456 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 19457 * clears the parent caches and does not causes an invalidate event. 19458 * 19459 * @hide 19460 */ 19461 @UnsupportedAppUsage invalidateParentCaches()19462 protected void invalidateParentCaches() { 19463 if (mParent instanceof View) { 19464 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 19465 } 19466 } 19467 19468 /** 19469 * Used to indicate that the parent of this view should be invalidated. This functionality 19470 * is used to force the parent to rebuild its display list (when hardware-accelerated), 19471 * which is necessary when various parent-managed properties of the view change, such as 19472 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 19473 * an invalidation event to the parent. 19474 * 19475 * @hide 19476 */ 19477 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) invalidateParentIfNeeded()19478 protected void invalidateParentIfNeeded() { 19479 if (isHardwareAccelerated() && mParent instanceof View) { 19480 ((View) mParent).invalidate(true); 19481 } 19482 } 19483 19484 /** 19485 * @hide 19486 */ invalidateParentIfNeededAndWasQuickRejected()19487 protected void invalidateParentIfNeededAndWasQuickRejected() { 19488 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 19489 // View was rejected last time it was drawn by its parent; this may have changed 19490 invalidateParentIfNeeded(); 19491 } 19492 } 19493 19494 /** 19495 * Indicates whether this View is opaque. An opaque View guarantees that it will 19496 * draw all the pixels overlapping its bounds using a fully opaque color. 19497 * 19498 * Subclasses of View should override this method whenever possible to indicate 19499 * whether an instance is opaque. Opaque Views are treated in a special way by 19500 * the View hierarchy, possibly allowing it to perform optimizations during 19501 * invalidate/draw passes. 19502 * 19503 * @return True if this View is guaranteed to be fully opaque, false otherwise. 19504 */ 19505 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()19506 public boolean isOpaque() { 19507 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 19508 getFinalAlpha() >= 1.0f; 19509 } 19510 19511 /** 19512 * @hide 19513 */ 19514 @UnsupportedAppUsage computeOpaqueFlags()19515 protected void computeOpaqueFlags() { 19516 // Opaque if: 19517 // - Has a background 19518 // - Background is opaque 19519 // - Doesn't have scrollbars or scrollbars overlay 19520 19521 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 19522 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 19523 } else { 19524 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 19525 } 19526 19527 final int flags = mViewFlags; 19528 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 19529 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 19530 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 19531 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 19532 } else { 19533 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 19534 } 19535 } 19536 19537 /** 19538 * @hide 19539 */ hasOpaqueScrollbars()19540 protected boolean hasOpaqueScrollbars() { 19541 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 19542 } 19543 19544 /** 19545 * @return A handler associated with the thread running the View. This 19546 * handler can be used to pump events in the UI events queue. 19547 */ getHandler()19548 public Handler getHandler() { 19549 final AttachInfo attachInfo = mAttachInfo; 19550 if (attachInfo != null) { 19551 return attachInfo.mHandler; 19552 } 19553 return null; 19554 } 19555 19556 /** 19557 * Returns the queue of runnable for this view. 19558 * 19559 * @return the queue of runnables for this view 19560 */ getRunQueue()19561 private HandlerActionQueue getRunQueue() { 19562 if (mRunQueue == null) { 19563 mRunQueue = new HandlerActionQueue(); 19564 } 19565 return mRunQueue; 19566 } 19567 19568 /** 19569 * Gets the view root associated with the View. 19570 * @return The view root, or null if none. 19571 * @hide 19572 */ 19573 @UnsupportedAppUsage getViewRootImpl()19574 public ViewRootImpl getViewRootImpl() { 19575 if (mAttachInfo != null) { 19576 return mAttachInfo.mViewRootImpl; 19577 } 19578 return null; 19579 } 19580 19581 /** 19582 * @hide 19583 */ 19584 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getThreadedRenderer()19585 public ThreadedRenderer getThreadedRenderer() { 19586 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 19587 } 19588 19589 /** 19590 * <p>Causes the Runnable to be added to the message queue. 19591 * The runnable will be run on the user interface thread.</p> 19592 * 19593 * @param action The Runnable that will be executed. 19594 * 19595 * @return Returns true if the Runnable was successfully placed in to the 19596 * message queue. Returns false on failure, usually because the 19597 * looper processing the message queue is exiting. 19598 * 19599 * @see #postDelayed 19600 * @see #removeCallbacks 19601 */ post(Runnable action)19602 public boolean post(Runnable action) { 19603 final AttachInfo attachInfo = mAttachInfo; 19604 if (attachInfo != null) { 19605 return attachInfo.mHandler.post(action); 19606 } 19607 19608 // Postpone the runnable until we know on which thread it needs to run. 19609 // Assume that the runnable will be successfully placed after attach. 19610 getRunQueue().post(action); 19611 return true; 19612 } 19613 19614 /** 19615 * <p>Causes the Runnable to be added to the message queue, to be run 19616 * after the specified amount of time elapses. 19617 * The runnable will be run on the user interface thread.</p> 19618 * 19619 * @param action The Runnable that will be executed. 19620 * @param delayMillis The delay (in milliseconds) until the Runnable 19621 * will be executed. 19622 * 19623 * @return true if the Runnable was successfully placed in to the 19624 * message queue. Returns false on failure, usually because the 19625 * looper processing the message queue is exiting. Note that a 19626 * result of true does not mean the Runnable will be processed -- 19627 * if the looper is quit before the delivery time of the message 19628 * occurs then the message will be dropped. 19629 * 19630 * @see #post 19631 * @see #removeCallbacks 19632 */ postDelayed(Runnable action, long delayMillis)19633 public boolean postDelayed(Runnable action, long delayMillis) { 19634 final AttachInfo attachInfo = mAttachInfo; 19635 if (attachInfo != null) { 19636 return attachInfo.mHandler.postDelayed(action, delayMillis); 19637 } 19638 19639 // Postpone the runnable until we know on which thread it needs to run. 19640 // Assume that the runnable will be successfully placed after attach. 19641 getRunQueue().postDelayed(action, delayMillis); 19642 return true; 19643 } 19644 19645 /** 19646 * <p>Causes the Runnable to execute on the next animation time step. 19647 * The runnable will be run on the user interface thread.</p> 19648 * 19649 * @param action The Runnable that will be executed. 19650 * 19651 * @see #postOnAnimationDelayed 19652 * @see #removeCallbacks 19653 */ postOnAnimation(Runnable action)19654 public void postOnAnimation(Runnable action) { 19655 final AttachInfo attachInfo = mAttachInfo; 19656 if (attachInfo != null) { 19657 attachInfo.mViewRootImpl.mChoreographer.postCallback( 19658 Choreographer.CALLBACK_ANIMATION, action, null); 19659 } else { 19660 // Postpone the runnable until we know 19661 // on which thread it needs to run. 19662 getRunQueue().post(action); 19663 } 19664 } 19665 19666 /** 19667 * <p>Causes the Runnable to execute on the next animation time step, 19668 * after the specified amount of time elapses. 19669 * The runnable will be run on the user interface thread.</p> 19670 * 19671 * @param action The Runnable that will be executed. 19672 * @param delayMillis The delay (in milliseconds) until the Runnable 19673 * will be executed. 19674 * 19675 * @see #postOnAnimation 19676 * @see #removeCallbacks 19677 */ postOnAnimationDelayed(Runnable action, long delayMillis)19678 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 19679 final AttachInfo attachInfo = mAttachInfo; 19680 if (attachInfo != null) { 19681 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19682 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 19683 } else { 19684 // Postpone the runnable until we know 19685 // on which thread it needs to run. 19686 getRunQueue().postDelayed(action, delayMillis); 19687 } 19688 } 19689 19690 /** 19691 * <p>Removes the specified Runnable from the message queue.</p> 19692 * 19693 * @param action The Runnable to remove from the message handling queue 19694 * 19695 * @return true if this view could ask the Handler to remove the Runnable, 19696 * false otherwise. When the returned value is true, the Runnable 19697 * may or may not have been actually removed from the message queue 19698 * (for instance, if the Runnable was not in the queue already.) 19699 * 19700 * @see #post 19701 * @see #postDelayed 19702 * @see #postOnAnimation 19703 * @see #postOnAnimationDelayed 19704 */ removeCallbacks(Runnable action)19705 public boolean removeCallbacks(Runnable action) { 19706 if (action != null) { 19707 final AttachInfo attachInfo = mAttachInfo; 19708 if (attachInfo != null) { 19709 attachInfo.mHandler.removeCallbacks(action); 19710 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19711 Choreographer.CALLBACK_ANIMATION, action, null); 19712 } 19713 getRunQueue().removeCallbacks(action); 19714 } 19715 return true; 19716 } 19717 19718 /** 19719 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 19720 * Use this to invalidate the View from a non-UI thread.</p> 19721 * 19722 * <p>This method can be invoked from outside of the UI thread 19723 * only when this View is attached to a window.</p> 19724 * 19725 * @see #invalidate() 19726 * @see #postInvalidateDelayed(long) 19727 */ postInvalidate()19728 public void postInvalidate() { 19729 postInvalidateDelayed(0); 19730 } 19731 19732 /** 19733 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 19734 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 19735 * 19736 * <p>This method can be invoked from outside of the UI thread 19737 * only when this View is attached to a window.</p> 19738 * 19739 * @param left The left coordinate of the rectangle to invalidate. 19740 * @param top The top coordinate of the rectangle to invalidate. 19741 * @param right The right coordinate of the rectangle to invalidate. 19742 * @param bottom The bottom coordinate of the rectangle to invalidate. 19743 * 19744 * @see #invalidate(int, int, int, int) 19745 * @see #invalidate(Rect) 19746 * @see #postInvalidateDelayed(long, int, int, int, int) 19747 */ postInvalidate(int left, int top, int right, int bottom)19748 public void postInvalidate(int left, int top, int right, int bottom) { 19749 postInvalidateDelayed(0, left, top, right, bottom); 19750 } 19751 19752 /** 19753 * <p>Cause an invalidate to happen on a subsequent cycle through the event 19754 * loop. Waits for the specified amount of time.</p> 19755 * 19756 * <p>This method can be invoked from outside of the UI thread 19757 * only when this View is attached to a window.</p> 19758 * 19759 * @param delayMilliseconds the duration in milliseconds to delay the 19760 * invalidation by 19761 * 19762 * @see #invalidate() 19763 * @see #postInvalidate() 19764 */ postInvalidateDelayed(long delayMilliseconds)19765 public void postInvalidateDelayed(long delayMilliseconds) { 19766 // We try only with the AttachInfo because there's no point in invalidating 19767 // if we are not attached to our window 19768 final AttachInfo attachInfo = mAttachInfo; 19769 if (attachInfo != null) { 19770 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 19771 } 19772 } 19773 19774 /** 19775 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 19776 * through the event loop. Waits for the specified amount of time.</p> 19777 * 19778 * <p>This method can be invoked from outside of the UI thread 19779 * only when this View is attached to a window.</p> 19780 * 19781 * @param delayMilliseconds the duration in milliseconds to delay the 19782 * invalidation by 19783 * @param left The left coordinate of the rectangle to invalidate. 19784 * @param top The top coordinate of the rectangle to invalidate. 19785 * @param right The right coordinate of the rectangle to invalidate. 19786 * @param bottom The bottom coordinate of the rectangle to invalidate. 19787 * 19788 * @see #invalidate(int, int, int, int) 19789 * @see #invalidate(Rect) 19790 * @see #postInvalidate(int, int, int, int) 19791 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)19792 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 19793 int right, int bottom) { 19794 19795 // We try only with the AttachInfo because there's no point in invalidating 19796 // if we are not attached to our window 19797 final AttachInfo attachInfo = mAttachInfo; 19798 if (attachInfo != null) { 19799 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19800 info.target = this; 19801 info.left = left; 19802 info.top = top; 19803 info.right = right; 19804 info.bottom = bottom; 19805 19806 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 19807 } 19808 } 19809 19810 /** 19811 * <p>Cause an invalidate to happen on the next animation time step, typically the 19812 * next display frame.</p> 19813 * 19814 * <p>This method can be invoked from outside of the UI thread 19815 * only when this View is attached to a window.</p> 19816 * 19817 * @see #invalidate() 19818 */ postInvalidateOnAnimation()19819 public void postInvalidateOnAnimation() { 19820 // We try only with the AttachInfo because there's no point in invalidating 19821 // if we are not attached to our window 19822 final AttachInfo attachInfo = mAttachInfo; 19823 if (attachInfo != null) { 19824 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 19825 } 19826 } 19827 19828 /** 19829 * <p>Cause an invalidate of the specified area to happen on the next animation 19830 * time step, typically the next display frame.</p> 19831 * 19832 * <p>This method can be invoked from outside of the UI thread 19833 * only when this View is attached to a window.</p> 19834 * 19835 * @param left The left coordinate of the rectangle to invalidate. 19836 * @param top The top coordinate of the rectangle to invalidate. 19837 * @param right The right coordinate of the rectangle to invalidate. 19838 * @param bottom The bottom coordinate of the rectangle to invalidate. 19839 * 19840 * @see #invalidate(int, int, int, int) 19841 * @see #invalidate(Rect) 19842 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)19843 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 19844 // We try only with the AttachInfo because there's no point in invalidating 19845 // if we are not attached to our window 19846 final AttachInfo attachInfo = mAttachInfo; 19847 if (attachInfo != null) { 19848 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19849 info.target = this; 19850 info.left = left; 19851 info.top = top; 19852 info.right = right; 19853 info.bottom = bottom; 19854 19855 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 19856 } 19857 } 19858 19859 /** 19860 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 19861 * This event is sent at most once every 19862 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 19863 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)19864 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 19865 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 19866 AccessibilityEvent event = 19867 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 19868 event.setScrollDeltaX(dx); 19869 event.setScrollDeltaY(dy); 19870 sendAccessibilityEventUnchecked(event); 19871 } 19872 } 19873 19874 /** 19875 * Called by a parent to request that a child update its values for mScrollX 19876 * and mScrollY if necessary. This will typically be done if the child is 19877 * animating a scroll using a {@link android.widget.Scroller Scroller} 19878 * object. 19879 */ computeScroll()19880 public void computeScroll() { 19881 } 19882 19883 /** 19884 * <p>Indicate whether the horizontal edges are faded when the view is 19885 * scrolled horizontally.</p> 19886 * 19887 * @return true if the horizontal edges should are faded on scroll, false 19888 * otherwise 19889 * 19890 * @see #setHorizontalFadingEdgeEnabled(boolean) 19891 * 19892 * @attr ref android.R.styleable#View_requiresFadingEdge 19893 */ isHorizontalFadingEdgeEnabled()19894 public boolean isHorizontalFadingEdgeEnabled() { 19895 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 19896 } 19897 19898 /** 19899 * <p>Define whether the horizontal edges should be faded when this view 19900 * is scrolled horizontally.</p> 19901 * 19902 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 19903 * be faded when the view is scrolled 19904 * horizontally 19905 * 19906 * @see #isHorizontalFadingEdgeEnabled() 19907 * 19908 * @attr ref android.R.styleable#View_requiresFadingEdge 19909 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)19910 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 19911 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 19912 if (horizontalFadingEdgeEnabled) { 19913 initScrollCache(); 19914 } 19915 19916 mViewFlags ^= FADING_EDGE_HORIZONTAL; 19917 } 19918 } 19919 19920 /** 19921 * <p>Indicate whether the vertical edges are faded when the view is 19922 * scrolled horizontally.</p> 19923 * 19924 * @return true if the vertical edges should are faded on scroll, false 19925 * otherwise 19926 * 19927 * @see #setVerticalFadingEdgeEnabled(boolean) 19928 * 19929 * @attr ref android.R.styleable#View_requiresFadingEdge 19930 */ isVerticalFadingEdgeEnabled()19931 public boolean isVerticalFadingEdgeEnabled() { 19932 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 19933 } 19934 19935 /** 19936 * <p>Define whether the vertical edges should be faded when this view 19937 * is scrolled vertically.</p> 19938 * 19939 * @param verticalFadingEdgeEnabled true if the vertical edges should 19940 * be faded when the view is scrolled 19941 * vertically 19942 * 19943 * @see #isVerticalFadingEdgeEnabled() 19944 * 19945 * @attr ref android.R.styleable#View_requiresFadingEdge 19946 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)19947 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 19948 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 19949 if (verticalFadingEdgeEnabled) { 19950 initScrollCache(); 19951 } 19952 19953 mViewFlags ^= FADING_EDGE_VERTICAL; 19954 } 19955 } 19956 19957 /** 19958 * Get the fading edge flags, used for inspection. 19959 * 19960 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 19961 * or {@link #FADING_EDGE_HORIZONTAL} 19962 * @hide 19963 */ 19964 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 19965 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 19966 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 19967 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 19968 }) getFadingEdge()19969 public int getFadingEdge() { 19970 return mViewFlags & FADING_EDGE_MASK; 19971 } 19972 19973 /** 19974 * Get the fading edge length, used for inspection 19975 * 19976 * @return The fading edge length or 0 19977 * @hide 19978 */ 19979 @InspectableProperty getFadingEdgeLength()19980 public int getFadingEdgeLength() { 19981 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 19982 return mScrollCache.fadingEdgeLength; 19983 } 19984 return 0; 19985 } 19986 19987 /** 19988 * Returns the strength, or intensity, of the top faded edge. The strength is 19989 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19990 * returns 0.0 or 1.0 but no value in between. 19991 * 19992 * Subclasses should override this method to provide a smoother fade transition 19993 * when scrolling occurs. 19994 * 19995 * @return the intensity of the top fade as a float between 0.0f and 1.0f 19996 */ getTopFadingEdgeStrength()19997 protected float getTopFadingEdgeStrength() { 19998 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 19999 } 20000 20001 /** 20002 * Returns the strength, or intensity, of the bottom faded edge. The strength is 20003 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20004 * returns 0.0 or 1.0 but no value in between. 20005 * 20006 * Subclasses should override this method to provide a smoother fade transition 20007 * when scrolling occurs. 20008 * 20009 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 20010 */ getBottomFadingEdgeStrength()20011 protected float getBottomFadingEdgeStrength() { 20012 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 20013 computeVerticalScrollRange() ? 1.0f : 0.0f; 20014 } 20015 20016 /** 20017 * Returns the strength, or intensity, of the left faded edge. The strength is 20018 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20019 * returns 0.0 or 1.0 but no value in between. 20020 * 20021 * Subclasses should override this method to provide a smoother fade transition 20022 * when scrolling occurs. 20023 * 20024 * @return the intensity of the left fade as a float between 0.0f and 1.0f 20025 */ getLeftFadingEdgeStrength()20026 protected float getLeftFadingEdgeStrength() { 20027 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 20028 } 20029 20030 /** 20031 * Returns the strength, or intensity, of the right faded edge. The strength is 20032 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20033 * returns 0.0 or 1.0 but no value in between. 20034 * 20035 * Subclasses should override this method to provide a smoother fade transition 20036 * when scrolling occurs. 20037 * 20038 * @return the intensity of the right fade as a float between 0.0f and 1.0f 20039 */ getRightFadingEdgeStrength()20040 protected float getRightFadingEdgeStrength() { 20041 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 20042 computeHorizontalScrollRange() ? 1.0f : 0.0f; 20043 } 20044 20045 /** 20046 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 20047 * scrollbar is not drawn by default.</p> 20048 * 20049 * @return true if the horizontal scrollbar should be painted, false 20050 * otherwise 20051 * 20052 * @see #setHorizontalScrollBarEnabled(boolean) 20053 */ isHorizontalScrollBarEnabled()20054 public boolean isHorizontalScrollBarEnabled() { 20055 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 20056 } 20057 20058 /** 20059 * <p>Define whether the horizontal scrollbar should be drawn or not. The 20060 * scrollbar is not drawn by default.</p> 20061 * 20062 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 20063 * be painted 20064 * 20065 * @see #isHorizontalScrollBarEnabled() 20066 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)20067 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 20068 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 20069 mViewFlags ^= SCROLLBARS_HORIZONTAL; 20070 computeOpaqueFlags(); 20071 resolvePadding(); 20072 } 20073 } 20074 20075 /** 20076 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 20077 * scrollbar is not drawn by default.</p> 20078 * 20079 * @return true if the vertical scrollbar should be painted, false 20080 * otherwise 20081 * 20082 * @see #setVerticalScrollBarEnabled(boolean) 20083 */ isVerticalScrollBarEnabled()20084 public boolean isVerticalScrollBarEnabled() { 20085 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 20086 } 20087 20088 /** 20089 * <p>Define whether the vertical scrollbar should be drawn or not. The 20090 * scrollbar is not drawn by default.</p> 20091 * 20092 * @param verticalScrollBarEnabled true if the vertical scrollbar should 20093 * be painted 20094 * 20095 * @see #isVerticalScrollBarEnabled() 20096 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)20097 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 20098 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 20099 mViewFlags ^= SCROLLBARS_VERTICAL; 20100 computeOpaqueFlags(); 20101 resolvePadding(); 20102 } 20103 } 20104 20105 /** 20106 * @hide 20107 */ 20108 @UnsupportedAppUsage recomputePadding()20109 protected void recomputePadding() { 20110 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 20111 } 20112 20113 /** 20114 * Define whether scrollbars will fade when the view is not scrolling. 20115 * 20116 * @param fadeScrollbars whether to enable fading 20117 * 20118 * @attr ref android.R.styleable#View_fadeScrollbars 20119 */ setScrollbarFadingEnabled(boolean fadeScrollbars)20120 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 20121 initScrollCache(); 20122 final ScrollabilityCache scrollabilityCache = mScrollCache; 20123 scrollabilityCache.fadeScrollBars = fadeScrollbars; 20124 if (fadeScrollbars) { 20125 scrollabilityCache.state = ScrollabilityCache.OFF; 20126 } else { 20127 scrollabilityCache.state = ScrollabilityCache.ON; 20128 } 20129 } 20130 20131 /** 20132 * 20133 * Returns true if scrollbars will fade when this view is not scrolling 20134 * 20135 * @return true if scrollbar fading is enabled 20136 * 20137 * @attr ref android.R.styleable#View_fadeScrollbars 20138 */ isScrollbarFadingEnabled()20139 public boolean isScrollbarFadingEnabled() { 20140 return mScrollCache != null && mScrollCache.fadeScrollBars; 20141 } 20142 20143 /** 20144 * 20145 * Returns the delay before scrollbars fade. 20146 * 20147 * @return the delay before scrollbars fade 20148 * 20149 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 20150 */ 20151 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()20152 public int getScrollBarDefaultDelayBeforeFade() { 20153 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 20154 mScrollCache.scrollBarDefaultDelayBeforeFade; 20155 } 20156 20157 /** 20158 * Define the delay before scrollbars fade. 20159 * 20160 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 20161 * 20162 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 20163 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)20164 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 20165 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 20166 } 20167 20168 /** 20169 * 20170 * Returns the scrollbar fade duration. 20171 * 20172 * @return the scrollbar fade duration, in milliseconds 20173 * 20174 * @attr ref android.R.styleable#View_scrollbarFadeDuration 20175 */ 20176 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()20177 public int getScrollBarFadeDuration() { 20178 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 20179 mScrollCache.scrollBarFadeDuration; 20180 } 20181 20182 /** 20183 * Define the scrollbar fade duration. 20184 * 20185 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 20186 * 20187 * @attr ref android.R.styleable#View_scrollbarFadeDuration 20188 */ setScrollBarFadeDuration(int scrollBarFadeDuration)20189 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 20190 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 20191 } 20192 20193 /** 20194 * 20195 * Returns the scrollbar size. 20196 * 20197 * @return the scrollbar size 20198 * 20199 * @attr ref android.R.styleable#View_scrollbarSize 20200 */ 20201 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()20202 public int getScrollBarSize() { 20203 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 20204 mScrollCache.scrollBarSize; 20205 } 20206 20207 /** 20208 * Define the scrollbar size. 20209 * 20210 * @param scrollBarSize - the scrollbar size 20211 * 20212 * @attr ref android.R.styleable#View_scrollbarSize 20213 */ setScrollBarSize(int scrollBarSize)20214 public void setScrollBarSize(int scrollBarSize) { 20215 getScrollCache().scrollBarSize = scrollBarSize; 20216 } 20217 20218 /** 20219 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 20220 * inset. When inset, they add to the padding of the view. And the scrollbars 20221 * can be drawn inside the padding area or on the edge of the view. For example, 20222 * if a view has a background drawable and you want to draw the scrollbars 20223 * inside the padding specified by the drawable, you can use 20224 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 20225 * appear at the edge of the view, ignoring the padding, then you can use 20226 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 20227 * @param style the style of the scrollbars. Should be one of 20228 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 20229 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 20230 * @see #SCROLLBARS_INSIDE_OVERLAY 20231 * @see #SCROLLBARS_INSIDE_INSET 20232 * @see #SCROLLBARS_OUTSIDE_OVERLAY 20233 * @see #SCROLLBARS_OUTSIDE_INSET 20234 * 20235 * @attr ref android.R.styleable#View_scrollbarStyle 20236 */ setScrollBarStyle(@crollBarStyle int style)20237 public void setScrollBarStyle(@ScrollBarStyle int style) { 20238 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 20239 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 20240 computeOpaqueFlags(); 20241 resolvePadding(); 20242 } 20243 } 20244 20245 /** 20246 * <p>Returns the current scrollbar style.</p> 20247 * @return the current scrollbar style 20248 * @see #SCROLLBARS_INSIDE_OVERLAY 20249 * @see #SCROLLBARS_INSIDE_INSET 20250 * @see #SCROLLBARS_OUTSIDE_OVERLAY 20251 * @see #SCROLLBARS_OUTSIDE_INSET 20252 * 20253 * @attr ref android.R.styleable#View_scrollbarStyle 20254 */ 20255 @ViewDebug.ExportedProperty(mapping = { 20256 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 20257 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 20258 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 20259 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 20260 }) 20261 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 20262 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 20263 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 20264 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 20265 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 20266 }) 20267 @ScrollBarStyle getScrollBarStyle()20268 public int getScrollBarStyle() { 20269 return mViewFlags & SCROLLBARS_STYLE_MASK; 20270 } 20271 20272 /** 20273 * <p>Compute the horizontal range that the horizontal scrollbar 20274 * represents.</p> 20275 * 20276 * <p>The range is expressed in arbitrary units that must be the same as the 20277 * units used by {@link #computeHorizontalScrollExtent()} and 20278 * {@link #computeHorizontalScrollOffset()}.</p> 20279 * 20280 * <p>The default range is the drawing width of this view.</p> 20281 * 20282 * @return the total horizontal range represented by the horizontal 20283 * scrollbar 20284 * 20285 * @see #computeHorizontalScrollExtent() 20286 * @see #computeHorizontalScrollOffset() 20287 */ computeHorizontalScrollRange()20288 protected int computeHorizontalScrollRange() { 20289 return getWidth(); 20290 } 20291 20292 /** 20293 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 20294 * within the horizontal range. This value is used to compute the position 20295 * of the thumb within the scrollbar's track.</p> 20296 * 20297 * <p>The range is expressed in arbitrary units that must be the same as the 20298 * units used by {@link #computeHorizontalScrollRange()} and 20299 * {@link #computeHorizontalScrollExtent()}.</p> 20300 * 20301 * <p>The default offset is the scroll offset of this view.</p> 20302 * 20303 * @return the horizontal offset of the scrollbar's thumb 20304 * 20305 * @see #computeHorizontalScrollRange() 20306 * @see #computeHorizontalScrollExtent() 20307 */ computeHorizontalScrollOffset()20308 protected int computeHorizontalScrollOffset() { 20309 return mScrollX; 20310 } 20311 20312 /** 20313 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 20314 * within the horizontal range. This value is used to compute the length 20315 * of the thumb within the scrollbar's track.</p> 20316 * 20317 * <p>The range is expressed in arbitrary units that must be the same as the 20318 * units used by {@link #computeHorizontalScrollRange()} and 20319 * {@link #computeHorizontalScrollOffset()}.</p> 20320 * 20321 * <p>The default extent is the drawing width of this view.</p> 20322 * 20323 * @return the horizontal extent of the scrollbar's thumb 20324 * 20325 * @see #computeHorizontalScrollRange() 20326 * @see #computeHorizontalScrollOffset() 20327 */ computeHorizontalScrollExtent()20328 protected int computeHorizontalScrollExtent() { 20329 return getWidth(); 20330 } 20331 20332 /** 20333 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 20334 * 20335 * <p>The range is expressed in arbitrary units that must be the same as the 20336 * units used by {@link #computeVerticalScrollExtent()} and 20337 * {@link #computeVerticalScrollOffset()}.</p> 20338 * 20339 * @return the total vertical range represented by the vertical scrollbar 20340 * 20341 * <p>The default range is the drawing height of this view.</p> 20342 * 20343 * @see #computeVerticalScrollExtent() 20344 * @see #computeVerticalScrollOffset() 20345 */ computeVerticalScrollRange()20346 protected int computeVerticalScrollRange() { 20347 return getHeight(); 20348 } 20349 20350 /** 20351 * <p>Compute the vertical offset of the vertical scrollbar's thumb 20352 * within the horizontal range. This value is used to compute the position 20353 * of the thumb within the scrollbar's track.</p> 20354 * 20355 * <p>The range is expressed in arbitrary units that must be the same as the 20356 * units used by {@link #computeVerticalScrollRange()} and 20357 * {@link #computeVerticalScrollExtent()}.</p> 20358 * 20359 * <p>The default offset is the scroll offset of this view.</p> 20360 * 20361 * @return the vertical offset of the scrollbar's thumb 20362 * 20363 * @see #computeVerticalScrollRange() 20364 * @see #computeVerticalScrollExtent() 20365 */ computeVerticalScrollOffset()20366 protected int computeVerticalScrollOffset() { 20367 return mScrollY; 20368 } 20369 20370 /** 20371 * <p>Compute the vertical extent of the vertical scrollbar's thumb 20372 * within the vertical range. This value is used to compute the length 20373 * of the thumb within the scrollbar's track.</p> 20374 * 20375 * <p>The range is expressed in arbitrary units that must be the same as the 20376 * units used by {@link #computeVerticalScrollRange()} and 20377 * {@link #computeVerticalScrollOffset()}.</p> 20378 * 20379 * <p>The default extent is the drawing height of this view.</p> 20380 * 20381 * @return the vertical extent of the scrollbar's thumb 20382 * 20383 * @see #computeVerticalScrollRange() 20384 * @see #computeVerticalScrollOffset() 20385 */ computeVerticalScrollExtent()20386 protected int computeVerticalScrollExtent() { 20387 return getHeight(); 20388 } 20389 20390 /** 20391 * Check if this view can be scrolled horizontally in a certain direction. 20392 * 20393 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 20394 * in response to user input or not. 20395 * 20396 * @param direction Negative to check scrolling left, positive to check scrolling right. 20397 * @return true if this view can be scrolled in the specified direction, false otherwise. 20398 */ canScrollHorizontally(int direction)20399 public boolean canScrollHorizontally(int direction) { 20400 final int offset = computeHorizontalScrollOffset(); 20401 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 20402 if (range == 0) return false; 20403 if (direction < 0) { 20404 return offset > 0; 20405 } else { 20406 return offset < range - 1; 20407 } 20408 } 20409 20410 /** 20411 * Check if this view can be scrolled vertically in a certain direction. 20412 * 20413 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 20414 * in response to user input or not. 20415 * 20416 * @param direction Negative to check scrolling up, positive to check scrolling down. 20417 * @return true if this view can be scrolled in the specified direction, false otherwise. 20418 */ canScrollVertically(int direction)20419 public boolean canScrollVertically(int direction) { 20420 final int offset = computeVerticalScrollOffset(); 20421 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 20422 if (range == 0) return false; 20423 if (direction < 0) { 20424 return offset > 0; 20425 } else { 20426 return offset < range - 1; 20427 } 20428 } 20429 getScrollIndicatorBounds(@onNull Rect out)20430 void getScrollIndicatorBounds(@NonNull Rect out) { 20431 out.left = mScrollX; 20432 out.right = mScrollX + mRight - mLeft; 20433 out.top = mScrollY; 20434 out.bottom = mScrollY + mBottom - mTop; 20435 } 20436 onDrawScrollIndicators(Canvas c)20437 private void onDrawScrollIndicators(Canvas c) { 20438 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 20439 // No scroll indicators enabled. 20440 return; 20441 } 20442 20443 final Drawable dr = mScrollIndicatorDrawable; 20444 if (dr == null) { 20445 // Scroll indicators aren't supported here. 20446 return; 20447 } 20448 20449 if (mAttachInfo == null) { 20450 // View is not attached. 20451 return; 20452 } 20453 20454 final int h = dr.getIntrinsicHeight(); 20455 final int w = dr.getIntrinsicWidth(); 20456 final Rect rect = mAttachInfo.mTmpInvalRect; 20457 getScrollIndicatorBounds(rect); 20458 20459 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 20460 final boolean canScrollUp = canScrollVertically(-1); 20461 if (canScrollUp) { 20462 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 20463 dr.draw(c); 20464 } 20465 } 20466 20467 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 20468 final boolean canScrollDown = canScrollVertically(1); 20469 if (canScrollDown) { 20470 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 20471 dr.draw(c); 20472 } 20473 } 20474 20475 final int leftRtl; 20476 final int rightRtl; 20477 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 20478 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 20479 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 20480 } else { 20481 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 20482 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 20483 } 20484 20485 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 20486 if ((mPrivateFlags3 & leftMask) != 0) { 20487 final boolean canScrollLeft = canScrollHorizontally(-1); 20488 if (canScrollLeft) { 20489 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 20490 dr.draw(c); 20491 } 20492 } 20493 20494 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 20495 if ((mPrivateFlags3 & rightMask) != 0) { 20496 final boolean canScrollRight = canScrollHorizontally(1); 20497 if (canScrollRight) { 20498 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 20499 dr.draw(c); 20500 } 20501 } 20502 } 20503 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)20504 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 20505 @Nullable Rect touchBounds) { 20506 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 20507 if (bounds == null) { 20508 return; 20509 } 20510 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 20511 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 20512 && !isVerticalScrollBarHidden(); 20513 final int size = getHorizontalScrollbarHeight(); 20514 final int verticalScrollBarGap = drawVerticalScrollBar ? 20515 getVerticalScrollbarWidth() : 0; 20516 final int width = mRight - mLeft; 20517 final int height = mBottom - mTop; 20518 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 20519 bounds.left = mScrollX + (mPaddingLeft & inside); 20520 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 20521 bounds.bottom = bounds.top + size; 20522 20523 if (touchBounds == null) { 20524 return; 20525 } 20526 if (touchBounds != bounds) { 20527 touchBounds.set(bounds); 20528 } 20529 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 20530 if (touchBounds.height() < minTouchTarget) { 20531 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 20532 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 20533 touchBounds.top = touchBounds.bottom - minTouchTarget; 20534 } 20535 if (touchBounds.width() < minTouchTarget) { 20536 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 20537 touchBounds.left -= adjust; 20538 touchBounds.right = touchBounds.left + minTouchTarget; 20539 } 20540 } 20541 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)20542 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 20543 if (mRoundScrollbarRenderer == null) { 20544 getStraightVerticalScrollBarBounds(bounds, touchBounds); 20545 } else { 20546 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 20547 } 20548 } 20549 getRoundVerticalScrollBarBounds(Rect bounds)20550 private void getRoundVerticalScrollBarBounds(Rect bounds) { 20551 final int width = mRight - mLeft; 20552 final int height = mBottom - mTop; 20553 // Do not take padding into account as we always want the scrollbars 20554 // to hug the screen for round wearable devices. 20555 bounds.left = mScrollX; 20556 bounds.top = mScrollY; 20557 bounds.right = bounds.left + width; 20558 bounds.bottom = mScrollY + height; 20559 } 20560 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)20561 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 20562 @Nullable Rect touchBounds) { 20563 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 20564 if (bounds == null) { 20565 return; 20566 } 20567 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 20568 final int size = getVerticalScrollbarWidth(); 20569 int verticalScrollbarPosition = mVerticalScrollbarPosition; 20570 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 20571 verticalScrollbarPosition = isLayoutRtl() ? 20572 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 20573 } 20574 final int width = mRight - mLeft; 20575 final int height = mBottom - mTop; 20576 switch (verticalScrollbarPosition) { 20577 default: 20578 case SCROLLBAR_POSITION_RIGHT: 20579 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 20580 break; 20581 case SCROLLBAR_POSITION_LEFT: 20582 bounds.left = mScrollX + (mUserPaddingLeft & inside); 20583 break; 20584 } 20585 bounds.top = mScrollY + (mPaddingTop & inside); 20586 bounds.right = bounds.left + size; 20587 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 20588 20589 if (touchBounds == null) { 20590 return; 20591 } 20592 if (touchBounds != bounds) { 20593 touchBounds.set(bounds); 20594 } 20595 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 20596 if (touchBounds.width() < minTouchTarget) { 20597 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 20598 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 20599 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 20600 touchBounds.left = touchBounds.right - minTouchTarget; 20601 } else { 20602 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 20603 touchBounds.right = touchBounds.left + minTouchTarget; 20604 } 20605 } 20606 if (touchBounds.height() < minTouchTarget) { 20607 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 20608 touchBounds.top -= adjust; 20609 touchBounds.bottom = touchBounds.top + minTouchTarget; 20610 } 20611 } 20612 20613 /** 20614 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 20615 * scrollbars are painted only if they have been awakened first.</p> 20616 * 20617 * @param canvas the canvas on which to draw the scrollbars 20618 * 20619 * @see #awakenScrollBars(int) 20620 */ onDrawScrollBars(Canvas canvas)20621 protected final void onDrawScrollBars(Canvas canvas) { 20622 // scrollbars are drawn only when the animation is running 20623 final ScrollabilityCache cache = mScrollCache; 20624 20625 if (cache != null) { 20626 20627 int state = cache.state; 20628 20629 if (state == ScrollabilityCache.OFF) { 20630 return; 20631 } 20632 20633 boolean invalidate = false; 20634 20635 if (state == ScrollabilityCache.FADING) { 20636 // We're fading -- get our fade interpolation 20637 if (cache.interpolatorValues == null) { 20638 cache.interpolatorValues = new float[1]; 20639 } 20640 20641 float[] values = cache.interpolatorValues; 20642 20643 // Stops the animation if we're done 20644 if (cache.scrollBarInterpolator.timeToValues(values) == 20645 Interpolator.Result.FREEZE_END) { 20646 cache.state = ScrollabilityCache.OFF; 20647 } else { 20648 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 20649 } 20650 20651 // This will make the scroll bars inval themselves after 20652 // drawing. We only want this when we're fading so that 20653 // we prevent excessive redraws 20654 invalidate = true; 20655 } else { 20656 // We're just on -- but we may have been fading before so 20657 // reset alpha 20658 cache.scrollBar.mutate().setAlpha(255); 20659 } 20660 20661 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 20662 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 20663 && !isVerticalScrollBarHidden(); 20664 20665 // Fork out the scroll bar drawing for round wearable devices. 20666 if (mRoundScrollbarRenderer != null) { 20667 if (drawVerticalScrollBar) { 20668 final Rect bounds = cache.mScrollBarBounds; 20669 getVerticalScrollBarBounds(bounds, null); 20670 mRoundScrollbarRenderer.drawRoundScrollbars( 20671 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 20672 if (invalidate) { 20673 invalidate(); 20674 } 20675 } 20676 // Do not draw horizontal scroll bars for round wearable devices. 20677 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 20678 final ScrollBarDrawable scrollBar = cache.scrollBar; 20679 20680 if (drawHorizontalScrollBar) { 20681 scrollBar.setParameters(computeHorizontalScrollRange(), 20682 computeHorizontalScrollOffset(), 20683 computeHorizontalScrollExtent(), false); 20684 final Rect bounds = cache.mScrollBarBounds; 20685 getHorizontalScrollBarBounds(bounds, null); 20686 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 20687 bounds.right, bounds.bottom); 20688 if (invalidate) { 20689 invalidate(bounds); 20690 } 20691 } 20692 20693 if (drawVerticalScrollBar) { 20694 scrollBar.setParameters(computeVerticalScrollRange(), 20695 computeVerticalScrollOffset(), 20696 computeVerticalScrollExtent(), true); 20697 final Rect bounds = cache.mScrollBarBounds; 20698 getVerticalScrollBarBounds(bounds, null); 20699 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 20700 bounds.right, bounds.bottom); 20701 if (invalidate) { 20702 invalidate(bounds); 20703 } 20704 } 20705 } 20706 } 20707 } 20708 20709 /** 20710 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 20711 * FastScroller is visible. 20712 * @return whether to temporarily hide the vertical scrollbar 20713 * @hide 20714 */ isVerticalScrollBarHidden()20715 protected boolean isVerticalScrollBarHidden() { 20716 return false; 20717 } 20718 20719 /** 20720 * <p>Draw the horizontal scrollbar if 20721 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 20722 * 20723 * @param canvas the canvas on which to draw the scrollbar 20724 * @param scrollBar the scrollbar's drawable 20725 * 20726 * @see #isHorizontalScrollBarEnabled() 20727 * @see #computeHorizontalScrollRange() 20728 * @see #computeHorizontalScrollExtent() 20729 * @see #computeHorizontalScrollOffset() 20730 * @hide 20731 */ 20732 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)20733 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 20734 int l, int t, int r, int b) { 20735 scrollBar.setBounds(l, t, r, b); 20736 scrollBar.draw(canvas); 20737 } 20738 20739 /** 20740 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 20741 * returns true.</p> 20742 * 20743 * @param canvas the canvas on which to draw the scrollbar 20744 * @param scrollBar the scrollbar's drawable 20745 * 20746 * @see #isVerticalScrollBarEnabled() 20747 * @see #computeVerticalScrollRange() 20748 * @see #computeVerticalScrollExtent() 20749 * @see #computeVerticalScrollOffset() 20750 * @hide 20751 */ 20752 @UnsupportedAppUsage onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)20753 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 20754 int l, int t, int r, int b) { 20755 scrollBar.setBounds(l, t, r, b); 20756 scrollBar.draw(canvas); 20757 } 20758 20759 /** 20760 * Implement this to do your drawing. 20761 * 20762 * @param canvas the canvas on which the background will be drawn 20763 */ onDraw(Canvas canvas)20764 protected void onDraw(Canvas canvas) { 20765 } 20766 20767 /* 20768 * Caller is responsible for calling requestLayout if necessary. 20769 * (This allows addViewInLayout to not request a new layout.) 20770 */ 20771 @UnsupportedAppUsage assignParent(ViewParent parent)20772 void assignParent(ViewParent parent) { 20773 if (mParent == null) { 20774 mParent = parent; 20775 } else if (parent == null) { 20776 mParent = null; 20777 } else { 20778 throw new RuntimeException("view " + this + " being added, but" 20779 + " it already has a parent"); 20780 } 20781 } 20782 20783 /** 20784 * This is called when the view is attached to a window. At this point it 20785 * has a Surface and will start drawing. Note that this function is 20786 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 20787 * however it may be called any time before the first onDraw -- including 20788 * before or after {@link #onMeasure(int, int)}. 20789 * 20790 * @see #onDetachedFromWindow() 20791 */ 20792 @CallSuper onAttachedToWindow()20793 protected void onAttachedToWindow() { 20794 if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 20795 mParent.requestTransparentRegion(this); 20796 } 20797 20798 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 20799 20800 jumpDrawablesToCurrentState(); 20801 20802 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 20803 resetSubtreeAccessibilityStateChanged(); 20804 20805 // rebuild, since Outline not maintained while View is detached 20806 rebuildOutline(); 20807 20808 if (isFocused()) { 20809 notifyFocusChangeToImeFocusController(true /* hasFocus */); 20810 } 20811 20812 if (sTraceLayoutSteps) { 20813 setTraversalTracingEnabled(true); 20814 } 20815 if (sTraceRequestLayoutClass != null 20816 && sTraceRequestLayoutClass.equals(getClass().getSimpleName())) { 20817 setRelayoutTracingEnabled(true); 20818 } 20819 } 20820 20821 /** 20822 * Resolve all RTL related properties. 20823 * 20824 * @return true if resolution of RTL properties has been done 20825 * 20826 * @hide 20827 */ resolveRtlPropertiesIfNeeded()20828 public boolean resolveRtlPropertiesIfNeeded() { 20829 if (!needRtlPropertiesResolution()) return false; 20830 20831 // Order is important here: LayoutDirection MUST be resolved first 20832 if (!isLayoutDirectionResolved()) { 20833 resolveLayoutDirection(); 20834 resolveLayoutParams(); 20835 } 20836 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 20837 if (!isTextDirectionResolved()) { 20838 resolveTextDirection(); 20839 } 20840 if (!isTextAlignmentResolved()) { 20841 resolveTextAlignment(); 20842 } 20843 // Should resolve Drawables before Padding because we need the layout direction of the 20844 // Drawable to correctly resolve Padding. 20845 if (!areDrawablesResolved()) { 20846 resolveDrawables(); 20847 } 20848 if (!isPaddingResolved()) { 20849 resolvePadding(); 20850 } 20851 onRtlPropertiesChanged(getLayoutDirection()); 20852 return true; 20853 } 20854 20855 /** 20856 * Reset resolution of all RTL related properties. 20857 * 20858 * @hide 20859 */ 20860 @TestApi resetRtlProperties()20861 public void resetRtlProperties() { 20862 resetResolvedLayoutDirection(); 20863 resetResolvedTextDirection(); 20864 resetResolvedTextAlignment(); 20865 resetResolvedPadding(); 20866 resetResolvedDrawables(); 20867 } 20868 20869 /** 20870 * @see #onScreenStateChanged(int) 20871 */ dispatchScreenStateChanged(int screenState)20872 void dispatchScreenStateChanged(int screenState) { 20873 onScreenStateChanged(screenState); 20874 } 20875 20876 /** 20877 * This method is called whenever the state of the screen this view is 20878 * attached to changes. A state change will usually occurs when the screen 20879 * turns on or off (whether it happens automatically or the user does it 20880 * manually.) 20881 * 20882 * @param screenState The new state of the screen. Can be either 20883 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 20884 */ onScreenStateChanged(int screenState)20885 public void onScreenStateChanged(int screenState) { 20886 } 20887 20888 /** 20889 * @see #onMovedToDisplay(int, Configuration) 20890 */ dispatchMovedToDisplay(Display display, Configuration config)20891 void dispatchMovedToDisplay(Display display, Configuration config) { 20892 mAttachInfo.mDisplay = display; 20893 mAttachInfo.mDisplayState = display.getState(); 20894 onMovedToDisplay(display.getDisplayId(), config); 20895 } 20896 20897 /** 20898 * Called by the system when the hosting activity is moved from one display to another without 20899 * recreation. This means that the activity is declared to handle all changes to configuration 20900 * that happened when it was switched to another display, so it wasn't destroyed and created 20901 * again. 20902 * 20903 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 20904 * applied configuration actually changed. It is up to app developer to choose whether to handle 20905 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 20906 * call. 20907 * 20908 * <p>Use this callback to track changes to the displays if some functionality relies on an 20909 * association with some display properties. 20910 * 20911 * @param displayId The id of the display to which the view was moved. 20912 * @param config Configuration of the resources on new display after move. 20913 * 20914 * @see #onConfigurationChanged(Configuration) 20915 * @hide 20916 */ onMovedToDisplay(int displayId, Configuration config)20917 public void onMovedToDisplay(int displayId, Configuration config) { 20918 } 20919 20920 /** 20921 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 20922 */ 20923 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hasRtlSupport()20924 private boolean hasRtlSupport() { 20925 return mContext.getApplicationInfo().hasRtlSupport(); 20926 } 20927 20928 /** 20929 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 20930 * RTL not supported) 20931 */ isRtlCompatibilityMode()20932 private boolean isRtlCompatibilityMode() { 20933 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 20934 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 20935 } 20936 20937 /** 20938 * @return true if RTL properties need resolution. 20939 * 20940 */ needRtlPropertiesResolution()20941 private boolean needRtlPropertiesResolution() { 20942 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 20943 } 20944 20945 /** 20946 * Called when any RTL property (layout direction or text direction or text alignment) has 20947 * been changed. 20948 * 20949 * Subclasses need to override this method to take care of cached information that depends on the 20950 * resolved layout direction, or to inform child views that inherit their layout direction. 20951 * 20952 * The default implementation does nothing. 20953 * 20954 * @param layoutDirection the direction of the layout 20955 * 20956 * @see #LAYOUT_DIRECTION_LTR 20957 * @see #LAYOUT_DIRECTION_RTL 20958 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)20959 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 20960 } 20961 20962 /** 20963 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 20964 * that the parent directionality can and will be resolved before its children. 20965 * 20966 * @return true if resolution has been done, false otherwise. 20967 * 20968 * @hide 20969 */ resolveLayoutDirection()20970 public boolean resolveLayoutDirection() { 20971 // Clear any previous layout direction resolution 20972 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20973 20974 if (hasRtlSupport()) { 20975 // Set resolved depending on layout direction 20976 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 20977 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 20978 case LAYOUT_DIRECTION_INHERIT: 20979 // We cannot resolve yet. LTR is by default and let the resolution happen again 20980 // later to get the correct resolved value 20981 if (!canResolveLayoutDirection()) return false; 20982 20983 // Parent has not yet resolved, LTR is still the default 20984 try { 20985 if (!mParent.isLayoutDirectionResolved()) return false; 20986 20987 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 20988 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20989 } 20990 } catch (AbstractMethodError e) { 20991 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20992 " does not fully implement ViewParent", e); 20993 } 20994 break; 20995 case LAYOUT_DIRECTION_RTL: 20996 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20997 break; 20998 case LAYOUT_DIRECTION_LOCALE: 20999 if((LAYOUT_DIRECTION_RTL == 21000 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 21001 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 21002 } 21003 break; 21004 default: 21005 // Nothing to do, LTR by default 21006 } 21007 } 21008 21009 // Set to resolved 21010 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 21011 return true; 21012 } 21013 21014 /** 21015 * Check if layout direction resolution can be done. 21016 * 21017 * @return true if layout direction resolution can be done otherwise return false. 21018 */ canResolveLayoutDirection()21019 public boolean canResolveLayoutDirection() { 21020 switch (getRawLayoutDirection()) { 21021 case LAYOUT_DIRECTION_INHERIT: 21022 if (mParent != null) { 21023 try { 21024 return mParent.canResolveLayoutDirection(); 21025 } catch (AbstractMethodError e) { 21026 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21027 " does not fully implement ViewParent", e); 21028 } 21029 } 21030 return false; 21031 21032 default: 21033 return true; 21034 } 21035 } 21036 21037 /** 21038 * Reset the resolved layout direction. Layout direction will be resolved during a call to 21039 * {@link #onMeasure(int, int)}. 21040 * 21041 * @hide 21042 */ 21043 @TestApi resetResolvedLayoutDirection()21044 public void resetResolvedLayoutDirection() { 21045 // Reset the current resolved bits 21046 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 21047 } 21048 21049 /** 21050 * @return true if the layout direction is inherited. 21051 * 21052 * @hide 21053 */ isLayoutDirectionInherited()21054 public boolean isLayoutDirectionInherited() { 21055 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 21056 } 21057 21058 /** 21059 * @return true if layout direction has been resolved. 21060 */ isLayoutDirectionResolved()21061 public boolean isLayoutDirectionResolved() { 21062 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 21063 } 21064 21065 /** 21066 * Return if padding has been resolved 21067 * 21068 * @hide 21069 */ 21070 @UnsupportedAppUsage isPaddingResolved()21071 boolean isPaddingResolved() { 21072 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 21073 } 21074 21075 /** 21076 * Resolves padding depending on layout direction, if applicable, and 21077 * recomputes internal padding values to adjust for scroll bars. 21078 * 21079 * @hide 21080 */ 21081 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolvePadding()21082 public void resolvePadding() { 21083 final int resolvedLayoutDirection = getLayoutDirection(); 21084 21085 if (!isRtlCompatibilityMode()) { 21086 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 21087 // If start / end padding are defined, they will be resolved (hence overriding) to 21088 // left / right or right / left depending on the resolved layout direction. 21089 // If start / end padding are not defined, use the left / right ones. 21090 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 21091 Rect padding = sThreadLocal.get(); 21092 if (padding == null) { 21093 padding = new Rect(); 21094 sThreadLocal.set(padding); 21095 } 21096 mBackground.getPadding(padding); 21097 if (!mLeftPaddingDefined) { 21098 mUserPaddingLeftInitial = padding.left; 21099 } 21100 if (!mRightPaddingDefined) { 21101 mUserPaddingRightInitial = padding.right; 21102 } 21103 } 21104 switch (resolvedLayoutDirection) { 21105 case LAYOUT_DIRECTION_RTL: 21106 if (mUserPaddingStart != UNDEFINED_PADDING) { 21107 mUserPaddingRight = mUserPaddingStart; 21108 } else { 21109 mUserPaddingRight = mUserPaddingRightInitial; 21110 } 21111 if (mUserPaddingEnd != UNDEFINED_PADDING) { 21112 mUserPaddingLeft = mUserPaddingEnd; 21113 } else { 21114 mUserPaddingLeft = mUserPaddingLeftInitial; 21115 } 21116 break; 21117 case LAYOUT_DIRECTION_LTR: 21118 default: 21119 if (mUserPaddingStart != UNDEFINED_PADDING) { 21120 mUserPaddingLeft = mUserPaddingStart; 21121 } else { 21122 mUserPaddingLeft = mUserPaddingLeftInitial; 21123 } 21124 if (mUserPaddingEnd != UNDEFINED_PADDING) { 21125 mUserPaddingRight = mUserPaddingEnd; 21126 } else { 21127 mUserPaddingRight = mUserPaddingRightInitial; 21128 } 21129 } 21130 21131 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 21132 } 21133 21134 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 21135 onRtlPropertiesChanged(resolvedLayoutDirection); 21136 21137 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 21138 } 21139 21140 /** 21141 * Reset the resolved layout direction. 21142 * 21143 * @hide 21144 */ 21145 @TestApi resetResolvedPadding()21146 public void resetResolvedPadding() { 21147 resetResolvedPaddingInternal(); 21148 } 21149 21150 /** 21151 * Used when we only want to reset *this* view's padding and not trigger overrides 21152 * in ViewGroup that reset children too. 21153 */ resetResolvedPaddingInternal()21154 void resetResolvedPaddingInternal() { 21155 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 21156 } 21157 21158 /** 21159 * This is called when the view is detached from a window. At this point it 21160 * no longer has a surface for drawing. 21161 * 21162 * @see #onAttachedToWindow() 21163 */ 21164 @CallSuper onDetachedFromWindow()21165 protected void onDetachedFromWindow() { 21166 } 21167 21168 /** 21169 * This is a framework-internal mirror of onDetachedFromWindow() that's called 21170 * after onDetachedFromWindow(). 21171 * 21172 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 21173 * The super method should be called at the end of the overridden method to ensure 21174 * subclasses are destroyed first 21175 * 21176 * @hide 21177 */ 21178 @CallSuper 21179 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()21180 protected void onDetachedFromWindowInternal() { 21181 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 21182 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 21183 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 21184 21185 removeUnsetPressCallback(); 21186 removeLongPressCallback(); 21187 removePerformClickCallback(); 21188 clearAccessibilityThrottles(); 21189 stopNestedScroll(); 21190 21191 // Anything that started animating right before detach should already 21192 // be in its final state when re-attached. 21193 jumpDrawablesToCurrentState(); 21194 21195 destroyDrawingCache(); 21196 21197 cleanupDraw(); 21198 mCurrentAnimation = null; 21199 21200 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 21201 hideTooltip(); 21202 } 21203 21204 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 21205 21206 if (mBackgroundRenderNode != null) { 21207 mBackgroundRenderNode.forceEndAnimators(); 21208 } 21209 mRenderNode.forceEndAnimators(); 21210 } 21211 cleanupDraw()21212 private void cleanupDraw() { 21213 resetDisplayList(); 21214 if (mAttachInfo != null) { 21215 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 21216 } 21217 } 21218 invalidateInheritedLayoutMode(int layoutModeOfRoot)21219 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 21220 } 21221 21222 /** 21223 * @return The number of times this view has been attached to a window 21224 */ getWindowAttachCount()21225 protected int getWindowAttachCount() { 21226 return mWindowAttachCount; 21227 } 21228 21229 /** 21230 * Retrieve a unique token identifying the window this view is attached to. 21231 * @return Return the window's token for use in 21232 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 21233 */ getWindowToken()21234 public IBinder getWindowToken() { 21235 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 21236 } 21237 21238 /** 21239 * Retrieve the {@link WindowId} for the window this view is 21240 * currently attached to. 21241 */ getWindowId()21242 public WindowId getWindowId() { 21243 AttachInfo ai = mAttachInfo; 21244 if (ai == null) { 21245 return null; 21246 } 21247 if (ai.mWindowId == null) { 21248 try { 21249 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 21250 if (ai.mIWindowId != null) { 21251 ai.mWindowId = new WindowId(ai.mIWindowId); 21252 } 21253 } catch (RemoteException e) { 21254 } 21255 } 21256 return ai.mWindowId; 21257 } 21258 21259 /** 21260 * Retrieve a unique token identifying the top-level "real" window of 21261 * the window that this view is attached to. That is, this is like 21262 * {@link #getWindowToken}, except if the window this view in is a panel 21263 * window (attached to another containing window), then the token of 21264 * the containing window is returned instead. 21265 * 21266 * @return Returns the associated window token, either 21267 * {@link #getWindowToken()} or the containing window's token. 21268 */ getApplicationWindowToken()21269 public IBinder getApplicationWindowToken() { 21270 AttachInfo ai = mAttachInfo; 21271 if (ai != null) { 21272 IBinder appWindowToken = ai.mPanelParentWindowToken; 21273 if (appWindowToken == null) { 21274 appWindowToken = ai.mWindowToken; 21275 } 21276 return appWindowToken; 21277 } 21278 return null; 21279 } 21280 21281 /** 21282 * Gets the logical display to which the view's window has been attached. 21283 * 21284 * @return The logical display, or null if the view is not currently attached to a window. 21285 */ getDisplay()21286 public Display getDisplay() { 21287 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 21288 } 21289 21290 /** 21291 * Retrieve private session object this view hierarchy is using to 21292 * communicate with the window manager. 21293 * @return the session object to communicate with the window manager 21294 */ 21295 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()21296 /*package*/ IWindowSession getWindowSession() { 21297 return mAttachInfo != null ? mAttachInfo.mSession : null; 21298 } 21299 21300 /** 21301 * Return the window this view is currently attached to. 21302 * @hide 21303 */ getWindow()21304 protected IWindow getWindow() { 21305 return mAttachInfo != null ? mAttachInfo.mWindow : null; 21306 } 21307 21308 /** 21309 * Return the visibility value of the least visible component passed. 21310 */ combineVisibility(int vis1, int vis2)21311 int combineVisibility(int vis1, int vis2) { 21312 // This works because VISIBLE < INVISIBLE < GONE. 21313 return Math.max(vis1, vis2); 21314 } 21315 21316 private boolean mShouldFakeFocus = false; 21317 21318 /** 21319 * Fake send a focus event after attaching to window. 21320 * See {@link android.view.ViewRootImpl#dispatchCompatFakeFocus()} for details. 21321 * @hide 21322 */ fakeFocusAfterAttachingToWindow()21323 public void fakeFocusAfterAttachingToWindow() { 21324 mShouldFakeFocus = true; 21325 } 21326 21327 /** 21328 * @param info the {@link android.view.View.AttachInfo} to associated with 21329 * this view 21330 */ 21331 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)21332 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 21333 mAttachInfo = info; 21334 if (mOverlay != null) { 21335 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 21336 } 21337 mWindowAttachCount++; 21338 // We will need to evaluate the drawable state at least once. 21339 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 21340 if (mFloatingTreeObserver != null) { 21341 info.mTreeObserver.merge(mFloatingTreeObserver); 21342 mFloatingTreeObserver = null; 21343 } 21344 21345 registerPendingFrameMetricsObservers(); 21346 21347 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 21348 mAttachInfo.mScrollContainers.add(this); 21349 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 21350 } 21351 // Transfer all pending runnables. 21352 if (mRunQueue != null) { 21353 mRunQueue.executeActions(info.mHandler); 21354 mRunQueue = null; 21355 } 21356 performCollectViewAttributes(mAttachInfo, visibility); 21357 onAttachedToWindow(); 21358 21359 ListenerInfo li = mListenerInfo; 21360 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 21361 li != null ? li.mOnAttachStateChangeListeners : null; 21362 if (listeners != null && listeners.size() > 0) { 21363 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 21364 // perform the dispatching. The iterator is a safe guard against listeners that 21365 // could mutate the list by calling the various add/remove methods. This prevents 21366 // the array from being modified while we iterate it. 21367 for (OnAttachStateChangeListener listener : listeners) { 21368 listener.onViewAttachedToWindow(this); 21369 } 21370 } 21371 21372 int vis = info.mWindowVisibility; 21373 if (vis != GONE) { 21374 onWindowVisibilityChanged(vis); 21375 if (isShown()) { 21376 // Calling onVisibilityAggregated directly here since the subtree will also 21377 // receive dispatchAttachedToWindow and this same call 21378 onVisibilityAggregated(vis == VISIBLE); 21379 } 21380 } 21381 21382 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 21383 // As all views in the subtree will already receive dispatchAttachedToWindow 21384 // traversing the subtree again here is not desired. 21385 onVisibilityChanged(this, visibility); 21386 21387 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 21388 // If nobody has evaluated the drawable state yet, then do it now. 21389 refreshDrawableState(); 21390 } 21391 needGlobalAttributesUpdate(false); 21392 21393 notifyEnterOrExitForAutoFillIfNeeded(true); 21394 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 21395 21396 if (mShouldFakeFocus) { 21397 getViewRootImpl().dispatchCompatFakeFocus(); 21398 mShouldFakeFocus = false; 21399 } 21400 } 21401 21402 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()21403 void dispatchDetachedFromWindow() { 21404 AttachInfo info = mAttachInfo; 21405 if (info != null) { 21406 int vis = info.mWindowVisibility; 21407 if (vis != GONE) { 21408 onWindowVisibilityChanged(GONE); 21409 if (isShown()) { 21410 // Invoking onVisibilityAggregated directly here since the subtree 21411 // will also receive detached from window 21412 onVisibilityAggregated(false); 21413 } 21414 } 21415 } 21416 21417 onDetachedFromWindow(); 21418 onDetachedFromWindowInternal(); 21419 21420 if (info != null) { 21421 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 21422 } 21423 21424 ListenerInfo li = mListenerInfo; 21425 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 21426 li != null ? li.mOnAttachStateChangeListeners : null; 21427 if (listeners != null && listeners.size() > 0) { 21428 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 21429 // perform the dispatching. The iterator is a safe guard against listeners that 21430 // could mutate the list by calling the various add/remove methods. This prevents 21431 // the array from being modified while we iterate it. 21432 for (OnAttachStateChangeListener listener : listeners) { 21433 listener.onViewDetachedFromWindow(this); 21434 } 21435 } 21436 21437 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 21438 mAttachInfo.mScrollContainers.remove(this); 21439 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 21440 } 21441 21442 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 21443 21444 mAttachInfo = null; 21445 if (mOverlay != null) { 21446 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 21447 } 21448 21449 notifyEnterOrExitForAutoFillIfNeeded(false); 21450 21451 if (info != null && !collectPreferKeepClearRects().isEmpty()) { 21452 info.mViewRootImpl.updateKeepClearRectsForView(this); 21453 } 21454 } 21455 21456 /** 21457 * Cancel any deferred high-level input events that were previously posted to the event queue. 21458 * 21459 * <p>Many views post high-level events such as click handlers to the event queue 21460 * to run deferred in order to preserve a desired user experience - clearing visible 21461 * pressed states before executing, etc. This method will abort any events of this nature 21462 * that are currently in flight.</p> 21463 * 21464 * <p>Custom views that generate their own high-level deferred input events should override 21465 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 21466 * 21467 * <p>This will also cancel pending input events for any child views.</p> 21468 * 21469 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 21470 * This will not impact newer events posted after this call that may occur as a result of 21471 * lower-level input events still waiting in the queue. If you are trying to prevent 21472 * double-submitted events for the duration of some sort of asynchronous transaction 21473 * you should also take other steps to protect against unexpected double inputs e.g. calling 21474 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 21475 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 21476 */ cancelPendingInputEvents()21477 public final void cancelPendingInputEvents() { 21478 dispatchCancelPendingInputEvents(); 21479 } 21480 21481 /** 21482 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 21483 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 21484 */ dispatchCancelPendingInputEvents()21485 void dispatchCancelPendingInputEvents() { 21486 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 21487 onCancelPendingInputEvents(); 21488 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 21489 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 21490 " did not call through to super.onCancelPendingInputEvents()"); 21491 } 21492 } 21493 21494 /** 21495 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 21496 * a parent view. 21497 * 21498 * <p>This method is responsible for removing any pending high-level input events that were 21499 * posted to the event queue to run later. Custom view classes that post their own deferred 21500 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 21501 * {@link android.os.Handler} should override this method, call 21502 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 21503 * </p> 21504 */ onCancelPendingInputEvents()21505 public void onCancelPendingInputEvents() { 21506 removePerformClickCallback(); 21507 cancelLongPress(); 21508 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 21509 } 21510 21511 /** 21512 * Store this view hierarchy's frozen state into the given container. 21513 * 21514 * @param container The SparseArray in which to save the view's state. 21515 * 21516 * @see #restoreHierarchyState(android.util.SparseArray) 21517 * @see #dispatchSaveInstanceState(android.util.SparseArray) 21518 * @see #onSaveInstanceState() 21519 */ saveHierarchyState(SparseArray<Parcelable> container)21520 public void saveHierarchyState(SparseArray<Parcelable> container) { 21521 dispatchSaveInstanceState(container); 21522 } 21523 21524 /** 21525 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 21526 * this view and its children. May be overridden to modify how freezing happens to a 21527 * view's children; for example, some views may want to not store state for their children. 21528 * 21529 * @param container The SparseArray in which to save the view's state. 21530 * 21531 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 21532 * @see #saveHierarchyState(android.util.SparseArray) 21533 * @see #onSaveInstanceState() 21534 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)21535 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 21536 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 21537 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 21538 Parcelable state = onSaveInstanceState(); 21539 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 21540 throw new IllegalStateException( 21541 "Derived class did not call super.onSaveInstanceState()"); 21542 } 21543 if (state != null) { 21544 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 21545 // + ": " + state); 21546 container.put(mID, state); 21547 } 21548 } 21549 } 21550 21551 /** 21552 * Hook allowing a view to generate a representation of its internal state 21553 * that can later be used to create a new instance with that same state. 21554 * This state should only contain information that is not persistent or can 21555 * not be reconstructed later. For example, you will never store your 21556 * current position on screen because that will be computed again when a 21557 * new instance of the view is placed in its view hierarchy. 21558 * <p> 21559 * Some examples of things you may store here: the current cursor position 21560 * in a text view (but usually not the text itself since that is stored in a 21561 * content provider or other persistent storage), the currently selected 21562 * item in a list view. 21563 * 21564 * @return Returns a Parcelable object containing the view's current dynamic 21565 * state, or null if there is nothing interesting to save. 21566 * @see #onRestoreInstanceState(Parcelable) 21567 * @see #saveHierarchyState(SparseArray) 21568 * @see #dispatchSaveInstanceState(SparseArray) 21569 * @see #setSaveEnabled(boolean) 21570 */ 21571 @CallSuper onSaveInstanceState()21572 @Nullable protected Parcelable onSaveInstanceState() { 21573 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 21574 if (mStartActivityRequestWho != null || isAutofilled() 21575 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 21576 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 21577 21578 if (mStartActivityRequestWho != null) { 21579 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 21580 } 21581 21582 if (isAutofilled()) { 21583 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 21584 } 21585 21586 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 21587 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 21588 } 21589 21590 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 21591 state.mIsAutofilled = isAutofilled(); 21592 state.mHideHighlight = hideAutofillHighlight(); 21593 state.mAutofillViewId = mAutofillViewId; 21594 return state; 21595 } 21596 return BaseSavedState.EMPTY_STATE; 21597 } 21598 21599 /** 21600 * Restore this view hierarchy's frozen state from the given container. 21601 * 21602 * @param container The SparseArray which holds previously frozen states. 21603 * 21604 * @see #saveHierarchyState(android.util.SparseArray) 21605 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 21606 * @see #onRestoreInstanceState(android.os.Parcelable) 21607 */ restoreHierarchyState(SparseArray<Parcelable> container)21608 public void restoreHierarchyState(SparseArray<Parcelable> container) { 21609 dispatchRestoreInstanceState(container); 21610 } 21611 21612 /** 21613 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 21614 * state for this view and its children. May be overridden to modify how restoring 21615 * happens to a view's children; for example, some views may want to not store state 21616 * for their children. 21617 * 21618 * @param container The SparseArray which holds previously saved state. 21619 * 21620 * @see #dispatchSaveInstanceState(android.util.SparseArray) 21621 * @see #restoreHierarchyState(android.util.SparseArray) 21622 * @see #onRestoreInstanceState(android.os.Parcelable) 21623 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)21624 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 21625 if (mID != NO_ID) { 21626 Parcelable state = container.get(mID); 21627 if (state != null) { 21628 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 21629 // + ": " + state); 21630 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 21631 onRestoreInstanceState(state); 21632 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 21633 throw new IllegalStateException( 21634 "Derived class did not call super.onRestoreInstanceState()"); 21635 } 21636 } 21637 } 21638 } 21639 21640 /** 21641 * Hook allowing a view to re-apply a representation of its internal state that had previously 21642 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 21643 * null state. 21644 * 21645 * @param state The frozen state that had previously been returned by 21646 * {@link #onSaveInstanceState}. 21647 * 21648 * @see #onSaveInstanceState() 21649 * @see #restoreHierarchyState(android.util.SparseArray) 21650 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 21651 */ 21652 @CallSuper onRestoreInstanceState(Parcelable state)21653 protected void onRestoreInstanceState(Parcelable state) { 21654 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 21655 if (state != null && !(state instanceof AbsSavedState)) { 21656 throw new IllegalArgumentException("Wrong state class, expecting View State but " 21657 + "received " + state.getClass().toString() + " instead. This usually happens " 21658 + "when two views of different type have the same id in the same hierarchy. " 21659 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 21660 + "other views do not use the same id."); 21661 } 21662 if (state != null && state instanceof BaseSavedState) { 21663 BaseSavedState baseState = (BaseSavedState) state; 21664 21665 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 21666 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 21667 } 21668 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 21669 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 21670 } 21671 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 21672 // It can happen that views have the same view id and the restoration path will not 21673 // be able to distinguish between them. The autofill id needs to be unique though. 21674 // Hence prevent the same autofill view id from being restored multiple times. 21675 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 21676 21677 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 21678 // Ignore when view already set it through setAutofillId(); 21679 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 21680 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 21681 + "to " + baseState.mAutofillViewId + " because view explicitly set" 21682 + " it to " + mAutofillId); 21683 } 21684 } else { 21685 mAutofillViewId = baseState.mAutofillViewId; 21686 mAutofillId = null; // will be set on demand by getAutofillId() 21687 } 21688 } 21689 } 21690 } 21691 21692 /** 21693 * <p>Return the time at which the drawing of the view hierarchy started.</p> 21694 * 21695 * @return the drawing start time in milliseconds 21696 */ getDrawingTime()21697 public long getDrawingTime() { 21698 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 21699 } 21700 21701 /** 21702 * <p>Enables or disables the duplication of the parent's state into this view. When 21703 * duplication is enabled, this view gets its drawable state from its parent rather 21704 * than from its own internal properties.</p> 21705 * 21706 * <p>Note: in the current implementation, setting this property to true after the 21707 * view was added to a ViewGroup might have no effect at all. This property should 21708 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 21709 * 21710 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 21711 * property is enabled, an exception will be thrown.</p> 21712 * 21713 * <p>Note: if the child view uses and updates additional states which are unknown to the 21714 * parent, these states should not be affected by this method.</p> 21715 * 21716 * @param enabled True to enable duplication of the parent's drawable state, false 21717 * to disable it. 21718 * 21719 * @see #getDrawableState() 21720 * @see #isDuplicateParentStateEnabled() 21721 */ setDuplicateParentStateEnabled(boolean enabled)21722 public void setDuplicateParentStateEnabled(boolean enabled) { 21723 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 21724 } 21725 21726 /** 21727 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 21728 * 21729 * @return True if this view's drawable state is duplicated from the parent, 21730 * false otherwise 21731 * 21732 * @see #getDrawableState() 21733 * @see #setDuplicateParentStateEnabled(boolean) 21734 */ 21735 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()21736 public boolean isDuplicateParentStateEnabled() { 21737 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 21738 } 21739 21740 /** 21741 * <p>Specifies the type of layer backing this view. The layer can be 21742 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21743 * {@link #LAYER_TYPE_HARDWARE}.</p> 21744 * 21745 * <p>A layer is associated with an optional {@link android.graphics.Paint} 21746 * instance that controls how the layer is composed on screen. The following 21747 * properties of the paint are taken into account when composing the layer:</p> 21748 * <ul> 21749 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 21750 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 21751 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 21752 * </ul> 21753 * 21754 * <p>If this view has an alpha value set to < 1.0 by calling 21755 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 21756 * by this view's alpha value.</p> 21757 * 21758 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 21759 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 21760 * for more information on when and how to use layers.</p> 21761 * 21762 * @param layerType The type of layer to use with this view, must be one of 21763 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21764 * {@link #LAYER_TYPE_HARDWARE} 21765 * @param paint The paint used to compose the layer. This argument is optional 21766 * and can be null. It is ignored when the layer type is 21767 * {@link #LAYER_TYPE_NONE} 21768 * 21769 * @see #getLayerType() 21770 * @see #LAYER_TYPE_NONE 21771 * @see #LAYER_TYPE_SOFTWARE 21772 * @see #LAYER_TYPE_HARDWARE 21773 * @see #setAlpha(float) 21774 * 21775 * @attr ref android.R.styleable#View_layerType 21776 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)21777 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 21778 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 21779 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 21780 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 21781 } 21782 21783 boolean typeChanged = mRenderNode.setLayerType(layerType); 21784 21785 if (!typeChanged) { 21786 setLayerPaint(paint); 21787 return; 21788 } 21789 21790 if (layerType != LAYER_TYPE_SOFTWARE) { 21791 // Destroy any previous software drawing cache if present 21792 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 21793 // drawing cache created in View#draw when drawing to a SW canvas. 21794 destroyDrawingCache(); 21795 } 21796 21797 mLayerType = layerType; 21798 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 21799 mRenderNode.setLayerPaint(mLayerPaint); 21800 21801 // draw() behaves differently if we are on a layer, so we need to 21802 // invalidate() here 21803 invalidateParentCaches(); 21804 invalidate(true); 21805 } 21806 21807 /** 21808 * Configure the {@link android.graphics.RenderEffect} to apply to this View. 21809 * This will apply a visual effect to the results of the View before it is drawn. For example if 21810 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 21811 * is provided, the contents will be drawn in a separate layer, then this layer will be blurred 21812 * when this View is drawn. 21813 * @param renderEffect to be applied to the View. Passing null clears the previously configured 21814 * {@link RenderEffect} 21815 */ setRenderEffect(@ullable RenderEffect renderEffect)21816 public void setRenderEffect(@Nullable RenderEffect renderEffect) { 21817 if (mRenderNode.setRenderEffect(renderEffect)) { 21818 invalidateViewProperty(true, true); 21819 } 21820 } 21821 21822 /** 21823 * Updates the {@link Paint} object used with the current layer (used only if the current 21824 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 21825 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 21826 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 21827 * ensure that the view gets redrawn immediately. 21828 * 21829 * <p>A layer is associated with an optional {@link android.graphics.Paint} 21830 * instance that controls how the layer is composed on screen. The following 21831 * properties of the paint are taken into account when composing the layer:</p> 21832 * <ul> 21833 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 21834 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 21835 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 21836 * </ul> 21837 * 21838 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 21839 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 21840 * 21841 * @param paint The paint used to compose the layer. This argument is optional 21842 * and can be null. It is ignored when the layer type is 21843 * {@link #LAYER_TYPE_NONE} 21844 * 21845 * @see #setLayerType(int, android.graphics.Paint) 21846 */ setLayerPaint(@ullable Paint paint)21847 public void setLayerPaint(@Nullable Paint paint) { 21848 int layerType = getLayerType(); 21849 if (layerType != LAYER_TYPE_NONE) { 21850 mLayerPaint = paint; 21851 if (layerType == LAYER_TYPE_HARDWARE) { 21852 if (mRenderNode.setLayerPaint(paint)) { 21853 invalidateViewProperty(false, false); 21854 } 21855 } else { 21856 invalidate(); 21857 } 21858 } 21859 } 21860 21861 /** 21862 * Indicates what type of layer is currently associated with this view. By default 21863 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 21864 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 21865 * for more information on the different types of layers. 21866 * 21867 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21868 * {@link #LAYER_TYPE_HARDWARE} 21869 * 21870 * @see #setLayerType(int, android.graphics.Paint) 21871 * @see #buildLayer() 21872 * @see #LAYER_TYPE_NONE 21873 * @see #LAYER_TYPE_SOFTWARE 21874 * @see #LAYER_TYPE_HARDWARE 21875 */ 21876 @InspectableProperty(enumMapping = { 21877 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 21878 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 21879 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 21880 }) 21881 @LayerType getLayerType()21882 public int getLayerType() { 21883 return mLayerType; 21884 } 21885 21886 /** 21887 * Forces this view's layer to be created and this view to be rendered 21888 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 21889 * invoking this method will have no effect. 21890 * 21891 * This method can for instance be used to render a view into its layer before 21892 * starting an animation. If this view is complex, rendering into the layer 21893 * before starting the animation will avoid skipping frames. 21894 * 21895 * @throws IllegalStateException If this view is not attached to a window 21896 * 21897 * @see #setLayerType(int, android.graphics.Paint) 21898 */ buildLayer()21899 public void buildLayer() { 21900 if (mLayerType == LAYER_TYPE_NONE) return; 21901 21902 final AttachInfo attachInfo = mAttachInfo; 21903 if (attachInfo == null) { 21904 throw new IllegalStateException("This view must be attached to a window first"); 21905 } 21906 21907 if (getWidth() == 0 || getHeight() == 0) { 21908 return; 21909 } 21910 21911 switch (mLayerType) { 21912 case LAYER_TYPE_HARDWARE: 21913 updateDisplayListIfDirty(); 21914 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 21915 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 21916 } 21917 break; 21918 case LAYER_TYPE_SOFTWARE: 21919 buildDrawingCache(true); 21920 break; 21921 } 21922 } 21923 21924 /** 21925 * Destroys all hardware rendering resources. This method is invoked 21926 * when the system needs to reclaim resources. Upon execution of this 21927 * method, you should free any OpenGL resources created by the view. 21928 * 21929 * Note: you <strong>must</strong> call 21930 * <code>super.destroyHardwareResources()</code> when overriding 21931 * this method. 21932 * 21933 * @hide 21934 */ 21935 @CallSuper 21936 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareResources()21937 protected void destroyHardwareResources() { 21938 if (mOverlay != null) { 21939 mOverlay.getOverlayView().destroyHardwareResources(); 21940 } 21941 if (mGhostView != null) { 21942 mGhostView.destroyHardwareResources(); 21943 } 21944 } 21945 21946 /** 21947 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 21948 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 21949 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 21950 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 21951 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 21952 * null.</p> 21953 * 21954 * <p>Enabling the drawing cache is similar to 21955 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 21956 * acceleration is turned off. When hardware acceleration is turned on, enabling the 21957 * drawing cache has no effect on rendering because the system uses a different mechanism 21958 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 21959 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 21960 * for information on how to enable software and hardware layers.</p> 21961 * 21962 * <p>This API can be used to manually generate 21963 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 21964 * {@link #getDrawingCache()}.</p> 21965 * 21966 * @param enabled true to enable the drawing cache, false otherwise 21967 * 21968 * @see #isDrawingCacheEnabled() 21969 * @see #getDrawingCache() 21970 * @see #buildDrawingCache() 21971 * @see #setLayerType(int, android.graphics.Paint) 21972 * 21973 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21974 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21975 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21976 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21977 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21978 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21979 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21980 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21981 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21982 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21983 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21984 * reports or unit testing the {@link PixelCopy} API is recommended. 21985 */ 21986 @Deprecated setDrawingCacheEnabled(boolean enabled)21987 public void setDrawingCacheEnabled(boolean enabled) { 21988 mCachingFailed = false; 21989 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 21990 } 21991 21992 /** 21993 * <p>Indicates whether the drawing cache is enabled for this view.</p> 21994 * 21995 * @return true if the drawing cache is enabled 21996 * 21997 * @see #setDrawingCacheEnabled(boolean) 21998 * @see #getDrawingCache() 21999 * 22000 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22001 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22002 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22003 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22004 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22005 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22006 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22007 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22008 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22009 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22010 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22011 * reports or unit testing the {@link PixelCopy} API is recommended. 22012 */ 22013 @Deprecated 22014 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()22015 public boolean isDrawingCacheEnabled() { 22016 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 22017 } 22018 22019 /** 22020 * Debugging utility which recursively outputs the dirty state of a view and its 22021 * descendants. 22022 * 22023 * @hide 22024 */ 22025 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)22026 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 22027 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 22028 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 22029 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 22030 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 22031 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 22032 if (clear) { 22033 mPrivateFlags &= clearMask; 22034 } 22035 if (this instanceof ViewGroup) { 22036 ViewGroup parent = (ViewGroup) this; 22037 final int count = parent.getChildCount(); 22038 for (int i = 0; i < count; i++) { 22039 final View child = parent.getChildAt(i); 22040 child.outputDirtyFlags(indent + " ", clear, clearMask); 22041 } 22042 } 22043 } 22044 22045 /** 22046 * This method is used by ViewGroup to cause its children to restore or recreate their 22047 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 22048 * to recreate its own display list, which would happen if it went through the normal 22049 * draw/dispatchDraw mechanisms. 22050 * 22051 * @hide 22052 */ dispatchGetDisplayList()22053 protected void dispatchGetDisplayList() {} 22054 22055 /** 22056 * A view that is not attached or hardware accelerated cannot create a display list. 22057 * This method checks these conditions and returns the appropriate result. 22058 * 22059 * @return true if view has the ability to create a display list, false otherwise. 22060 * 22061 * @hide 22062 */ canHaveDisplayList()22063 public boolean canHaveDisplayList() { 22064 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 22065 } 22066 22067 /** 22068 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 22069 * @hide 22070 */ 22071 @NonNull 22072 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateDisplayListIfDirty()22073 public RenderNode updateDisplayListIfDirty() { 22074 final RenderNode renderNode = mRenderNode; 22075 if (!canHaveDisplayList()) { 22076 // can't populate RenderNode, don't try 22077 return renderNode; 22078 } 22079 22080 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 22081 || !renderNode.hasDisplayList() 22082 || (mRecreateDisplayList)) { 22083 // Don't need to recreate the display list, just need to tell our 22084 // children to restore/recreate theirs 22085 if (renderNode.hasDisplayList() 22086 && !mRecreateDisplayList) { 22087 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 22088 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22089 dispatchGetDisplayList(); 22090 22091 return renderNode; // no work needed 22092 } 22093 22094 // If we got here, we're recreating it. Mark it as such to ensure that 22095 // we copy in child display lists into ours in drawChild() 22096 mRecreateDisplayList = true; 22097 22098 int width = mRight - mLeft; 22099 int height = mBottom - mTop; 22100 int layerType = getLayerType(); 22101 22102 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 22103 // instead of being "stateful" like other RenderNode properties 22104 renderNode.clearStretch(); 22105 22106 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 22107 22108 try { 22109 if (layerType == LAYER_TYPE_SOFTWARE) { 22110 buildDrawingCache(true); 22111 Bitmap cache = getDrawingCache(true); 22112 if (cache != null) { 22113 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 22114 } 22115 } else { 22116 computeScroll(); 22117 22118 canvas.translate(-mScrollX, -mScrollY); 22119 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 22120 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22121 22122 // Fast path for layouts with no backgrounds 22123 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22124 dispatchDraw(canvas); 22125 drawAutofilledHighlight(canvas); 22126 if (mOverlay != null && !mOverlay.isEmpty()) { 22127 mOverlay.getOverlayView().draw(canvas); 22128 } 22129 if (isShowingLayoutBounds()) { 22130 debugDrawFocus(canvas); 22131 } 22132 } else { 22133 draw(canvas); 22134 } 22135 } 22136 } finally { 22137 renderNode.endRecording(); 22138 setDisplayListProperties(renderNode); 22139 } 22140 } else { 22141 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 22142 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22143 } 22144 return renderNode; 22145 } 22146 22147 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resetDisplayList()22148 private void resetDisplayList() { 22149 mRenderNode.discardDisplayList(); 22150 if (mBackgroundRenderNode != null) { 22151 mBackgroundRenderNode.discardDisplayList(); 22152 } 22153 } 22154 22155 /** 22156 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 22157 * 22158 * @return A non-scaled bitmap representing this view or null if cache is disabled. 22159 * 22160 * @see #getDrawingCache(boolean) 22161 * 22162 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22163 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22164 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22165 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22166 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22167 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22168 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22169 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22170 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22171 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22172 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22173 * reports or unit testing the {@link PixelCopy} API is recommended. 22174 */ 22175 @Deprecated getDrawingCache()22176 public Bitmap getDrawingCache() { 22177 return getDrawingCache(false); 22178 } 22179 22180 /** 22181 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 22182 * is null when caching is disabled. If caching is enabled and the cache is not ready, 22183 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 22184 * draw from the cache when the cache is enabled. To benefit from the cache, you must 22185 * request the drawing cache by calling this method and draw it on screen if the 22186 * returned bitmap is not null.</p> 22187 * 22188 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 22189 * this method will create a bitmap of the same size as this view. Because this bitmap 22190 * will be drawn scaled by the parent ViewGroup, the result on screen might show 22191 * scaling artifacts. To avoid such artifacts, you should call this method by setting 22192 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 22193 * size than the view. This implies that your application must be able to handle this 22194 * size.</p> 22195 * 22196 * @param autoScale Indicates whether the generated bitmap should be scaled based on 22197 * the current density of the screen when the application is in compatibility 22198 * mode. 22199 * 22200 * @return A bitmap representing this view or null if cache is disabled. 22201 * 22202 * @see #setDrawingCacheEnabled(boolean) 22203 * @see #isDrawingCacheEnabled() 22204 * @see #buildDrawingCache(boolean) 22205 * @see #destroyDrawingCache() 22206 * 22207 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22208 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22209 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22210 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22211 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22212 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22213 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22214 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22215 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22216 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22217 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22218 * reports or unit testing the {@link PixelCopy} API is recommended. 22219 */ 22220 @Deprecated getDrawingCache(boolean autoScale)22221 public Bitmap getDrawingCache(boolean autoScale) { 22222 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 22223 return null; 22224 } 22225 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 22226 buildDrawingCache(autoScale); 22227 } 22228 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 22229 } 22230 22231 /** 22232 * <p>Frees the resources used by the drawing cache. If you call 22233 * {@link #buildDrawingCache()} manually without calling 22234 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 22235 * should cleanup the cache with this method afterwards.</p> 22236 * 22237 * @see #setDrawingCacheEnabled(boolean) 22238 * @see #buildDrawingCache() 22239 * @see #getDrawingCache() 22240 * 22241 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22242 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22243 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22244 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22245 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22246 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22247 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22248 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22249 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22250 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22251 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22252 * reports or unit testing the {@link PixelCopy} API is recommended. 22253 */ 22254 @Deprecated destroyDrawingCache()22255 public void destroyDrawingCache() { 22256 if (mDrawingCache != null) { 22257 mDrawingCache.recycle(); 22258 mDrawingCache = null; 22259 } 22260 if (mUnscaledDrawingCache != null) { 22261 mUnscaledDrawingCache.recycle(); 22262 mUnscaledDrawingCache = null; 22263 } 22264 } 22265 22266 /** 22267 * Setting a solid background color for the drawing cache's bitmaps will improve 22268 * performance and memory usage. Note, though that this should only be used if this 22269 * view will always be drawn on top of a solid color. 22270 * 22271 * @param color The background color to use for the drawing cache's bitmap 22272 * 22273 * @see #setDrawingCacheEnabled(boolean) 22274 * @see #buildDrawingCache() 22275 * @see #getDrawingCache() 22276 * 22277 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22278 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22279 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22280 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22281 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22282 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22283 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22284 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22285 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22286 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22287 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22288 * reports or unit testing the {@link PixelCopy} API is recommended. 22289 */ 22290 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)22291 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 22292 if (color != mDrawingCacheBackgroundColor) { 22293 mDrawingCacheBackgroundColor = color; 22294 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 22295 } 22296 } 22297 22298 /** 22299 * @see #setDrawingCacheBackgroundColor(int) 22300 * 22301 * @return The background color to used for the drawing cache's bitmap 22302 * 22303 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22304 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22305 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22306 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22307 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22308 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22309 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22310 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22311 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22312 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22313 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22314 * reports or unit testing the {@link PixelCopy} API is recommended. 22315 */ 22316 @Deprecated 22317 @ColorInt getDrawingCacheBackgroundColor()22318 public int getDrawingCacheBackgroundColor() { 22319 return mDrawingCacheBackgroundColor; 22320 } 22321 22322 /** 22323 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 22324 * 22325 * @see #buildDrawingCache(boolean) 22326 * 22327 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22328 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22329 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22330 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22331 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22332 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22333 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22334 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22335 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22336 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22337 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22338 * reports or unit testing the {@link PixelCopy} API is recommended. 22339 */ 22340 @Deprecated buildDrawingCache()22341 public void buildDrawingCache() { 22342 buildDrawingCache(false); 22343 } 22344 22345 /** 22346 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 22347 * 22348 * <p>If you call {@link #buildDrawingCache()} manually without calling 22349 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 22350 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 22351 * 22352 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 22353 * this method will create a bitmap of the same size as this view. Because this bitmap 22354 * will be drawn scaled by the parent ViewGroup, the result on screen might show 22355 * scaling artifacts. To avoid such artifacts, you should call this method by setting 22356 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 22357 * size than the view. This implies that your application must be able to handle this 22358 * size.</p> 22359 * 22360 * <p>You should avoid calling this method when hardware acceleration is enabled. If 22361 * you do not need the drawing cache bitmap, calling this method will increase memory 22362 * usage and cause the view to be rendered in software once, thus negatively impacting 22363 * performance.</p> 22364 * 22365 * @see #getDrawingCache() 22366 * @see #destroyDrawingCache() 22367 * 22368 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22369 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22370 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22371 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22372 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22373 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22374 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22375 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22376 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22377 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22378 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22379 * reports or unit testing the {@link PixelCopy} API is recommended. 22380 */ 22381 @Deprecated buildDrawingCache(boolean autoScale)22382 public void buildDrawingCache(boolean autoScale) { 22383 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 22384 mDrawingCache == null : mUnscaledDrawingCache == null)) { 22385 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 22386 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 22387 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 22388 } 22389 try { 22390 buildDrawingCacheImpl(autoScale); 22391 } finally { 22392 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 22393 } 22394 } 22395 } 22396 22397 /** 22398 * private, internal implementation of buildDrawingCache, used to enable tracing 22399 */ buildDrawingCacheImpl(boolean autoScale)22400 private void buildDrawingCacheImpl(boolean autoScale) { 22401 mCachingFailed = false; 22402 22403 int width = mRight - mLeft; 22404 int height = mBottom - mTop; 22405 22406 final AttachInfo attachInfo = mAttachInfo; 22407 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 22408 22409 if (autoScale && scalingRequired) { 22410 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 22411 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 22412 } 22413 22414 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 22415 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 22416 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 22417 22418 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 22419 final long drawingCacheSize = 22420 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 22421 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 22422 if (width > 0 && height > 0) { 22423 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 22424 + " too large to fit into a software layer (or drawing cache), needs " 22425 + projectedBitmapSize + " bytes, only " 22426 + drawingCacheSize + " available"); 22427 } 22428 destroyDrawingCache(); 22429 mCachingFailed = true; 22430 return; 22431 } 22432 22433 boolean clear = true; 22434 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 22435 22436 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 22437 Bitmap.Config quality; 22438 if (!opaque) { 22439 // Never pick ARGB_4444 because it looks awful 22440 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 22441 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 22442 case DRAWING_CACHE_QUALITY_AUTO: 22443 case DRAWING_CACHE_QUALITY_LOW: 22444 case DRAWING_CACHE_QUALITY_HIGH: 22445 default: 22446 quality = Bitmap.Config.ARGB_8888; 22447 break; 22448 } 22449 } else { 22450 // Optimization for translucent windows 22451 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 22452 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 22453 } 22454 22455 // Try to cleanup memory 22456 if (bitmap != null) bitmap.recycle(); 22457 22458 try { 22459 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 22460 width, height, quality); 22461 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 22462 if (autoScale) { 22463 mDrawingCache = bitmap; 22464 } else { 22465 mUnscaledDrawingCache = bitmap; 22466 } 22467 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 22468 } catch (OutOfMemoryError e) { 22469 // If there is not enough memory to create the bitmap cache, just 22470 // ignore the issue as bitmap caches are not required to draw the 22471 // view hierarchy 22472 if (autoScale) { 22473 mDrawingCache = null; 22474 } else { 22475 mUnscaledDrawingCache = null; 22476 } 22477 mCachingFailed = true; 22478 return; 22479 } 22480 22481 clear = drawingCacheBackgroundColor != 0; 22482 } 22483 22484 Canvas canvas; 22485 if (attachInfo != null) { 22486 canvas = attachInfo.mCanvas; 22487 if (canvas == null) { 22488 canvas = new Canvas(); 22489 } 22490 canvas.setBitmap(bitmap); 22491 // Temporarily clobber the cached Canvas in case one of our children 22492 // is also using a drawing cache. Without this, the children would 22493 // steal the canvas by attaching their own bitmap to it and bad, bad 22494 // thing would happen (invisible views, corrupted drawings, etc.) 22495 attachInfo.mCanvas = null; 22496 } else { 22497 // This case should hopefully never or seldom happen 22498 canvas = new Canvas(bitmap); 22499 } 22500 22501 if (clear) { 22502 bitmap.eraseColor(drawingCacheBackgroundColor); 22503 } 22504 22505 computeScroll(); 22506 final int restoreCount = canvas.save(); 22507 22508 if (autoScale && scalingRequired) { 22509 final float scale = attachInfo.mApplicationScale; 22510 canvas.scale(scale, scale); 22511 } 22512 22513 canvas.translate(-mScrollX, -mScrollY); 22514 22515 mPrivateFlags |= PFLAG_DRAWN; 22516 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 22517 mLayerType != LAYER_TYPE_NONE) { 22518 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 22519 } 22520 22521 // Fast path for layouts with no backgrounds 22522 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22523 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22524 dispatchDraw(canvas); 22525 drawAutofilledHighlight(canvas); 22526 if (mOverlay != null && !mOverlay.isEmpty()) { 22527 mOverlay.getOverlayView().draw(canvas); 22528 } 22529 } else { 22530 draw(canvas); 22531 } 22532 22533 canvas.restoreToCount(restoreCount); 22534 canvas.setBitmap(null); 22535 22536 if (attachInfo != null) { 22537 // Restore the cached Canvas for our siblings 22538 attachInfo.mCanvas = canvas; 22539 } 22540 } 22541 22542 /** 22543 * Create a snapshot of the view into a bitmap. We should probably make 22544 * some form of this public, but should think about the API. 22545 * 22546 * @hide 22547 */ 22548 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)22549 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 22550 int width = mRight - mLeft; 22551 int height = mBottom - mTop; 22552 22553 final AttachInfo attachInfo = mAttachInfo; 22554 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 22555 width = (int) ((width * scale) + 0.5f); 22556 height = (int) ((height * scale) + 0.5f); 22557 22558 Canvas oldCanvas = null; 22559 try { 22560 Canvas canvas = canvasProvider.getCanvas(this, 22561 width > 0 ? width : 1, height > 0 ? height : 1); 22562 22563 if (attachInfo != null) { 22564 oldCanvas = attachInfo.mCanvas; 22565 // Temporarily clobber the cached Canvas in case one of our children 22566 // is also using a drawing cache. Without this, the children would 22567 // steal the canvas by attaching their own bitmap to it and bad, bad 22568 // things would happen (invisible views, corrupted drawings, etc.) 22569 attachInfo.mCanvas = null; 22570 } 22571 22572 computeScroll(); 22573 final int restoreCount = canvas.save(); 22574 canvas.scale(scale, scale); 22575 canvas.translate(-mScrollX, -mScrollY); 22576 22577 // Temporarily remove the dirty mask 22578 int flags = mPrivateFlags; 22579 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22580 22581 // Fast path for layouts with no backgrounds 22582 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22583 dispatchDraw(canvas); 22584 drawAutofilledHighlight(canvas); 22585 if (mOverlay != null && !mOverlay.isEmpty()) { 22586 mOverlay.getOverlayView().draw(canvas); 22587 } 22588 } else { 22589 draw(canvas); 22590 } 22591 22592 mPrivateFlags = flags; 22593 canvas.restoreToCount(restoreCount); 22594 return canvasProvider.createBitmap(); 22595 } finally { 22596 if (oldCanvas != null) { 22597 attachInfo.mCanvas = oldCanvas; 22598 } 22599 } 22600 } 22601 22602 /** 22603 * Indicates whether this View is currently in edit mode. A View is usually 22604 * in edit mode when displayed within a developer tool. For instance, if 22605 * this View is being drawn by a visual user interface builder, this method 22606 * should return true. 22607 * 22608 * Subclasses should check the return value of this method to provide 22609 * different behaviors if their normal behavior might interfere with the 22610 * host environment. For instance: the class spawns a thread in its 22611 * constructor, the drawing code relies on device-specific features, etc. 22612 * 22613 * This method is usually checked in the drawing code of custom widgets. 22614 * 22615 * @return True if this View is in edit mode, false otherwise. 22616 */ isInEditMode()22617 public boolean isInEditMode() { 22618 return false; 22619 } 22620 22621 /** 22622 * If the View draws content inside its padding and enables fading edges, 22623 * it needs to support padding offsets. Padding offsets are added to the 22624 * fading edges to extend the length of the fade so that it covers pixels 22625 * drawn inside the padding. 22626 * 22627 * Subclasses of this class should override this method if they need 22628 * to draw content inside the padding. 22629 * 22630 * @return True if padding offset must be applied, false otherwise. 22631 * 22632 * @see #getLeftPaddingOffset() 22633 * @see #getRightPaddingOffset() 22634 * @see #getTopPaddingOffset() 22635 * @see #getBottomPaddingOffset() 22636 * 22637 * @since CURRENT 22638 */ isPaddingOffsetRequired()22639 protected boolean isPaddingOffsetRequired() { 22640 return false; 22641 } 22642 22643 /** 22644 * Amount by which to extend the left fading region. Called only when 22645 * {@link #isPaddingOffsetRequired()} returns true. 22646 * 22647 * @return The left padding offset in pixels. 22648 * 22649 * @see #isPaddingOffsetRequired() 22650 * 22651 * @since CURRENT 22652 */ getLeftPaddingOffset()22653 protected int getLeftPaddingOffset() { 22654 return 0; 22655 } 22656 22657 /** 22658 * Amount by which to extend the right fading region. Called only when 22659 * {@link #isPaddingOffsetRequired()} returns true. 22660 * 22661 * @return The right padding offset in pixels. 22662 * 22663 * @see #isPaddingOffsetRequired() 22664 * 22665 * @since CURRENT 22666 */ getRightPaddingOffset()22667 protected int getRightPaddingOffset() { 22668 return 0; 22669 } 22670 22671 /** 22672 * Amount by which to extend the top fading region. Called only when 22673 * {@link #isPaddingOffsetRequired()} returns true. 22674 * 22675 * @return The top padding offset in pixels. 22676 * 22677 * @see #isPaddingOffsetRequired() 22678 * 22679 * @since CURRENT 22680 */ getTopPaddingOffset()22681 protected int getTopPaddingOffset() { 22682 return 0; 22683 } 22684 22685 /** 22686 * Amount by which to extend the bottom fading region. Called only when 22687 * {@link #isPaddingOffsetRequired()} returns true. 22688 * 22689 * @return The bottom padding offset in pixels. 22690 * 22691 * @see #isPaddingOffsetRequired() 22692 * 22693 * @since CURRENT 22694 */ getBottomPaddingOffset()22695 protected int getBottomPaddingOffset() { 22696 return 0; 22697 } 22698 22699 /** 22700 * @hide 22701 * @param offsetRequired 22702 */ getFadeTop(boolean offsetRequired)22703 protected int getFadeTop(boolean offsetRequired) { 22704 int top = mPaddingTop; 22705 if (offsetRequired) top += getTopPaddingOffset(); 22706 return top; 22707 } 22708 22709 /** 22710 * @hide 22711 * @param offsetRequired 22712 */ getFadeHeight(boolean offsetRequired)22713 protected int getFadeHeight(boolean offsetRequired) { 22714 int padding = mPaddingTop; 22715 if (offsetRequired) padding += getTopPaddingOffset(); 22716 return mBottom - mTop - mPaddingBottom - padding; 22717 } 22718 22719 /** 22720 * <p>Indicates whether this view is attached to a hardware accelerated 22721 * window or not.</p> 22722 * 22723 * <p>Even if this method returns true, it does not mean that every call 22724 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 22725 * accelerated {@link android.graphics.Canvas}. For instance, if this view 22726 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 22727 * window is hardware accelerated, 22728 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 22729 * return false, and this method will return true.</p> 22730 * 22731 * @return True if the view is attached to a window and the window is 22732 * hardware accelerated; false in any other case. 22733 */ 22734 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()22735 public boolean isHardwareAccelerated() { 22736 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 22737 } 22738 22739 /** 22740 * Sets a rectangular area on this view to which the view will be clipped 22741 * when it is drawn. Setting the value to null will remove the clip bounds 22742 * and the view will draw normally, using its full bounds. 22743 * 22744 * @param clipBounds The rectangular area, in the local coordinates of 22745 * this view, to which future drawing operations will be clipped. 22746 */ setClipBounds(Rect clipBounds)22747 public void setClipBounds(Rect clipBounds) { 22748 if (clipBounds == mClipBounds 22749 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 22750 return; 22751 } 22752 if (clipBounds != null) { 22753 if (mClipBounds == null) { 22754 mClipBounds = new Rect(clipBounds); 22755 } else { 22756 mClipBounds.set(clipBounds); 22757 } 22758 } else { 22759 mClipBounds = null; 22760 } 22761 mRenderNode.setClipRect(mClipBounds); 22762 invalidateViewProperty(false, false); 22763 } 22764 22765 /** 22766 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 22767 * 22768 * @return A copy of the current clip bounds if clip bounds are set, 22769 * otherwise null. 22770 */ getClipBounds()22771 public Rect getClipBounds() { 22772 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 22773 } 22774 22775 22776 /** 22777 * Populates an output rectangle with the clip bounds of the view, 22778 * returning {@code true} if successful or {@code false} if the view's 22779 * clip bounds are {@code null}. 22780 * 22781 * @param outRect rectangle in which to place the clip bounds of the view 22782 * @return {@code true} if successful or {@code false} if the view's 22783 * clip bounds are {@code null} 22784 */ getClipBounds(Rect outRect)22785 public boolean getClipBounds(Rect outRect) { 22786 if (mClipBounds != null) { 22787 outRect.set(mClipBounds); 22788 return true; 22789 } 22790 return false; 22791 } 22792 22793 /** 22794 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 22795 * case of an active Animation being run on the view. 22796 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)22797 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 22798 Animation a, boolean scalingRequired) { 22799 Transformation invalidationTransform; 22800 final int flags = parent.mGroupFlags; 22801 final boolean initialized = a.isInitialized(); 22802 if (!initialized) { 22803 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 22804 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 22805 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 22806 onAnimationStart(); 22807 } 22808 22809 final Transformation t = parent.getChildTransformation(); 22810 boolean more = a.getTransformation(drawingTime, t, 1f); 22811 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 22812 if (parent.mInvalidationTransformation == null) { 22813 parent.mInvalidationTransformation = new Transformation(); 22814 } 22815 invalidationTransform = parent.mInvalidationTransformation; 22816 a.getTransformation(drawingTime, invalidationTransform, 1f); 22817 } else { 22818 invalidationTransform = t; 22819 } 22820 22821 if (more) { 22822 if (!a.willChangeBounds()) { 22823 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 22824 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 22825 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 22826 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 22827 // The child need to draw an animation, potentially offscreen, so 22828 // make sure we do not cancel invalidate requests 22829 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 22830 parent.invalidate(mLeft, mTop, mRight, mBottom); 22831 } 22832 } else { 22833 if (parent.mInvalidateRegion == null) { 22834 parent.mInvalidateRegion = new RectF(); 22835 } 22836 final RectF region = parent.mInvalidateRegion; 22837 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 22838 invalidationTransform); 22839 22840 // The child need to draw an animation, potentially offscreen, so 22841 // make sure we do not cancel invalidate requests 22842 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 22843 22844 final int left = mLeft + (int) region.left; 22845 final int top = mTop + (int) region.top; 22846 parent.invalidate(left, top, left + (int) (region.width() + .5f), 22847 top + (int) (region.height() + .5f)); 22848 } 22849 } 22850 return more; 22851 } 22852 22853 /** 22854 * This method is called by getDisplayList() when a display list is recorded for a View. 22855 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 22856 */ setDisplayListProperties(RenderNode renderNode)22857 void setDisplayListProperties(RenderNode renderNode) { 22858 if (renderNode != null) { 22859 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 22860 renderNode.setClipToBounds(mParent instanceof ViewGroup 22861 && ((ViewGroup) mParent).getClipChildren()); 22862 22863 float alpha = 1; 22864 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 22865 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22866 ViewGroup parentVG = (ViewGroup) mParent; 22867 final Transformation t = parentVG.getChildTransformation(); 22868 if (parentVG.getChildStaticTransformation(this, t)) { 22869 final int transformType = t.getTransformationType(); 22870 if (transformType != Transformation.TYPE_IDENTITY) { 22871 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 22872 alpha = t.getAlpha(); 22873 } 22874 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 22875 renderNode.setStaticMatrix(t.getMatrix()); 22876 } 22877 } 22878 } 22879 } 22880 if (mTransformationInfo != null) { 22881 alpha *= getFinalAlpha(); 22882 if (alpha < 1) { 22883 final int multipliedAlpha = (int) (255 * alpha); 22884 if (onSetAlpha(multipliedAlpha)) { 22885 alpha = 1; 22886 } 22887 } 22888 renderNode.setAlpha(alpha); 22889 } else if (alpha < 1) { 22890 renderNode.setAlpha(alpha); 22891 } 22892 } 22893 } 22894 22895 /** 22896 * If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 22897 * 22898 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 22899 * HW accelerated, it can't handle drawing RenderNodes. 22900 * 22901 * @hide 22902 */ drawsWithRenderNode(Canvas canvas)22903 protected final boolean drawsWithRenderNode(Canvas canvas) { 22904 return mAttachInfo != null 22905 && mAttachInfo.mHardwareAccelerated 22906 && canvas.isHardwareAccelerated(); 22907 } 22908 22909 /** 22910 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 22911 * 22912 * This is where the View specializes rendering behavior based on layer type, 22913 * and hardware acceleration. 22914 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)22915 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 22916 22917 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 22918 22919 boolean drawingWithRenderNode = drawsWithRenderNode(canvas); 22920 22921 boolean more = false; 22922 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 22923 final int parentFlags = parent.mGroupFlags; 22924 22925 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 22926 parent.getChildTransformation().clear(); 22927 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22928 } 22929 22930 Transformation transformToApply = null; 22931 boolean concatMatrix = false; 22932 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 22933 final Animation a = getAnimation(); 22934 if (a != null) { 22935 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 22936 concatMatrix = a.willChangeTransformationMatrix(); 22937 if (concatMatrix) { 22938 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22939 } 22940 transformToApply = parent.getChildTransformation(); 22941 } else { 22942 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 22943 // No longer animating: clear out old animation matrix 22944 mRenderNode.setAnimationMatrix(null); 22945 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22946 } 22947 if (!drawingWithRenderNode 22948 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22949 final Transformation t = parent.getChildTransformation(); 22950 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 22951 if (hasTransform) { 22952 final int transformType = t.getTransformationType(); 22953 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 22954 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 22955 } 22956 } 22957 } 22958 22959 concatMatrix |= !childHasIdentityMatrix; 22960 22961 // Sets the flag as early as possible to allow draw() implementations 22962 // to call invalidate() successfully when doing animations 22963 mPrivateFlags |= PFLAG_DRAWN; 22964 22965 if (!concatMatrix && 22966 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 22967 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 22968 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 22969 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 22970 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 22971 return more; 22972 } 22973 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 22974 22975 if (hardwareAcceleratedCanvas) { 22976 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 22977 // retain the flag's value temporarily in the mRecreateDisplayList flag 22978 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 22979 mPrivateFlags &= ~PFLAG_INVALIDATED; 22980 } 22981 22982 RenderNode renderNode = null; 22983 Bitmap cache = null; 22984 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 22985 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 22986 if (layerType != LAYER_TYPE_NONE) { 22987 // If not drawing with RenderNode, treat HW layers as SW 22988 layerType = LAYER_TYPE_SOFTWARE; 22989 buildDrawingCache(true); 22990 } 22991 cache = getDrawingCache(true); 22992 } 22993 22994 if (drawingWithRenderNode) { 22995 // Delay getting the display list until animation-driven alpha values are 22996 // set up and possibly passed on to the view 22997 renderNode = updateDisplayListIfDirty(); 22998 if (!renderNode.hasDisplayList()) { 22999 // Uncommon, but possible. If a view is removed from the hierarchy during the call 23000 // to getDisplayList(), the display list will be marked invalid and we should not 23001 // try to use it again. 23002 renderNode = null; 23003 drawingWithRenderNode = false; 23004 } 23005 } 23006 23007 int sx = 0; 23008 int sy = 0; 23009 if (!drawingWithRenderNode) { 23010 computeScroll(); 23011 sx = mScrollX; 23012 sy = mScrollY; 23013 } 23014 23015 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 23016 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 23017 23018 int restoreTo = -1; 23019 if (!drawingWithRenderNode || transformToApply != null) { 23020 restoreTo = canvas.save(); 23021 } 23022 if (offsetForScroll) { 23023 canvas.translate(mLeft - sx, mTop - sy); 23024 } else { 23025 if (!drawingWithRenderNode) { 23026 canvas.translate(mLeft, mTop); 23027 } 23028 if (scalingRequired) { 23029 if (drawingWithRenderNode) { 23030 // TODO: Might not need this if we put everything inside the DL 23031 restoreTo = canvas.save(); 23032 } 23033 // mAttachInfo cannot be null, otherwise scalingRequired == false 23034 final float scale = 1.0f / mAttachInfo.mApplicationScale; 23035 canvas.scale(scale, scale); 23036 } 23037 } 23038 23039 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 23040 if (transformToApply != null 23041 || alpha < 1 23042 || !hasIdentityMatrix() 23043 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 23044 if (transformToApply != null || !childHasIdentityMatrix) { 23045 int transX = 0; 23046 int transY = 0; 23047 23048 if (offsetForScroll) { 23049 transX = -sx; 23050 transY = -sy; 23051 } 23052 23053 if (transformToApply != null) { 23054 if (concatMatrix) { 23055 if (drawingWithRenderNode) { 23056 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 23057 } else { 23058 // Undo the scroll translation, apply the transformation matrix, 23059 // then redo the scroll translate to get the correct result. 23060 canvas.translate(-transX, -transY); 23061 canvas.concat(transformToApply.getMatrix()); 23062 canvas.translate(transX, transY); 23063 } 23064 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23065 } 23066 23067 float transformAlpha = transformToApply.getAlpha(); 23068 if (transformAlpha < 1) { 23069 alpha *= transformAlpha; 23070 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23071 } 23072 } 23073 23074 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 23075 canvas.translate(-transX, -transY); 23076 canvas.concat(getMatrix()); 23077 canvas.translate(transX, transY); 23078 } 23079 } 23080 23081 // Deal with alpha if it is or used to be <1 23082 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 23083 if (alpha < 1) { 23084 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 23085 } else { 23086 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 23087 } 23088 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23089 if (!drawingWithDrawingCache) { 23090 final int multipliedAlpha = (int) (255 * alpha); 23091 if (!onSetAlpha(multipliedAlpha)) { 23092 if (drawingWithRenderNode) { 23093 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 23094 } else if (layerType == LAYER_TYPE_NONE) { 23095 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 23096 multipliedAlpha); 23097 } 23098 } else { 23099 // Alpha is handled by the child directly, clobber the layer's alpha 23100 mPrivateFlags |= PFLAG_ALPHA_SET; 23101 } 23102 } 23103 } 23104 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 23105 onSetAlpha(255); 23106 mPrivateFlags &= ~PFLAG_ALPHA_SET; 23107 } 23108 23109 if (!drawingWithRenderNode) { 23110 // apply clips directly, since RenderNode won't do it for this draw 23111 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 23112 if (offsetForScroll) { 23113 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 23114 } else { 23115 if (!scalingRequired || cache == null) { 23116 canvas.clipRect(0, 0, getWidth(), getHeight()); 23117 } else { 23118 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 23119 } 23120 } 23121 } 23122 23123 if (mClipBounds != null) { 23124 // clip bounds ignore scroll 23125 canvas.clipRect(mClipBounds); 23126 } 23127 } 23128 23129 if (!drawingWithDrawingCache) { 23130 if (drawingWithRenderNode) { 23131 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23132 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 23133 } else { 23134 // Fast path for layouts with no backgrounds 23135 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 23136 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23137 dispatchDraw(canvas); 23138 } else { 23139 draw(canvas); 23140 } 23141 } 23142 } else if (cache != null) { 23143 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23144 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 23145 // no layer paint, use temporary paint to draw bitmap 23146 Paint cachePaint = parent.mCachePaint; 23147 if (cachePaint == null) { 23148 cachePaint = new Paint(); 23149 cachePaint.setDither(false); 23150 parent.mCachePaint = cachePaint; 23151 } 23152 cachePaint.setAlpha((int) (alpha * 255)); 23153 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 23154 } else { 23155 // use layer paint to draw the bitmap, merging the two alphas, but also restore 23156 int layerPaintAlpha = mLayerPaint.getAlpha(); 23157 if (alpha < 1) { 23158 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 23159 } 23160 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 23161 if (alpha < 1) { 23162 mLayerPaint.setAlpha(layerPaintAlpha); 23163 } 23164 } 23165 } 23166 23167 if (restoreTo >= 0) { 23168 canvas.restoreToCount(restoreTo); 23169 } 23170 23171 if (a != null && !more) { 23172 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 23173 onSetAlpha(255); 23174 } 23175 parent.finishAnimatingView(this, a); 23176 } 23177 23178 if (more && hardwareAcceleratedCanvas) { 23179 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 23180 // alpha animations should cause the child to recreate its display list 23181 invalidate(true); 23182 } 23183 } 23184 23185 mRecreateDisplayList = false; 23186 23187 return more; 23188 } 23189 getDebugPaint()23190 static Paint getDebugPaint() { 23191 if (sDebugPaint == null) { 23192 sDebugPaint = new Paint(); 23193 sDebugPaint.setAntiAlias(false); 23194 } 23195 return sDebugPaint; 23196 } 23197 dipsToPixels(int dips)23198 final int dipsToPixels(int dips) { 23199 float scale = getContext().getResources().getDisplayMetrics().density; 23200 return (int) (dips * scale + 0.5f); 23201 } 23202 debugDrawFocus(Canvas canvas)23203 final private void debugDrawFocus(Canvas canvas) { 23204 if (isFocused()) { 23205 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 23206 final int l = mScrollX; 23207 final int r = l + mRight - mLeft; 23208 final int t = mScrollY; 23209 final int b = t + mBottom - mTop; 23210 23211 final Paint paint = getDebugPaint(); 23212 paint.setColor(DEBUG_CORNERS_COLOR); 23213 23214 // Draw squares in corners. 23215 paint.setStyle(Paint.Style.FILL); 23216 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 23217 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 23218 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 23219 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 23220 23221 // Draw big X across the view. 23222 paint.setStyle(Paint.Style.STROKE); 23223 canvas.drawLine(l, t, r, b, paint); 23224 canvas.drawLine(l, b, r, t, paint); 23225 } 23226 } 23227 23228 /** 23229 * Manually render this view (and all of its children) to the given Canvas. 23230 * The view must have already done a full layout before this function is 23231 * called. When implementing a view, implement 23232 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 23233 * If you do need to override this method, call the superclass version. 23234 * 23235 * @param canvas The Canvas to which the View is rendered. 23236 */ 23237 @CallSuper draw(Canvas canvas)23238 public void draw(Canvas canvas) { 23239 final int privateFlags = mPrivateFlags; 23240 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 23241 23242 /* 23243 * Draw traversal performs several drawing steps which must be executed 23244 * in the appropriate order: 23245 * 23246 * 1. Draw the background 23247 * 2. If necessary, save the canvas' layers to prepare for fading 23248 * 3. Draw view's content 23249 * 4. Draw children 23250 * 5. If necessary, draw the fading edges and restore layers 23251 * 6. Draw decorations (scrollbars for instance) 23252 * 7. If necessary, draw the default focus highlight 23253 */ 23254 23255 // Step 1, draw the background, if needed 23256 int saveCount; 23257 23258 drawBackground(canvas); 23259 23260 // skip step 2 & 5 if possible (common case) 23261 final int viewFlags = mViewFlags; 23262 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 23263 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 23264 if (!verticalEdges && !horizontalEdges) { 23265 // Step 3, draw the content 23266 onDraw(canvas); 23267 23268 // Step 4, draw the children 23269 dispatchDraw(canvas); 23270 23271 drawAutofilledHighlight(canvas); 23272 23273 // Overlay is part of the content and draws beneath Foreground 23274 if (mOverlay != null && !mOverlay.isEmpty()) { 23275 mOverlay.getOverlayView().dispatchDraw(canvas); 23276 } 23277 23278 // Step 6, draw decorations (foreground, scrollbars) 23279 onDrawForeground(canvas); 23280 23281 // Step 7, draw the default focus highlight 23282 drawDefaultFocusHighlight(canvas); 23283 23284 if (isShowingLayoutBounds()) { 23285 debugDrawFocus(canvas); 23286 } 23287 23288 // we're done... 23289 return; 23290 } 23291 23292 /* 23293 * Here we do the full fledged routine... 23294 * (this is an uncommon case where speed matters less, 23295 * this is why we repeat some of the tests that have been 23296 * done above) 23297 */ 23298 23299 boolean drawTop = false; 23300 boolean drawBottom = false; 23301 boolean drawLeft = false; 23302 boolean drawRight = false; 23303 23304 float topFadeStrength = 0.0f; 23305 float bottomFadeStrength = 0.0f; 23306 float leftFadeStrength = 0.0f; 23307 float rightFadeStrength = 0.0f; 23308 23309 // Step 2, save the canvas' layers 23310 int paddingLeft = mPaddingLeft; 23311 23312 final boolean offsetRequired = isPaddingOffsetRequired(); 23313 if (offsetRequired) { 23314 paddingLeft += getLeftPaddingOffset(); 23315 } 23316 23317 int left = mScrollX + paddingLeft; 23318 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 23319 int top = mScrollY + getFadeTop(offsetRequired); 23320 int bottom = top + getFadeHeight(offsetRequired); 23321 23322 if (offsetRequired) { 23323 right += getRightPaddingOffset(); 23324 bottom += getBottomPaddingOffset(); 23325 } 23326 23327 final ScrollabilityCache scrollabilityCache = mScrollCache; 23328 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 23329 int length = (int) fadeHeight; 23330 23331 // clip the fade length if top and bottom fades overlap 23332 // overlapping fades produce odd-looking artifacts 23333 if (verticalEdges && (top + length > bottom - length)) { 23334 length = (bottom - top) / 2; 23335 } 23336 23337 // also clip horizontal fades if necessary 23338 if (horizontalEdges && (left + length > right - length)) { 23339 length = (right - left) / 2; 23340 } 23341 23342 if (verticalEdges) { 23343 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 23344 drawTop = topFadeStrength * fadeHeight > 1.0f; 23345 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 23346 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 23347 } 23348 23349 if (horizontalEdges) { 23350 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 23351 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 23352 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 23353 drawRight = rightFadeStrength * fadeHeight > 1.0f; 23354 } 23355 23356 saveCount = canvas.getSaveCount(); 23357 int topSaveCount = -1; 23358 int bottomSaveCount = -1; 23359 int leftSaveCount = -1; 23360 int rightSaveCount = -1; 23361 23362 int solidColor = getSolidColor(); 23363 if (solidColor == 0) { 23364 if (drawTop) { 23365 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 23366 } 23367 23368 if (drawBottom) { 23369 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 23370 } 23371 23372 if (drawLeft) { 23373 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 23374 } 23375 23376 if (drawRight) { 23377 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 23378 } 23379 } else { 23380 scrollabilityCache.setFadeColor(solidColor); 23381 } 23382 23383 // Step 3, draw the content 23384 onDraw(canvas); 23385 23386 // Step 4, draw the children 23387 dispatchDraw(canvas); 23388 23389 // Step 5, draw the fade effect and restore layers 23390 final Paint p = scrollabilityCache.paint; 23391 final Matrix matrix = scrollabilityCache.matrix; 23392 final Shader fade = scrollabilityCache.shader; 23393 23394 // must be restored in the reverse order that they were saved 23395 if (drawRight) { 23396 matrix.setScale(1, fadeHeight * rightFadeStrength); 23397 matrix.postRotate(90); 23398 matrix.postTranslate(right, top); 23399 fade.setLocalMatrix(matrix); 23400 p.setShader(fade); 23401 if (solidColor == 0) { 23402 canvas.restoreUnclippedLayer(rightSaveCount, p); 23403 23404 } else { 23405 canvas.drawRect(right - length, top, right, bottom, p); 23406 } 23407 } 23408 23409 if (drawLeft) { 23410 matrix.setScale(1, fadeHeight * leftFadeStrength); 23411 matrix.postRotate(-90); 23412 matrix.postTranslate(left, top); 23413 fade.setLocalMatrix(matrix); 23414 p.setShader(fade); 23415 if (solidColor == 0) { 23416 canvas.restoreUnclippedLayer(leftSaveCount, p); 23417 } else { 23418 canvas.drawRect(left, top, left + length, bottom, p); 23419 } 23420 } 23421 23422 if (drawBottom) { 23423 matrix.setScale(1, fadeHeight * bottomFadeStrength); 23424 matrix.postRotate(180); 23425 matrix.postTranslate(left, bottom); 23426 fade.setLocalMatrix(matrix); 23427 p.setShader(fade); 23428 if (solidColor == 0) { 23429 canvas.restoreUnclippedLayer(bottomSaveCount, p); 23430 } else { 23431 canvas.drawRect(left, bottom - length, right, bottom, p); 23432 } 23433 } 23434 23435 if (drawTop) { 23436 matrix.setScale(1, fadeHeight * topFadeStrength); 23437 matrix.postTranslate(left, top); 23438 fade.setLocalMatrix(matrix); 23439 p.setShader(fade); 23440 if (solidColor == 0) { 23441 canvas.restoreUnclippedLayer(topSaveCount, p); 23442 } else { 23443 canvas.drawRect(left, top, right, top + length, p); 23444 } 23445 } 23446 23447 canvas.restoreToCount(saveCount); 23448 23449 drawAutofilledHighlight(canvas); 23450 23451 // Overlay is part of the content and draws beneath Foreground 23452 if (mOverlay != null && !mOverlay.isEmpty()) { 23453 mOverlay.getOverlayView().dispatchDraw(canvas); 23454 } 23455 23456 // Step 6, draw decorations (foreground, scrollbars) 23457 onDrawForeground(canvas); 23458 23459 // Step 7, draw the default focus highlight 23460 drawDefaultFocusHighlight(canvas); 23461 23462 if (isShowingLayoutBounds()) { 23463 debugDrawFocus(canvas); 23464 } 23465 } 23466 23467 /** 23468 * Draws the background onto the specified canvas. 23469 * 23470 * @param canvas Canvas on which to draw the background 23471 */ 23472 @UnsupportedAppUsage drawBackground(Canvas canvas)23473 private void drawBackground(Canvas canvas) { 23474 final Drawable background = mBackground; 23475 if (background == null) { 23476 return; 23477 } 23478 23479 setBackgroundBounds(); 23480 23481 // Attempt to use a display list if requested. 23482 if (canvas.isHardwareAccelerated() && mAttachInfo != null 23483 && mAttachInfo.mThreadedRenderer != null) { 23484 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 23485 23486 final RenderNode renderNode = mBackgroundRenderNode; 23487 if (renderNode != null && renderNode.hasDisplayList()) { 23488 setBackgroundRenderNodeProperties(renderNode); 23489 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 23490 return; 23491 } 23492 } 23493 23494 final int scrollX = mScrollX; 23495 final int scrollY = mScrollY; 23496 if ((scrollX | scrollY) == 0) { 23497 background.draw(canvas); 23498 } else { 23499 canvas.translate(scrollX, scrollY); 23500 background.draw(canvas); 23501 canvas.translate(-scrollX, -scrollY); 23502 } 23503 } 23504 23505 /** 23506 * Sets the correct background bounds and rebuilds the outline, if needed. 23507 * <p/> 23508 * This is called by LayoutLib. 23509 */ setBackgroundBounds()23510 void setBackgroundBounds() { 23511 if (mBackgroundSizeChanged && mBackground != null) { 23512 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 23513 mBackgroundSizeChanged = false; 23514 rebuildOutline(); 23515 } 23516 } 23517 setBackgroundRenderNodeProperties(RenderNode renderNode)23518 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 23519 renderNode.setTranslationX(mScrollX); 23520 renderNode.setTranslationY(mScrollY); 23521 } 23522 23523 /** 23524 * Creates a new display list or updates the existing display list for the 23525 * specified Drawable. 23526 * 23527 * @param drawable Drawable for which to create a display list 23528 * @param renderNode Existing RenderNode, or {@code null} 23529 * @return A valid display list for the specified drawable 23530 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)23531 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 23532 if (renderNode == null) { 23533 renderNode = RenderNode.create(drawable.getClass().getName(), 23534 new ViewAnimationHostBridge(this)); 23535 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 23536 } 23537 23538 final Rect bounds = drawable.getBounds(); 23539 final int width = bounds.width(); 23540 final int height = bounds.height(); 23541 23542 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 23543 // instead of being "stateful" like other RenderNode properties 23544 renderNode.clearStretch(); 23545 23546 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 23547 23548 // Reverse left/top translation done by drawable canvas, which will 23549 // instead be applied by rendernode's LTRB bounds below. This way, the 23550 // drawable's bounds match with its rendernode bounds and its content 23551 // will lie within those bounds in the rendernode tree. 23552 canvas.translate(-bounds.left, -bounds.top); 23553 23554 try { 23555 drawable.draw(canvas); 23556 } finally { 23557 renderNode.endRecording(); 23558 } 23559 23560 // Set up drawable properties that are view-independent. 23561 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 23562 renderNode.setProjectBackwards(drawable.isProjected()); 23563 renderNode.setProjectionReceiver(true); 23564 renderNode.setClipToBounds(false); 23565 return renderNode; 23566 } 23567 23568 /** 23569 * Returns the overlay for this view, creating it if it does not yet exist. 23570 * Adding drawables to the overlay will cause them to be displayed whenever 23571 * the view itself is redrawn. Objects in the overlay should be actively 23572 * managed: remove them when they should not be displayed anymore. The 23573 * overlay will always have the same size as its host view. 23574 * 23575 * <p>Note: Overlays do not currently work correctly with {@link 23576 * SurfaceView} or {@link TextureView}; contents in overlays for these 23577 * types of views may not display correctly.</p> 23578 * 23579 * @return The ViewOverlay object for this view. 23580 * @see ViewOverlay 23581 */ getOverlay()23582 public ViewOverlay getOverlay() { 23583 if (mOverlay == null) { 23584 mOverlay = new ViewOverlay(mContext, this); 23585 } 23586 return mOverlay; 23587 } 23588 23589 /** 23590 * Override this if your view is known to always be drawn on top of a solid color background, 23591 * and needs to draw fading edges. Returning a non-zero color enables the view system to 23592 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 23593 * should be set to 0xFF. 23594 * 23595 * @see #setVerticalFadingEdgeEnabled(boolean) 23596 * @see #setHorizontalFadingEdgeEnabled(boolean) 23597 * 23598 * @return The known solid color background for this view, or 0 if the color may vary 23599 */ 23600 @ViewDebug.ExportedProperty(category = "drawing") 23601 @InspectableProperty 23602 @ColorInt getSolidColor()23603 public int getSolidColor() { 23604 return 0; 23605 } 23606 23607 /** 23608 * Build a human readable string representation of the specified view flags. 23609 * 23610 * @param flags the view flags to convert to a string 23611 * @return a String representing the supplied flags 23612 */ printFlags(int flags)23613 private static String printFlags(int flags) { 23614 String output = ""; 23615 int numFlags = 0; 23616 if ((flags & FOCUSABLE) == FOCUSABLE) { 23617 output += "TAKES_FOCUS"; 23618 numFlags++; 23619 } 23620 23621 switch (flags & VISIBILITY_MASK) { 23622 case INVISIBLE: 23623 if (numFlags > 0) { 23624 output += " "; 23625 } 23626 output += "INVISIBLE"; 23627 // USELESS HERE numFlags++; 23628 break; 23629 case GONE: 23630 if (numFlags > 0) { 23631 output += " "; 23632 } 23633 output += "GONE"; 23634 // USELESS HERE numFlags++; 23635 break; 23636 default: 23637 break; 23638 } 23639 return output; 23640 } 23641 23642 /** 23643 * Build a human readable string representation of the specified private 23644 * view flags. 23645 * 23646 * @param privateFlags the private view flags to convert to a string 23647 * @return a String representing the supplied flags 23648 */ printPrivateFlags(int privateFlags)23649 private static String printPrivateFlags(int privateFlags) { 23650 String output = ""; 23651 int numFlags = 0; 23652 23653 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 23654 output += "WANTS_FOCUS"; 23655 numFlags++; 23656 } 23657 23658 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 23659 if (numFlags > 0) { 23660 output += " "; 23661 } 23662 output += "FOCUSED"; 23663 numFlags++; 23664 } 23665 23666 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 23667 if (numFlags > 0) { 23668 output += " "; 23669 } 23670 output += "SELECTED"; 23671 numFlags++; 23672 } 23673 23674 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 23675 if (numFlags > 0) { 23676 output += " "; 23677 } 23678 output += "IS_ROOT_NAMESPACE"; 23679 numFlags++; 23680 } 23681 23682 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 23683 if (numFlags > 0) { 23684 output += " "; 23685 } 23686 output += "HAS_BOUNDS"; 23687 numFlags++; 23688 } 23689 23690 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 23691 if (numFlags > 0) { 23692 output += " "; 23693 } 23694 output += "DRAWN"; 23695 // USELESS HERE numFlags++; 23696 } 23697 return output; 23698 } 23699 23700 /** 23701 * <p>Indicates whether or not this view's layout will be requested during 23702 * the next hierarchy layout pass.</p> 23703 * 23704 * @return true if the layout will be forced during next layout pass 23705 */ isLayoutRequested()23706 public boolean isLayoutRequested() { 23707 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 23708 } 23709 23710 /** 23711 * Return true if o is a ViewGroup that is laying out using optical bounds. 23712 * @hide 23713 */ isLayoutModeOptical(Object o)23714 public static boolean isLayoutModeOptical(Object o) { 23715 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 23716 } 23717 23718 /** 23719 * Enable measure/layout debugging on traces. 23720 * 23721 * @see Trace 23722 * @hide 23723 */ setTraceLayoutSteps(boolean traceLayoutSteps)23724 public static void setTraceLayoutSteps(boolean traceLayoutSteps) { 23725 sTraceLayoutSteps = traceLayoutSteps; 23726 } 23727 23728 /** 23729 * Enable request layout tracing classes with {@code s} simple name. 23730 * <p> 23731 * When set, a {@link Trace} instant event and a log with the stacktrace is emitted every 23732 * time a requestLayout of a class matching {@code s} name happens. 23733 * This applies only to views attached from this point onwards. 23734 * 23735 * @see Trace#instant(long, String) 23736 * @hide 23737 */ setTracedRequestLayoutClassClass(String s)23738 public static void setTracedRequestLayoutClassClass(String s) { 23739 sTraceRequestLayoutClass = s; 23740 } 23741 setOpticalFrame(int left, int top, int right, int bottom)23742 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 23743 Insets parentInsets = mParent instanceof View ? 23744 ((View) mParent).getOpticalInsets() : Insets.NONE; 23745 Insets childInsets = getOpticalInsets(); 23746 return setFrame( 23747 left + parentInsets.left - childInsets.left, 23748 top + parentInsets.top - childInsets.top, 23749 right + parentInsets.left + childInsets.right, 23750 bottom + parentInsets.top + childInsets.bottom); 23751 } 23752 23753 /** 23754 * Assign a size and position to a view and all of its 23755 * descendants 23756 * 23757 * <p>This is the second phase of the layout mechanism. 23758 * (The first is measuring). In this phase, each parent calls 23759 * layout on all of its children to position them. 23760 * This is typically done using the child measurements 23761 * that were stored in the measure pass().</p> 23762 * 23763 * <p>Derived classes should not override this method. 23764 * Derived classes with children should override 23765 * onLayout. In that method, they should 23766 * call layout on each of their children.</p> 23767 * 23768 * @param l Left position, relative to parent 23769 * @param t Top position, relative to parent 23770 * @param r Right position, relative to parent 23771 * @param b Bottom position, relative to parent 23772 */ 23773 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)23774 public void layout(int l, int t, int r, int b) { 23775 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 23776 if (isTraversalTracingEnabled()) { 23777 Trace.beginSection(mTracingStrings.onMeasureBeforeLayout); 23778 } 23779 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 23780 if (isTraversalTracingEnabled()) { 23781 Trace.endSection(); 23782 } 23783 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 23784 } 23785 23786 int oldL = mLeft; 23787 int oldT = mTop; 23788 int oldB = mBottom; 23789 int oldR = mRight; 23790 23791 boolean changed = isLayoutModeOptical(mParent) ? 23792 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 23793 23794 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 23795 if (isTraversalTracingEnabled()) { 23796 Trace.beginSection(mTracingStrings.onLayout); 23797 } 23798 onLayout(changed, l, t, r, b); 23799 if (isTraversalTracingEnabled()) { 23800 Trace.endSection(); 23801 } 23802 23803 if (shouldDrawRoundScrollbar()) { 23804 if(mRoundScrollbarRenderer == null) { 23805 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 23806 } 23807 } else { 23808 mRoundScrollbarRenderer = null; 23809 } 23810 23811 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 23812 23813 ListenerInfo li = mListenerInfo; 23814 if (li != null && li.mOnLayoutChangeListeners != null) { 23815 ArrayList<OnLayoutChangeListener> listenersCopy = 23816 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 23817 int numListeners = listenersCopy.size(); 23818 for (int i = 0; i < numListeners; ++i) { 23819 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 23820 } 23821 } 23822 } 23823 23824 final boolean wasLayoutValid = isLayoutValid(); 23825 23826 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 23827 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 23828 23829 if (!wasLayoutValid && isFocused()) { 23830 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 23831 if (canTakeFocus()) { 23832 // We have a robust focus, so parents should no longer be wanting focus. 23833 clearParentsWantFocus(); 23834 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 23835 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 23836 // layout. In this case, there's no guarantee that parent layouts will be evaluated 23837 // and thus the safest action is to clear focus here. 23838 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23839 clearParentsWantFocus(); 23840 } else if (!hasParentWantsFocus()) { 23841 // original requestFocus was likely on this view directly, so just clear focus 23842 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23843 } 23844 // otherwise, we let parents handle re-assigning focus during their layout passes. 23845 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 23846 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 23847 View focused = findFocus(); 23848 if (focused != null) { 23849 // Try to restore focus as close as possible to our starting focus. 23850 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 23851 // Give up and clear focus once we've reached the top-most parent which wants 23852 // focus. 23853 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23854 } 23855 } 23856 } 23857 23858 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 23859 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 23860 notifyEnterOrExitForAutoFillIfNeeded(true); 23861 } 23862 23863 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 23864 } 23865 hasParentWantsFocus()23866 private boolean hasParentWantsFocus() { 23867 ViewParent parent = mParent; 23868 while (parent instanceof ViewGroup) { 23869 ViewGroup pv = (ViewGroup) parent; 23870 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 23871 return true; 23872 } 23873 parent = pv.mParent; 23874 } 23875 return false; 23876 } 23877 23878 /** 23879 * Called from layout when this view should 23880 * assign a size and position to each of its children. 23881 * 23882 * Derived classes with children should override 23883 * this method and call layout on each of 23884 * their children. 23885 * @param changed This is a new size or position for this view 23886 * @param left Left position, relative to parent 23887 * @param top Top position, relative to parent 23888 * @param right Right position, relative to parent 23889 * @param bottom Bottom position, relative to parent 23890 */ onLayout(boolean changed, int left, int top, int right, int bottom)23891 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 23892 } 23893 23894 /** 23895 * Assign a size and position to this view. 23896 * 23897 * This is called from layout. 23898 * 23899 * @param left Left position, relative to parent 23900 * @param top Top position, relative to parent 23901 * @param right Right position, relative to parent 23902 * @param bottom Bottom position, relative to parent 23903 * @return true if the new size and position are different than the 23904 * previous ones 23905 * {@hide} 23906 */ 23907 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)23908 protected boolean setFrame(int left, int top, int right, int bottom) { 23909 boolean changed = false; 23910 23911 if (DBG) { 23912 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 23913 + right + "," + bottom + ")"); 23914 } 23915 23916 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 23917 changed = true; 23918 23919 // Remember our drawn bit 23920 int drawn = mPrivateFlags & PFLAG_DRAWN; 23921 23922 int oldWidth = mRight - mLeft; 23923 int oldHeight = mBottom - mTop; 23924 int newWidth = right - left; 23925 int newHeight = bottom - top; 23926 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 23927 23928 // Invalidate our old position 23929 invalidate(sizeChanged); 23930 23931 mLeft = left; 23932 mTop = top; 23933 mRight = right; 23934 mBottom = bottom; 23935 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 23936 23937 mPrivateFlags |= PFLAG_HAS_BOUNDS; 23938 23939 23940 if (sizeChanged) { 23941 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 23942 } 23943 23944 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 23945 // If we are visible, force the DRAWN bit to on so that 23946 // this invalidate will go through (at least to our parent). 23947 // This is because someone may have invalidated this view 23948 // before this call to setFrame came in, thereby clearing 23949 // the DRAWN bit. 23950 mPrivateFlags |= PFLAG_DRAWN; 23951 invalidate(sizeChanged); 23952 // parent display list may need to be recreated based on a change in the bounds 23953 // of any child 23954 invalidateParentCaches(); 23955 } 23956 23957 // Reset drawn bit to original value (invalidate turns it off) 23958 mPrivateFlags |= drawn; 23959 23960 mBackgroundSizeChanged = true; 23961 mDefaultFocusHighlightSizeChanged = true; 23962 if (mForegroundInfo != null) { 23963 mForegroundInfo.mBoundsChanged = true; 23964 } 23965 23966 notifySubtreeAccessibilityStateChangedIfNeeded(); 23967 } 23968 return changed; 23969 } 23970 23971 /** 23972 * Assign a size and position to this view. 23973 * 23974 * This method is meant to be used in animations only as it applies this position and size 23975 * for the view only temporary and it can be changed back at any time by the layout. 23976 * 23977 * @param left Left position, relative to parent 23978 * @param top Top position, relative to parent 23979 * @param right Right position, relative to parent 23980 * @param bottom Bottom position, relative to parent 23981 * 23982 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 23983 */ setLeftTopRightBottom(int left, int top, int right, int bottom)23984 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 23985 setFrame(left, top, right, bottom); 23986 } 23987 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)23988 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 23989 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 23990 if (mOverlay != null) { 23991 mOverlay.getOverlayView().setRight(newWidth); 23992 mOverlay.getOverlayView().setBottom(newHeight); 23993 } 23994 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 23995 // backtracking" of requestFocus during layout, so don't touch focus here. 23996 if (!sCanFocusZeroSized && isLayoutValid() 23997 // Don't touch focus if animating 23998 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 23999 if (newWidth <= 0 || newHeight <= 0) { 24000 if (hasFocus()) { 24001 clearFocus(); 24002 if (mParent instanceof ViewGroup) { 24003 ((ViewGroup) mParent).clearFocusedInCluster(); 24004 } 24005 } 24006 clearAccessibilityFocus(); 24007 } else if (oldWidth <= 0 || oldHeight <= 0) { 24008 if (mParent != null && canTakeFocus()) { 24009 mParent.focusableViewAvailable(this); 24010 } 24011 } 24012 } 24013 rebuildOutline(); 24014 } 24015 24016 /** 24017 * Finalize inflating a view from XML. This is called as the last phase 24018 * of inflation, after all child views have been added. 24019 * 24020 * <p>Even if the subclass overrides onFinishInflate, they should always be 24021 * sure to call the super method, so that we get called. 24022 */ 24023 @CallSuper onFinishInflate()24024 protected void onFinishInflate() { 24025 } 24026 24027 /** 24028 * Returns the resources associated with this view. 24029 * 24030 * @return Resources object. 24031 */ getResources()24032 public Resources getResources() { 24033 return mResources; 24034 } 24035 24036 /** 24037 * Invalidates the specified Drawable. 24038 * 24039 * @param drawable the drawable to invalidate 24040 */ 24041 @Override invalidateDrawable(@onNull Drawable drawable)24042 public void invalidateDrawable(@NonNull Drawable drawable) { 24043 if (verifyDrawable(drawable)) { 24044 final Rect dirty = drawable.getDirtyBounds(); 24045 final int scrollX = mScrollX; 24046 final int scrollY = mScrollY; 24047 24048 invalidate(dirty.left + scrollX, dirty.top + scrollY, 24049 dirty.right + scrollX, dirty.bottom + scrollY); 24050 rebuildOutline(); 24051 } 24052 } 24053 24054 /** 24055 * Schedules an action on a drawable to occur at a specified time. 24056 * 24057 * @param who the recipient of the action 24058 * @param what the action to run on the drawable 24059 * @param when the time at which the action must occur. Uses the 24060 * {@link SystemClock#uptimeMillis} timebase. 24061 */ 24062 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)24063 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 24064 if (verifyDrawable(who) && what != null) { 24065 final long delay = when - SystemClock.uptimeMillis(); 24066 if (mAttachInfo != null) { 24067 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 24068 Choreographer.CALLBACK_ANIMATION, what, who, 24069 Choreographer.subtractFrameDelay(delay)); 24070 } else { 24071 // Postpone the runnable until we know 24072 // on which thread it needs to run. 24073 getRunQueue().postDelayed(what, delay); 24074 } 24075 } 24076 } 24077 24078 /** 24079 * Cancels a scheduled action on a drawable. 24080 * 24081 * @param who the recipient of the action 24082 * @param what the action to cancel 24083 */ 24084 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)24085 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 24086 if (verifyDrawable(who) && what != null) { 24087 if (mAttachInfo != null) { 24088 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 24089 Choreographer.CALLBACK_ANIMATION, what, who); 24090 } 24091 getRunQueue().removeCallbacks(what); 24092 } 24093 } 24094 24095 /** 24096 * Unschedule any events associated with the given Drawable. This can be 24097 * used when selecting a new Drawable into a view, so that the previous 24098 * one is completely unscheduled. 24099 * 24100 * @param who The Drawable to unschedule. 24101 * 24102 * @see #drawableStateChanged 24103 */ unscheduleDrawable(Drawable who)24104 public void unscheduleDrawable(Drawable who) { 24105 if (mAttachInfo != null && who != null) { 24106 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 24107 Choreographer.CALLBACK_ANIMATION, null, who); 24108 } 24109 } 24110 24111 /** 24112 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 24113 * that the View directionality can and will be resolved before its Drawables. 24114 * 24115 * Will call {@link View#onResolveDrawables} when resolution is done. 24116 * 24117 * @hide 24118 */ resolveDrawables()24119 protected void resolveDrawables() { 24120 // Drawables resolution may need to happen before resolving the layout direction (which is 24121 // done only during the measure() call). 24122 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 24123 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 24124 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 24125 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 24126 // direction to be resolved as its resolved value will be the same as its raw value. 24127 if (!isLayoutDirectionResolved() && 24128 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 24129 return; 24130 } 24131 24132 final int layoutDirection = isLayoutDirectionResolved() ? 24133 getLayoutDirection() : getRawLayoutDirection(); 24134 24135 if (mBackground != null) { 24136 mBackground.setLayoutDirection(layoutDirection); 24137 } 24138 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 24139 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 24140 } 24141 if (mDefaultFocusHighlight != null) { 24142 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 24143 } 24144 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 24145 onResolveDrawables(layoutDirection); 24146 } 24147 areDrawablesResolved()24148 boolean areDrawablesResolved() { 24149 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 24150 } 24151 24152 /** 24153 * Called when layout direction has been resolved. 24154 * 24155 * The default implementation does nothing. 24156 * 24157 * @param layoutDirection The resolved layout direction. 24158 * 24159 * @see #LAYOUT_DIRECTION_LTR 24160 * @see #LAYOUT_DIRECTION_RTL 24161 * 24162 * @hide 24163 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)24164 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 24165 } 24166 24167 /** 24168 * @hide 24169 */ 24170 @TestApi resetResolvedDrawables()24171 protected void resetResolvedDrawables() { 24172 resetResolvedDrawablesInternal(); 24173 } 24174 resetResolvedDrawablesInternal()24175 void resetResolvedDrawablesInternal() { 24176 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 24177 } 24178 24179 /** 24180 * If your view subclass is displaying its own Drawable objects, it should 24181 * override this function and return true for any Drawable it is 24182 * displaying. This allows animations for those drawables to be 24183 * scheduled. 24184 * 24185 * <p>Be sure to call through to the super class when overriding this 24186 * function. 24187 * 24188 * @param who The Drawable to verify. Return true if it is one you are 24189 * displaying, else return the result of calling through to the 24190 * super class. 24191 * 24192 * @return boolean If true then the Drawable is being displayed in the 24193 * view; else false and it is not allowed to animate. 24194 * 24195 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 24196 * @see #drawableStateChanged() 24197 */ 24198 @CallSuper verifyDrawable(@onNull Drawable who)24199 protected boolean verifyDrawable(@NonNull Drawable who) { 24200 // Avoid verifying the scroll bar drawable so that we don't end up in 24201 // an invalidation loop. This effectively prevents the scroll bar 24202 // drawable from triggering invalidations and scheduling runnables. 24203 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 24204 || (mDefaultFocusHighlight == who); 24205 } 24206 24207 /** 24208 * This function is called whenever the state of the view changes in such 24209 * a way that it impacts the state of drawables being shown. 24210 * <p> 24211 * If the View has a StateListAnimator, it will also be called to run necessary state 24212 * change animations. 24213 * <p> 24214 * Be sure to call through to the superclass when overriding this function. 24215 * 24216 * @see Drawable#setState(int[]) 24217 */ 24218 @CallSuper drawableStateChanged()24219 protected void drawableStateChanged() { 24220 final int[] state = getDrawableState(); 24221 boolean changed = false; 24222 24223 final Drawable bg = mBackground; 24224 if (bg != null && bg.isStateful()) { 24225 changed |= bg.setState(state); 24226 } 24227 24228 final Drawable hl = mDefaultFocusHighlight; 24229 if (hl != null && hl.isStateful()) { 24230 changed |= hl.setState(state); 24231 } 24232 24233 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24234 if (fg != null && fg.isStateful()) { 24235 changed |= fg.setState(state); 24236 } 24237 24238 if (mScrollCache != null) { 24239 final Drawable scrollBar = mScrollCache.scrollBar; 24240 if (scrollBar != null && scrollBar.isStateful()) { 24241 changed |= scrollBar.setState(state) 24242 && mScrollCache.state != ScrollabilityCache.OFF; 24243 } 24244 } 24245 24246 if (mStateListAnimator != null) { 24247 mStateListAnimator.setState(state); 24248 } 24249 24250 if (!isAggregatedVisible()) { 24251 // If we're not visible, skip any animated changes 24252 jumpDrawablesToCurrentState(); 24253 } 24254 24255 if (changed) { 24256 invalidate(); 24257 } 24258 } 24259 24260 /** 24261 * This function is called whenever the view hotspot changes and needs to 24262 * be propagated to drawables or child views managed by the view. 24263 * <p> 24264 * Dispatching to child views is handled by 24265 * {@link #dispatchDrawableHotspotChanged(float, float)}. 24266 * <p> 24267 * Be sure to call through to the superclass when overriding this function. 24268 * 24269 * @param x hotspot x coordinate 24270 * @param y hotspot y coordinate 24271 */ 24272 @CallSuper drawableHotspotChanged(float x, float y)24273 public void drawableHotspotChanged(float x, float y) { 24274 if (mBackground != null) { 24275 mBackground.setHotspot(x, y); 24276 } 24277 if (mDefaultFocusHighlight != null) { 24278 mDefaultFocusHighlight.setHotspot(x, y); 24279 } 24280 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 24281 mForegroundInfo.mDrawable.setHotspot(x, y); 24282 } 24283 24284 dispatchDrawableHotspotChanged(x, y); 24285 } 24286 24287 /** 24288 * Dispatches drawableHotspotChanged to all of this View's children. 24289 * 24290 * @param x hotspot x coordinate 24291 * @param y hotspot y coordinate 24292 * @see #drawableHotspotChanged(float, float) 24293 */ dispatchDrawableHotspotChanged(float x, float y)24294 public void dispatchDrawableHotspotChanged(float x, float y) { 24295 } 24296 24297 /** 24298 * Call this to force a view to update its drawable state. This will cause 24299 * drawableStateChanged to be called on this view. Views that are interested 24300 * in the new state should call getDrawableState. 24301 * 24302 * @see #drawableStateChanged 24303 * @see #getDrawableState 24304 */ refreshDrawableState()24305 public void refreshDrawableState() { 24306 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 24307 drawableStateChanged(); 24308 24309 ViewParent parent = mParent; 24310 if (parent != null) { 24311 parent.childDrawableStateChanged(this); 24312 } 24313 } 24314 24315 /** 24316 * Create a default focus highlight if it doesn't exist. 24317 * @return a default focus highlight. 24318 */ getDefaultFocusHighlightDrawable()24319 private Drawable getDefaultFocusHighlightDrawable() { 24320 if (mDefaultFocusHighlightCache == null) { 24321 if (mContext != null) { 24322 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 24323 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 24324 mDefaultFocusHighlightCache = ta.getDrawable(0); 24325 ta.recycle(); 24326 } 24327 } 24328 return mDefaultFocusHighlightCache; 24329 } 24330 24331 /** 24332 * Set the current default focus highlight. 24333 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 24334 */ setDefaultFocusHighlight(Drawable highlight)24335 private void setDefaultFocusHighlight(Drawable highlight) { 24336 mDefaultFocusHighlight = highlight; 24337 mDefaultFocusHighlightSizeChanged = true; 24338 if (highlight != null) { 24339 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24340 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24341 } 24342 highlight.setLayoutDirection(getLayoutDirection()); 24343 if (highlight.isStateful()) { 24344 highlight.setState(getDrawableState()); 24345 } 24346 if (isAttachedToWindow()) { 24347 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24348 } 24349 // Set callback last, since the view may still be initializing. 24350 highlight.setCallback(this); 24351 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 24352 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 24353 mPrivateFlags |= PFLAG_SKIP_DRAW; 24354 } 24355 invalidate(); 24356 } 24357 24358 /** 24359 * Check whether we need to draw a default focus highlight when this view gets focused, 24360 * which requires: 24361 * <ul> 24362 * <li>In both background and foreground, {@link android.R.attr#state_focused} 24363 * is not defined.</li> 24364 * <li>This view is not in touch mode.</li> 24365 * <li>This view doesn't opt out for a default focus highlight, via 24366 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 24367 * <li>This view is attached to window.</li> 24368 * </ul> 24369 * @return {@code true} if a default focus highlight is needed. 24370 * @hide 24371 */ 24372 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)24373 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 24374 final boolean lackFocusState = (background == null || !background.isStateful() 24375 || !background.hasFocusStateSpecified()) 24376 && (foreground == null || !foreground.isStateful() 24377 || !foreground.hasFocusStateSpecified()); 24378 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 24379 && isAttachedToWindow() && sUseDefaultFocusHighlight; 24380 } 24381 24382 /** 24383 * When this view is focused, switches on/off the default focused highlight. 24384 * <p> 24385 * This always happens when this view is focused, and only at this moment the default focus 24386 * highlight can be visible. 24387 */ switchDefaultFocusHighlight()24388 private void switchDefaultFocusHighlight() { 24389 if (isFocused()) { 24390 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 24391 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 24392 final boolean active = mDefaultFocusHighlight != null; 24393 if (needed && !active) { 24394 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 24395 } else if (!needed && active) { 24396 // The highlight is no longer needed, so tear it down. 24397 setDefaultFocusHighlight(null); 24398 } 24399 } 24400 } 24401 24402 /** 24403 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 24404 * @param canvas the canvas where we're drawing the highlight. 24405 */ drawDefaultFocusHighlight(Canvas canvas)24406 private void drawDefaultFocusHighlight(Canvas canvas) { 24407 if (mDefaultFocusHighlight != null && isFocused()) { 24408 if (mDefaultFocusHighlightSizeChanged) { 24409 mDefaultFocusHighlightSizeChanged = false; 24410 final int l = mScrollX; 24411 final int r = l + mRight - mLeft; 24412 final int t = mScrollY; 24413 final int b = t + mBottom - mTop; 24414 mDefaultFocusHighlight.setBounds(l, t, r, b); 24415 } 24416 mDefaultFocusHighlight.draw(canvas); 24417 } 24418 } 24419 24420 /** 24421 * Return an array of resource IDs of the drawable states representing the 24422 * current state of the view. 24423 * 24424 * @return The current drawable state 24425 * 24426 * @see Drawable#setState(int[]) 24427 * @see #drawableStateChanged() 24428 * @see #onCreateDrawableState(int) 24429 */ getDrawableState()24430 public final int[] getDrawableState() { 24431 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 24432 return mDrawableState; 24433 } else { 24434 mDrawableState = onCreateDrawableState(0); 24435 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 24436 return mDrawableState; 24437 } 24438 } 24439 24440 /** 24441 * Generate the new {@link android.graphics.drawable.Drawable} state for 24442 * this view. This is called by the view 24443 * system when the cached Drawable state is determined to be invalid. To 24444 * retrieve the current state, you should use {@link #getDrawableState}. 24445 * 24446 * @param extraSpace if non-zero, this is the number of extra entries you 24447 * would like in the returned array in which you can place your own 24448 * states. 24449 * 24450 * @return Returns an array holding the current {@link Drawable} state of 24451 * the view. 24452 * 24453 * @see #mergeDrawableStates(int[], int[]) 24454 */ onCreateDrawableState(int extraSpace)24455 protected int[] onCreateDrawableState(int extraSpace) { 24456 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 24457 mParent instanceof View) { 24458 return ((View) mParent).onCreateDrawableState(extraSpace); 24459 } 24460 24461 int[] drawableState; 24462 24463 int privateFlags = mPrivateFlags; 24464 24465 int viewStateIndex = 0; 24466 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 24467 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 24468 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 24469 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 24470 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 24471 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 24472 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { 24473 // This is set if HW acceleration is requested, even if the current 24474 // process doesn't allow it. This is just to allow app preview 24475 // windows to better match their app. 24476 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 24477 } 24478 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 24479 24480 final int privateFlags2 = mPrivateFlags2; 24481 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 24482 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 24483 } 24484 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 24485 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 24486 } 24487 24488 drawableState = StateSet.get(viewStateIndex); 24489 24490 //noinspection ConstantIfStatement 24491 if (false) { 24492 Log.i("View", "drawableStateIndex=" + viewStateIndex); 24493 Log.i("View", toString() 24494 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 24495 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 24496 + " fo=" + hasFocus() 24497 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 24498 + " wf=" + hasWindowFocus() 24499 + ": " + Arrays.toString(drawableState)); 24500 } 24501 24502 if (extraSpace == 0) { 24503 return drawableState; 24504 } 24505 24506 final int[] fullState; 24507 if (drawableState != null) { 24508 fullState = new int[drawableState.length + extraSpace]; 24509 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 24510 } else { 24511 fullState = new int[extraSpace]; 24512 } 24513 24514 return fullState; 24515 } 24516 24517 /** 24518 * Merge your own state values in <var>additionalState</var> into the base 24519 * state values <var>baseState</var> that were returned by 24520 * {@link #onCreateDrawableState(int)}. 24521 * 24522 * @param baseState The base state values returned by 24523 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 24524 * own additional state values. 24525 * 24526 * @param additionalState The additional state values you would like 24527 * added to <var>baseState</var>; this array is not modified. 24528 * 24529 * @return As a convenience, the <var>baseState</var> array you originally 24530 * passed into the function is returned. 24531 * 24532 * @see #onCreateDrawableState(int) 24533 */ mergeDrawableStates(int[] baseState, int[] additionalState)24534 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 24535 final int N = baseState.length; 24536 int i = N - 1; 24537 while (i >= 0 && baseState[i] == 0) { 24538 i--; 24539 } 24540 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 24541 return baseState; 24542 } 24543 24544 /** 24545 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 24546 * on all Drawable objects associated with this view. 24547 * <p> 24548 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 24549 * attached to this view. 24550 */ 24551 @CallSuper jumpDrawablesToCurrentState()24552 public void jumpDrawablesToCurrentState() { 24553 if (mBackground != null) { 24554 mBackground.jumpToCurrentState(); 24555 } 24556 if (mStateListAnimator != null) { 24557 mStateListAnimator.jumpToCurrentState(); 24558 } 24559 if (mDefaultFocusHighlight != null) { 24560 mDefaultFocusHighlight.jumpToCurrentState(); 24561 } 24562 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 24563 mForegroundInfo.mDrawable.jumpToCurrentState(); 24564 } 24565 } 24566 24567 /** 24568 * Sets the background color for this view. 24569 * @param color the color of the background 24570 */ 24571 @RemotableViewMethod setBackgroundColor(@olorInt int color)24572 public void setBackgroundColor(@ColorInt int color) { 24573 if (mBackground instanceof ColorDrawable) { 24574 ((ColorDrawable) mBackground.mutate()).setColor(color); 24575 computeOpaqueFlags(); 24576 mBackgroundResource = 0; 24577 } else { 24578 setBackground(new ColorDrawable(color)); 24579 } 24580 } 24581 24582 /** 24583 * Set the background to a given resource. The resource should refer to 24584 * a Drawable object or 0 to remove the background. 24585 * @param resid The identifier of the resource. 24586 * 24587 * @attr ref android.R.styleable#View_background 24588 */ 24589 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)24590 public void setBackgroundResource(@DrawableRes int resid) { 24591 if (resid != 0 && resid == mBackgroundResource) { 24592 return; 24593 } 24594 24595 Drawable d = null; 24596 if (resid != 0) { 24597 d = mContext.getDrawable(resid); 24598 } 24599 setBackground(d); 24600 24601 mBackgroundResource = resid; 24602 } 24603 24604 /** 24605 * Set the background to a given Drawable, or remove the background. If the 24606 * background has padding, this View's padding is set to the background's 24607 * padding. However, when a background is removed, this View's padding isn't 24608 * touched. If setting the padding is desired, please use 24609 * {@link #setPadding(int, int, int, int)}. 24610 * 24611 * @param background The Drawable to use as the background, or null to remove the 24612 * background 24613 */ setBackground(Drawable background)24614 public void setBackground(Drawable background) { 24615 //noinspection deprecation 24616 setBackgroundDrawable(background); 24617 } 24618 24619 /** 24620 * @deprecated use {@link #setBackground(Drawable)} instead 24621 */ 24622 @Deprecated setBackgroundDrawable(Drawable background)24623 public void setBackgroundDrawable(Drawable background) { 24624 computeOpaqueFlags(); 24625 24626 if (background == mBackground) { 24627 return; 24628 } 24629 24630 boolean requestLayout = false; 24631 24632 mBackgroundResource = 0; 24633 24634 /* 24635 * Regardless of whether we're setting a new background or not, we want 24636 * to clear the previous drawable. setVisible first while we still have the callback set. 24637 */ 24638 if (mBackground != null) { 24639 if (isAttachedToWindow()) { 24640 mBackground.setVisible(false, false); 24641 } 24642 mBackground.setCallback(null); 24643 unscheduleDrawable(mBackground); 24644 } 24645 24646 if (background != null) { 24647 Rect padding = sThreadLocal.get(); 24648 if (padding == null) { 24649 padding = new Rect(); 24650 sThreadLocal.set(padding); 24651 } 24652 resetResolvedDrawablesInternal(); 24653 background.setLayoutDirection(getLayoutDirection()); 24654 if (background.getPadding(padding)) { 24655 resetResolvedPaddingInternal(); 24656 switch (background.getLayoutDirection()) { 24657 case LAYOUT_DIRECTION_RTL: 24658 mUserPaddingLeftInitial = padding.right; 24659 mUserPaddingRightInitial = padding.left; 24660 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 24661 break; 24662 case LAYOUT_DIRECTION_LTR: 24663 default: 24664 mUserPaddingLeftInitial = padding.left; 24665 mUserPaddingRightInitial = padding.right; 24666 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 24667 } 24668 mLeftPaddingDefined = false; 24669 mRightPaddingDefined = false; 24670 } 24671 24672 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 24673 // if it has a different minimum size, we should layout again 24674 if (mBackground == null 24675 || mBackground.getMinimumHeight() != background.getMinimumHeight() 24676 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 24677 requestLayout = true; 24678 } 24679 24680 // Set mBackground before we set this as the callback and start making other 24681 // background drawable state change calls. In particular, the setVisible call below 24682 // can result in drawables attempting to start animations or otherwise invalidate, 24683 // which requires the view set as the callback (us) to recognize the drawable as 24684 // belonging to it as per verifyDrawable. 24685 mBackground = background; 24686 if (background.isStateful()) { 24687 background.setState(getDrawableState()); 24688 } 24689 if (isAttachedToWindow()) { 24690 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24691 } 24692 24693 applyBackgroundTint(); 24694 24695 // Set callback last, since the view may still be initializing. 24696 background.setCallback(this); 24697 24698 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24699 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24700 requestLayout = true; 24701 } 24702 } else { 24703 /* Remove the background */ 24704 mBackground = null; 24705 if ((mViewFlags & WILL_NOT_DRAW) != 0 24706 && (mDefaultFocusHighlight == null) 24707 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 24708 mPrivateFlags |= PFLAG_SKIP_DRAW; 24709 } 24710 24711 /* 24712 * When the background is set, we try to apply its padding to this 24713 * View. When the background is removed, we don't touch this View's 24714 * padding. This is noted in the Javadocs. Hence, we don't need to 24715 * requestLayout(), the invalidate() below is sufficient. 24716 */ 24717 24718 // The old background's minimum size could have affected this 24719 // View's layout, so let's requestLayout 24720 requestLayout = true; 24721 } 24722 24723 computeOpaqueFlags(); 24724 24725 if (requestLayout) { 24726 requestLayout(); 24727 } 24728 24729 mBackgroundSizeChanged = true; 24730 invalidate(true); 24731 invalidateOutline(); 24732 } 24733 24734 /** 24735 * Gets the background drawable 24736 * 24737 * @return The drawable used as the background for this view, if any. 24738 * 24739 * @see #setBackground(Drawable) 24740 * 24741 * @attr ref android.R.styleable#View_background 24742 */ 24743 @InspectableProperty getBackground()24744 public Drawable getBackground() { 24745 return mBackground; 24746 } 24747 24748 /** 24749 * Applies a tint to the background drawable. Does not modify the current tint 24750 * mode, which is {@link BlendMode#SRC_IN} by default. 24751 * <p> 24752 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 24753 * mutate the drawable and apply the specified tint and tint mode using 24754 * {@link Drawable#setTintList(ColorStateList)}. 24755 * 24756 * @param tint the tint to apply, may be {@code null} to clear tint 24757 * 24758 * @attr ref android.R.styleable#View_backgroundTint 24759 * @see #getBackgroundTintList() 24760 * @see Drawable#setTintList(ColorStateList) 24761 */ 24762 @RemotableViewMethod setBackgroundTintList(@ullable ColorStateList tint)24763 public void setBackgroundTintList(@Nullable ColorStateList tint) { 24764 if (mBackgroundTint == null) { 24765 mBackgroundTint = new TintInfo(); 24766 } 24767 mBackgroundTint.mTintList = tint; 24768 mBackgroundTint.mHasTintList = true; 24769 24770 applyBackgroundTint(); 24771 } 24772 24773 /** 24774 * Return the tint applied to the background drawable, if specified. 24775 * 24776 * @return the tint applied to the background drawable 24777 * @attr ref android.R.styleable#View_backgroundTint 24778 * @see #setBackgroundTintList(ColorStateList) 24779 */ 24780 @InspectableProperty(name = "backgroundTint") 24781 @Nullable getBackgroundTintList()24782 public ColorStateList getBackgroundTintList() { 24783 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 24784 } 24785 24786 /** 24787 * Specifies the blending mode used to apply the tint specified by 24788 * {@link #setBackgroundTintList(ColorStateList)}} to the background 24789 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 24790 * 24791 * @param tintMode the blending mode used to apply the tint, may be 24792 * {@code null} to clear tint 24793 * @attr ref android.R.styleable#View_backgroundTintMode 24794 * @see #getBackgroundTintMode() 24795 * @see Drawable#setTintMode(PorterDuff.Mode) 24796 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)24797 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 24798 BlendMode mode = null; 24799 if (tintMode != null) { 24800 mode = BlendMode.fromValue(tintMode.nativeInt); 24801 } 24802 24803 setBackgroundTintBlendMode(mode); 24804 } 24805 24806 /** 24807 * Specifies the blending mode used to apply the tint specified by 24808 * {@link #setBackgroundTintList(ColorStateList)}} to the background 24809 * drawable. The default mode is {@link BlendMode#SRC_IN}. 24810 * 24811 * @param blendMode the blending mode used to apply the tint, may be 24812 * {@code null} to clear tint 24813 * @attr ref android.R.styleable#View_backgroundTintMode 24814 * @see #getBackgroundTintMode() 24815 * @see Drawable#setTintBlendMode(BlendMode) 24816 */ 24817 @RemotableViewMethod setBackgroundTintBlendMode(@ullable BlendMode blendMode)24818 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 24819 if (mBackgroundTint == null) { 24820 mBackgroundTint = new TintInfo(); 24821 } 24822 24823 mBackgroundTint.mBlendMode = blendMode; 24824 mBackgroundTint.mHasTintMode = true; 24825 24826 applyBackgroundTint(); 24827 } 24828 24829 /** 24830 * Return the blending mode used to apply the tint to the background 24831 * drawable, if specified. 24832 * 24833 * @return the blending mode used to apply the tint to the background 24834 * drawable 24835 * @attr ref android.R.styleable#View_backgroundTintMode 24836 * @see #setBackgroundTintBlendMode(BlendMode) 24837 * 24838 */ 24839 @Nullable 24840 @InspectableProperty getBackgroundTintMode()24841 public PorterDuff.Mode getBackgroundTintMode() { 24842 PorterDuff.Mode porterDuffMode; 24843 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 24844 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 24845 } else { 24846 porterDuffMode = null; 24847 } 24848 return porterDuffMode; 24849 } 24850 24851 /** 24852 * Return the blending mode used to apply the tint to the background 24853 * drawable, if specified. 24854 * 24855 * @return the blending mode used to apply the tint to the background 24856 * drawable, null if no blend has previously been configured 24857 * @attr ref android.R.styleable#View_backgroundTintMode 24858 * @see #setBackgroundTintBlendMode(BlendMode) 24859 */ getBackgroundTintBlendMode()24860 public @Nullable BlendMode getBackgroundTintBlendMode() { 24861 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 24862 } 24863 applyBackgroundTint()24864 private void applyBackgroundTint() { 24865 if (mBackground != null && mBackgroundTint != null) { 24866 final TintInfo tintInfo = mBackgroundTint; 24867 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 24868 mBackground = mBackground.mutate(); 24869 24870 if (tintInfo.mHasTintList) { 24871 mBackground.setTintList(tintInfo.mTintList); 24872 } 24873 24874 if (tintInfo.mHasTintMode) { 24875 mBackground.setTintBlendMode(tintInfo.mBlendMode); 24876 } 24877 24878 // The drawable (or one of its children) may not have been 24879 // stateful before applying the tint, so let's try again. 24880 if (mBackground.isStateful()) { 24881 mBackground.setState(getDrawableState()); 24882 } 24883 } 24884 } 24885 } 24886 24887 /** 24888 * Returns the drawable used as the foreground of this View. The 24889 * foreground drawable, if non-null, is always drawn on top of the view's content. 24890 * 24891 * @return a Drawable or null if no foreground was set 24892 * 24893 * @see #onDrawForeground(Canvas) 24894 */ 24895 @InspectableProperty getForeground()24896 public Drawable getForeground() { 24897 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24898 } 24899 24900 /** 24901 * Supply a Drawable that is to be rendered on top of all of the content in the view. 24902 * 24903 * @param foreground the Drawable to be drawn on top of the children 24904 * 24905 * @attr ref android.R.styleable#View_foreground 24906 */ setForeground(Drawable foreground)24907 public void setForeground(Drawable foreground) { 24908 if (mForegroundInfo == null) { 24909 if (foreground == null) { 24910 // Nothing to do. 24911 return; 24912 } 24913 mForegroundInfo = new ForegroundInfo(); 24914 } 24915 24916 if (foreground == mForegroundInfo.mDrawable) { 24917 // Nothing to do 24918 return; 24919 } 24920 24921 if (mForegroundInfo.mDrawable != null) { 24922 if (isAttachedToWindow()) { 24923 mForegroundInfo.mDrawable.setVisible(false, false); 24924 } 24925 mForegroundInfo.mDrawable.setCallback(null); 24926 unscheduleDrawable(mForegroundInfo.mDrawable); 24927 } 24928 24929 mForegroundInfo.mDrawable = foreground; 24930 mForegroundInfo.mBoundsChanged = true; 24931 if (foreground != null) { 24932 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24933 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24934 } 24935 foreground.setLayoutDirection(getLayoutDirection()); 24936 if (foreground.isStateful()) { 24937 foreground.setState(getDrawableState()); 24938 } 24939 applyForegroundTint(); 24940 if (isAttachedToWindow()) { 24941 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24942 } 24943 // Set callback last, since the view may still be initializing. 24944 foreground.setCallback(this); 24945 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 24946 && (mDefaultFocusHighlight == null)) { 24947 mPrivateFlags |= PFLAG_SKIP_DRAW; 24948 } 24949 requestLayout(); 24950 invalidate(); 24951 } 24952 24953 /** 24954 * Magic bit used to support features of framework-internal window decor implementation details. 24955 * This used to live exclusively in FrameLayout. 24956 * 24957 * @return true if the foreground should draw inside the padding region or false 24958 * if it should draw inset by the view's padding 24959 * @hide internal use only; only used by FrameLayout and internal screen layouts. 24960 */ isForegroundInsidePadding()24961 public boolean isForegroundInsidePadding() { 24962 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 24963 } 24964 24965 /** 24966 * Describes how the foreground is positioned. 24967 * 24968 * @return foreground gravity. 24969 * 24970 * @see #setForegroundGravity(int) 24971 * 24972 * @attr ref android.R.styleable#View_foregroundGravity 24973 */ 24974 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()24975 public int getForegroundGravity() { 24976 return mForegroundInfo != null ? mForegroundInfo.mGravity 24977 : Gravity.START | Gravity.TOP; 24978 } 24979 24980 /** 24981 * Describes how the foreground is positioned. Defaults to START and TOP. 24982 * 24983 * @param gravity see {@link android.view.Gravity} 24984 * 24985 * @see #getForegroundGravity() 24986 * 24987 * @attr ref android.R.styleable#View_foregroundGravity 24988 */ setForegroundGravity(int gravity)24989 public void setForegroundGravity(int gravity) { 24990 if (mForegroundInfo == null) { 24991 mForegroundInfo = new ForegroundInfo(); 24992 } 24993 24994 if (mForegroundInfo.mGravity != gravity) { 24995 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 24996 gravity |= Gravity.START; 24997 } 24998 24999 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 25000 gravity |= Gravity.TOP; 25001 } 25002 25003 mForegroundInfo.mGravity = gravity; 25004 requestLayout(); 25005 } 25006 } 25007 25008 /** 25009 * Applies a tint to the foreground drawable. Does not modify the current tint 25010 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 25011 * <p> 25012 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 25013 * mutate the drawable and apply the specified tint and tint mode using 25014 * {@link Drawable#setTintList(ColorStateList)}. 25015 * 25016 * @param tint the tint to apply, may be {@code null} to clear tint 25017 * 25018 * @attr ref android.R.styleable#View_foregroundTint 25019 * @see #getForegroundTintList() 25020 * @see Drawable#setTintList(ColorStateList) 25021 */ 25022 @RemotableViewMethod setForegroundTintList(@ullable ColorStateList tint)25023 public void setForegroundTintList(@Nullable ColorStateList tint) { 25024 if (mForegroundInfo == null) { 25025 mForegroundInfo = new ForegroundInfo(); 25026 } 25027 if (mForegroundInfo.mTintInfo == null) { 25028 mForegroundInfo.mTintInfo = new TintInfo(); 25029 } 25030 mForegroundInfo.mTintInfo.mTintList = tint; 25031 mForegroundInfo.mTintInfo.mHasTintList = true; 25032 25033 applyForegroundTint(); 25034 } 25035 25036 /** 25037 * Return the tint applied to the foreground drawable, if specified. 25038 * 25039 * @return the tint applied to the foreground drawable 25040 * @attr ref android.R.styleable#View_foregroundTint 25041 * @see #setForegroundTintList(ColorStateList) 25042 */ 25043 @InspectableProperty(name = "foregroundTint") 25044 @Nullable getForegroundTintList()25045 public ColorStateList getForegroundTintList() { 25046 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 25047 ? mForegroundInfo.mTintInfo.mTintList : null; 25048 } 25049 25050 /** 25051 * Specifies the blending mode used to apply the tint specified by 25052 * {@link #setForegroundTintList(ColorStateList)}} to the background 25053 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 25054 * 25055 * @param tintMode the blending mode used to apply the tint, may be 25056 * {@code null} to clear tint 25057 * @attr ref android.R.styleable#View_foregroundTintMode 25058 * @see #getForegroundTintMode() 25059 * @see Drawable#setTintMode(PorterDuff.Mode) 25060 * 25061 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)25062 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 25063 BlendMode mode = null; 25064 if (tintMode != null) { 25065 mode = BlendMode.fromValue(tintMode.nativeInt); 25066 } 25067 setForegroundTintBlendMode(mode); 25068 } 25069 25070 /** 25071 * Specifies the blending mode used to apply the tint specified by 25072 * {@link #setForegroundTintList(ColorStateList)}} to the background 25073 * drawable. The default mode is {@link BlendMode#SRC_IN}. 25074 * 25075 * @param blendMode the blending mode used to apply the tint, may be 25076 * {@code null} to clear tint 25077 * @attr ref android.R.styleable#View_foregroundTintMode 25078 * @see #getForegroundTintMode() 25079 * @see Drawable#setTintBlendMode(BlendMode) 25080 */ 25081 @RemotableViewMethod setForegroundTintBlendMode(@ullable BlendMode blendMode)25082 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 25083 if (mForegroundInfo == null) { 25084 mForegroundInfo = new ForegroundInfo(); 25085 } 25086 if (mForegroundInfo.mTintInfo == null) { 25087 mForegroundInfo.mTintInfo = new TintInfo(); 25088 } 25089 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 25090 mForegroundInfo.mTintInfo.mHasTintMode = true; 25091 25092 applyForegroundTint(); 25093 } 25094 25095 /** 25096 * Return the blending mode used to apply the tint to the foreground 25097 * drawable, if specified. 25098 * 25099 * @return the blending mode used to apply the tint to the foreground 25100 * drawable 25101 * @attr ref android.R.styleable#View_foregroundTintMode 25102 * @see #setForegroundTintMode(PorterDuff.Mode) 25103 */ 25104 @InspectableProperty 25105 @Nullable getForegroundTintMode()25106 public PorterDuff.Mode getForegroundTintMode() { 25107 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 25108 ? mForegroundInfo.mTintInfo.mBlendMode : null; 25109 if (blendMode != null) { 25110 return BlendMode.blendModeToPorterDuffMode(blendMode); 25111 } else { 25112 return null; 25113 } 25114 } 25115 25116 /** 25117 * Return the blending mode used to apply the tint to the foreground 25118 * drawable, if specified. 25119 * 25120 * @return the blending mode used to apply the tint to the foreground 25121 * drawable 25122 * @attr ref android.R.styleable#View_foregroundTintMode 25123 * @see #setForegroundTintBlendMode(BlendMode) 25124 * 25125 */ getForegroundTintBlendMode()25126 public @Nullable BlendMode getForegroundTintBlendMode() { 25127 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 25128 ? mForegroundInfo.mTintInfo.mBlendMode : null; 25129 } 25130 applyForegroundTint()25131 private void applyForegroundTint() { 25132 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 25133 && mForegroundInfo.mTintInfo != null) { 25134 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 25135 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 25136 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 25137 25138 if (tintInfo.mHasTintList) { 25139 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 25140 } 25141 25142 if (tintInfo.mHasTintMode) { 25143 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 25144 } 25145 25146 // The drawable (or one of its children) may not have been 25147 // stateful before applying the tint, so let's try again. 25148 if (mForegroundInfo.mDrawable.isStateful()) { 25149 mForegroundInfo.mDrawable.setState(getDrawableState()); 25150 } 25151 } 25152 } 25153 } 25154 25155 /** 25156 * Get the drawable to be overlayed when a view is autofilled 25157 * 25158 * @return The drawable 25159 * 25160 * @throws IllegalStateException if the drawable could not be found. 25161 */ getAutofilledDrawable()25162 @Nullable private Drawable getAutofilledDrawable() { 25163 if (mAttachInfo == null) { 25164 return null; 25165 } 25166 // Lazily load the isAutofilled drawable. 25167 if (mAttachInfo.mAutofilledDrawable == null) { 25168 Context rootContext = getRootView().getContext(); 25169 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 25170 int attributeResourceId = a.getResourceId(0, 0); 25171 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 25172 a.recycle(); 25173 } 25174 25175 return mAttachInfo.mAutofilledDrawable; 25176 } 25177 25178 /** 25179 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 25180 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 25181 * 25182 * @param canvas The canvas to draw on 25183 */ drawAutofilledHighlight(@onNull Canvas canvas)25184 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 25185 if (isAutofilled() && !hideAutofillHighlight()) { 25186 Drawable autofilledHighlight = getAutofilledDrawable(); 25187 25188 if (autofilledHighlight != null) { 25189 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 25190 autofilledHighlight.draw(canvas); 25191 } 25192 } 25193 } 25194 25195 /** 25196 * Draw any foreground content for this view. 25197 * 25198 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 25199 * drawable or other view-specific decorations. The foreground is drawn on top of the 25200 * primary view content.</p> 25201 * 25202 * @param canvas canvas to draw into 25203 */ onDrawForeground(Canvas canvas)25204 public void onDrawForeground(Canvas canvas) { 25205 onDrawScrollIndicators(canvas); 25206 onDrawScrollBars(canvas); 25207 25208 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 25209 if (foreground != null) { 25210 if (mForegroundInfo.mBoundsChanged) { 25211 mForegroundInfo.mBoundsChanged = false; 25212 final Rect selfBounds = mForegroundInfo.mSelfBounds; 25213 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 25214 25215 if (mForegroundInfo.mInsidePadding) { 25216 selfBounds.set(0, 0, getWidth(), getHeight()); 25217 } else { 25218 selfBounds.set(getPaddingLeft(), getPaddingTop(), 25219 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 25220 } 25221 25222 final int ld = getLayoutDirection(); 25223 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 25224 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 25225 foreground.setBounds(overlayBounds); 25226 } 25227 25228 foreground.draw(canvas); 25229 } 25230 } 25231 25232 /** 25233 * Sets the padding. The view may add on the space required to display 25234 * the scrollbars, depending on the style and visibility of the scrollbars. 25235 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 25236 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 25237 * from the values set in this call. 25238 * 25239 * @attr ref android.R.styleable#View_padding 25240 * @attr ref android.R.styleable#View_paddingBottom 25241 * @attr ref android.R.styleable#View_paddingLeft 25242 * @attr ref android.R.styleable#View_paddingRight 25243 * @attr ref android.R.styleable#View_paddingTop 25244 * @param left the left padding in pixels 25245 * @param top the top padding in pixels 25246 * @param right the right padding in pixels 25247 * @param bottom the bottom padding in pixels 25248 */ setPadding(int left, int top, int right, int bottom)25249 public void setPadding(int left, int top, int right, int bottom) { 25250 resetResolvedPaddingInternal(); 25251 25252 mUserPaddingStart = UNDEFINED_PADDING; 25253 mUserPaddingEnd = UNDEFINED_PADDING; 25254 25255 mUserPaddingLeftInitial = left; 25256 mUserPaddingRightInitial = right; 25257 25258 mLeftPaddingDefined = true; 25259 mRightPaddingDefined = true; 25260 25261 internalSetPadding(left, top, right, bottom); 25262 } 25263 25264 /** 25265 * @hide 25266 */ 25267 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)25268 protected void internalSetPadding(int left, int top, int right, int bottom) { 25269 mUserPaddingLeft = left; 25270 mUserPaddingRight = right; 25271 mUserPaddingBottom = bottom; 25272 25273 final int viewFlags = mViewFlags; 25274 boolean changed = false; 25275 25276 // Common case is there are no scroll bars. 25277 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 25278 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 25279 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 25280 ? 0 : getVerticalScrollbarWidth(); 25281 switch (mVerticalScrollbarPosition) { 25282 case SCROLLBAR_POSITION_DEFAULT: 25283 if (isLayoutRtl()) { 25284 left += offset; 25285 } else { 25286 right += offset; 25287 } 25288 break; 25289 case SCROLLBAR_POSITION_RIGHT: 25290 right += offset; 25291 break; 25292 case SCROLLBAR_POSITION_LEFT: 25293 left += offset; 25294 break; 25295 } 25296 } 25297 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 25298 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 25299 ? 0 : getHorizontalScrollbarHeight(); 25300 } 25301 } 25302 25303 if (mPaddingLeft != left) { 25304 changed = true; 25305 mPaddingLeft = left; 25306 } 25307 if (mPaddingTop != top) { 25308 changed = true; 25309 mPaddingTop = top; 25310 } 25311 if (mPaddingRight != right) { 25312 changed = true; 25313 mPaddingRight = right; 25314 } 25315 if (mPaddingBottom != bottom) { 25316 changed = true; 25317 mPaddingBottom = bottom; 25318 } 25319 25320 if (changed) { 25321 requestLayout(); 25322 invalidateOutline(); 25323 } 25324 } 25325 25326 /** 25327 * Sets the relative padding. The view may add on the space required to display 25328 * the scrollbars, depending on the style and visibility of the scrollbars. 25329 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 25330 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 25331 * from the values set in this call. 25332 * 25333 * @attr ref android.R.styleable#View_padding 25334 * @attr ref android.R.styleable#View_paddingBottom 25335 * @attr ref android.R.styleable#View_paddingStart 25336 * @attr ref android.R.styleable#View_paddingEnd 25337 * @attr ref android.R.styleable#View_paddingTop 25338 * @param start the start padding in pixels 25339 * @param top the top padding in pixels 25340 * @param end the end padding in pixels 25341 * @param bottom the bottom padding in pixels 25342 */ setPaddingRelative(int start, int top, int end, int bottom)25343 public void setPaddingRelative(int start, int top, int end, int bottom) { 25344 resetResolvedPaddingInternal(); 25345 25346 mUserPaddingStart = start; 25347 mUserPaddingEnd = end; 25348 mLeftPaddingDefined = true; 25349 mRightPaddingDefined = true; 25350 25351 switch(getLayoutDirection()) { 25352 case LAYOUT_DIRECTION_RTL: 25353 mUserPaddingLeftInitial = end; 25354 mUserPaddingRightInitial = start; 25355 internalSetPadding(end, top, start, bottom); 25356 break; 25357 case LAYOUT_DIRECTION_LTR: 25358 default: 25359 mUserPaddingLeftInitial = start; 25360 mUserPaddingRightInitial = end; 25361 internalSetPadding(start, top, end, bottom); 25362 } 25363 } 25364 25365 /** 25366 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 25367 * resource ID of the source layout. 25368 * 25369 * @return The layout resource id if this view was inflated from XML, otherwise 25370 * {@link Resources#ID_NULL}. 25371 */ 25372 @LayoutRes getSourceLayoutResId()25373 public int getSourceLayoutResId() { 25374 return mSourceLayoutId; 25375 } 25376 25377 /** 25378 * Returns the top padding of this view. 25379 * 25380 * @return the top padding in pixels 25381 */ 25382 @InspectableProperty getPaddingTop()25383 public int getPaddingTop() { 25384 return mPaddingTop; 25385 } 25386 25387 /** 25388 * Returns the bottom padding of this view. If there are inset and enabled 25389 * scrollbars, this value may include the space required to display the 25390 * scrollbars as well. 25391 * 25392 * @return the bottom padding in pixels 25393 */ 25394 @InspectableProperty getPaddingBottom()25395 public int getPaddingBottom() { 25396 return mPaddingBottom; 25397 } 25398 25399 /** 25400 * Returns the left padding of this view. If there are inset and enabled 25401 * scrollbars, this value may include the space required to display the 25402 * scrollbars as well. 25403 * 25404 * @return the left padding in pixels 25405 */ 25406 @InspectableProperty getPaddingLeft()25407 public int getPaddingLeft() { 25408 if (!isPaddingResolved()) { 25409 resolvePadding(); 25410 } 25411 return mPaddingLeft; 25412 } 25413 25414 /** 25415 * Returns the start padding of this view depending on its resolved layout direction. 25416 * If there are inset and enabled scrollbars, this value may include the space 25417 * required to display the scrollbars as well. 25418 * 25419 * @return the start padding in pixels 25420 */ getPaddingStart()25421 public int getPaddingStart() { 25422 if (!isPaddingResolved()) { 25423 resolvePadding(); 25424 } 25425 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 25426 mPaddingRight : mPaddingLeft; 25427 } 25428 25429 /** 25430 * Returns the right padding of this view. If there are inset and enabled 25431 * scrollbars, this value may include the space required to display the 25432 * scrollbars as well. 25433 * 25434 * @return the right padding in pixels 25435 */ 25436 @InspectableProperty getPaddingRight()25437 public int getPaddingRight() { 25438 if (!isPaddingResolved()) { 25439 resolvePadding(); 25440 } 25441 return mPaddingRight; 25442 } 25443 25444 /** 25445 * Returns the end padding of this view depending on its resolved layout direction. 25446 * If there are inset and enabled scrollbars, this value may include the space 25447 * required to display the scrollbars as well. 25448 * 25449 * @return the end padding in pixels 25450 */ getPaddingEnd()25451 public int getPaddingEnd() { 25452 if (!isPaddingResolved()) { 25453 resolvePadding(); 25454 } 25455 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 25456 mPaddingLeft : mPaddingRight; 25457 } 25458 25459 /** 25460 * Return if the padding has been set through relative values 25461 * {@link #setPaddingRelative(int, int, int, int)} or through 25462 * @attr ref android.R.styleable#View_paddingStart or 25463 * @attr ref android.R.styleable#View_paddingEnd 25464 * 25465 * @return true if the padding is relative or false if it is not. 25466 */ isPaddingRelative()25467 public boolean isPaddingRelative() { 25468 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 25469 } 25470 computeOpticalInsets()25471 Insets computeOpticalInsets() { 25472 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 25473 } 25474 25475 /** 25476 * @hide 25477 */ 25478 @UnsupportedAppUsage resetPaddingToInitialValues()25479 public void resetPaddingToInitialValues() { 25480 if (isRtlCompatibilityMode()) { 25481 mPaddingLeft = mUserPaddingLeftInitial; 25482 mPaddingRight = mUserPaddingRightInitial; 25483 return; 25484 } 25485 if (isLayoutRtl()) { 25486 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 25487 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 25488 } else { 25489 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 25490 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 25491 } 25492 } 25493 25494 /** 25495 * @hide 25496 */ getOpticalInsets()25497 public Insets getOpticalInsets() { 25498 if (mLayoutInsets == null) { 25499 mLayoutInsets = computeOpticalInsets(); 25500 } 25501 return mLayoutInsets; 25502 } 25503 25504 /** 25505 * Set this view's optical insets. 25506 * 25507 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 25508 * property. Views that compute their own optical insets should call it as part of measurement. 25509 * This method does not request layout. If you are setting optical insets outside of 25510 * measure/layout itself you will want to call requestLayout() yourself. 25511 * </p> 25512 * @hide 25513 */ setOpticalInsets(Insets insets)25514 public void setOpticalInsets(Insets insets) { 25515 mLayoutInsets = insets; 25516 } 25517 25518 /** 25519 * Changes the selection state of this view. A view can be selected or not. 25520 * Note that selection is not the same as focus. Views are typically 25521 * selected in the context of an AdapterView like ListView or GridView; 25522 * the selected view is the view that is highlighted. 25523 * 25524 * @param selected true if the view must be selected, false otherwise 25525 */ setSelected(boolean selected)25526 public void setSelected(boolean selected) { 25527 //noinspection DoubleNegation 25528 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 25529 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 25530 if (!selected) resetPressedState(); 25531 invalidate(true); 25532 refreshDrawableState(); 25533 dispatchSetSelected(selected); 25534 if (selected) { 25535 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 25536 } else { 25537 notifyViewAccessibilityStateChangedIfNeeded( 25538 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 25539 } 25540 } 25541 } 25542 25543 /** 25544 * Dispatch setSelected to all of this View's children. 25545 * 25546 * @see #setSelected(boolean) 25547 * 25548 * @param selected The new selected state 25549 */ dispatchSetSelected(boolean selected)25550 protected void dispatchSetSelected(boolean selected) { 25551 } 25552 25553 /** 25554 * Indicates the selection state of this view. 25555 * 25556 * @return true if the view is selected, false otherwise 25557 */ 25558 @ViewDebug.ExportedProperty 25559 @InspectableProperty(hasAttributeId = false) isSelected()25560 public boolean isSelected() { 25561 return (mPrivateFlags & PFLAG_SELECTED) != 0; 25562 } 25563 25564 /** 25565 * Changes the activated state of this view. A view can be activated or not. 25566 * Note that activation is not the same as selection. Selection is 25567 * a transient property, representing the view (hierarchy) the user is 25568 * currently interacting with. Activation is a longer-term state that the 25569 * user can move views in and out of. For example, in a list view with 25570 * single or multiple selection enabled, the views in the current selection 25571 * set are activated. (Um, yeah, we are deeply sorry about the terminology 25572 * here.) The activated state is propagated down to children of the view it 25573 * is set on. 25574 * 25575 * @param activated true if the view must be activated, false otherwise 25576 */ setActivated(boolean activated)25577 public void setActivated(boolean activated) { 25578 //noinspection DoubleNegation 25579 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 25580 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 25581 invalidate(true); 25582 refreshDrawableState(); 25583 dispatchSetActivated(activated); 25584 } 25585 } 25586 25587 /** 25588 * Dispatch setActivated to all of this View's children. 25589 * 25590 * @see #setActivated(boolean) 25591 * 25592 * @param activated The new activated state 25593 */ dispatchSetActivated(boolean activated)25594 protected void dispatchSetActivated(boolean activated) { 25595 } 25596 25597 /** 25598 * Indicates the activation state of this view. 25599 * 25600 * @return true if the view is activated, false otherwise 25601 */ 25602 @ViewDebug.ExportedProperty 25603 @InspectableProperty(hasAttributeId = false) isActivated()25604 public boolean isActivated() { 25605 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 25606 } 25607 25608 /** 25609 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 25610 * observer can be used to get notifications when global events, like 25611 * layout, happen. 25612 * 25613 * The returned ViewTreeObserver observer is not guaranteed to remain 25614 * valid for the lifetime of this View. If the caller of this method keeps 25615 * a long-lived reference to ViewTreeObserver, it should always check for 25616 * the return value of {@link ViewTreeObserver#isAlive()}. 25617 * 25618 * @return The ViewTreeObserver for this view's hierarchy. 25619 */ getViewTreeObserver()25620 public ViewTreeObserver getViewTreeObserver() { 25621 if (mAttachInfo != null) { 25622 return mAttachInfo.mTreeObserver; 25623 } 25624 if (mFloatingTreeObserver == null) { 25625 mFloatingTreeObserver = new ViewTreeObserver(mContext); 25626 } 25627 return mFloatingTreeObserver; 25628 } 25629 25630 /** 25631 * <p>Finds the topmost view in the current view hierarchy.</p> 25632 * 25633 * @return the topmost view containing this view 25634 */ getRootView()25635 public View getRootView() { 25636 if (mAttachInfo != null) { 25637 final View v = mAttachInfo.mRootView; 25638 if (v != null) { 25639 return v; 25640 } 25641 } 25642 25643 View parent = this; 25644 25645 while (parent.mParent instanceof View) { 25646 parent = (View) parent.mParent; 25647 } 25648 25649 return parent; 25650 } 25651 25652 /** 25653 * Transforms a motion event from view-local coordinates to on-screen 25654 * coordinates. 25655 * 25656 * @param ev the view-local motion event 25657 * @return false if the transformation could not be applied 25658 * @hide 25659 */ 25660 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toGlobalMotionEvent(MotionEvent ev)25661 public boolean toGlobalMotionEvent(MotionEvent ev) { 25662 final AttachInfo info = mAttachInfo; 25663 if (info == null) { 25664 return false; 25665 } 25666 25667 final Matrix m = info.mTmpMatrix; 25668 m.set(Matrix.IDENTITY_MATRIX); 25669 transformMatrixToGlobal(m); 25670 ev.transform(m); 25671 return true; 25672 } 25673 25674 /** 25675 * Transforms a motion event from on-screen coordinates to view-local 25676 * coordinates. 25677 * 25678 * @param ev the on-screen motion event 25679 * @return false if the transformation could not be applied 25680 * @hide 25681 */ 25682 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toLocalMotionEvent(MotionEvent ev)25683 public boolean toLocalMotionEvent(MotionEvent ev) { 25684 final AttachInfo info = mAttachInfo; 25685 if (info == null) { 25686 return false; 25687 } 25688 25689 final Matrix m = info.mTmpMatrix; 25690 m.set(Matrix.IDENTITY_MATRIX); 25691 transformMatrixToLocal(m); 25692 ev.transform(m); 25693 return true; 25694 } 25695 25696 /** 25697 * Modifies the input matrix such that it maps view-local coordinates to 25698 * on-screen coordinates. 25699 * 25700 * @param matrix input matrix to modify 25701 */ transformMatrixToGlobal(@onNull Matrix matrix)25702 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 25703 final ViewParent parent = mParent; 25704 if (parent instanceof View) { 25705 final View vp = (View) parent; 25706 vp.transformMatrixToGlobal(matrix); 25707 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 25708 } else if (parent instanceof ViewRootImpl) { 25709 final ViewRootImpl vr = (ViewRootImpl) parent; 25710 vr.transformMatrixToGlobal(matrix); 25711 matrix.preTranslate(0, -vr.mCurScrollY); 25712 } 25713 25714 matrix.preTranslate(mLeft, mTop); 25715 25716 if (!hasIdentityMatrix()) { 25717 matrix.preConcat(getMatrix()); 25718 } 25719 } 25720 25721 /** 25722 * Modifies the input matrix such that it maps on-screen coordinates to 25723 * view-local coordinates. 25724 * 25725 * @param matrix input matrix to modify 25726 */ transformMatrixToLocal(@onNull Matrix matrix)25727 public void transformMatrixToLocal(@NonNull Matrix matrix) { 25728 final ViewParent parent = mParent; 25729 if (parent instanceof View) { 25730 final View vp = (View) parent; 25731 vp.transformMatrixToLocal(matrix); 25732 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 25733 } else if (parent instanceof ViewRootImpl) { 25734 final ViewRootImpl vr = (ViewRootImpl) parent; 25735 vr.transformMatrixToLocal(matrix); 25736 matrix.postTranslate(0, vr.mCurScrollY); 25737 } 25738 25739 matrix.postTranslate(-mLeft, -mTop); 25740 25741 if (!hasIdentityMatrix()) { 25742 matrix.postConcat(getInverseMatrix()); 25743 } 25744 } 25745 25746 /** 25747 * @hide 25748 */ 25749 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 25750 @ViewDebug.IntToString(from = 0, to = "x"), 25751 @ViewDebug.IntToString(from = 1, to = "y") 25752 }) 25753 @UnsupportedAppUsage getLocationOnScreen()25754 public int[] getLocationOnScreen() { 25755 int[] location = new int[2]; 25756 getLocationOnScreen(location); 25757 return location; 25758 } 25759 25760 /** 25761 * Gets the coordinates of this view in the coordinate space of the device 25762 * screen, irrespective of system decorations and whether the system is in 25763 * multi-window mode. 25764 * 25765 * <p>In multi-window mode, the coordinate space encompasses the entire 25766 * device screen, ignoring the bounds of the app window. For example, if the 25767 * view is in the bottom portion of a horizontal split screen, the top edge 25768 * of the screen—not the top edge of the window—is the origin 25769 * from which the y-coordinate is calculated. 25770 * 25771 * <p>In multiple-screen scenarios, the coordinate space can span screens. 25772 * For example, if the app is spanning both screens of a dual-screen device 25773 * and the view is located on the right-hand screen, the x-coordinate is 25774 * calculated from the left edge of the left-hand screen to the left edge of 25775 * the view. When the app is restricted to a single screen in a 25776 * multiple-screen environment, the coordinate space includes only the 25777 * screen on which the app is running. 25778 * 25779 * <p>After the method returns, the argument array contains the x and y 25780 * coordinates of the view relative to the view's left and top edges, 25781 * respectively. 25782 * 25783 * @param outLocation A two-element integer array in which the view 25784 * coordinates are stored. The x-coordinate is at index 0; the 25785 * y-coordinate, at index 1. 25786 */ getLocationOnScreen(@ize2) int[] outLocation)25787 public void getLocationOnScreen(@Size(2) int[] outLocation) { 25788 getLocationInWindow(outLocation); 25789 25790 final AttachInfo info = mAttachInfo; 25791 if (info != null) { 25792 outLocation[0] += info.mWindowLeft; 25793 outLocation[1] += info.mWindowTop; 25794 // If OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS override is enabled, 25795 // applyViewLocationSandboxingIfNeeded sandboxes outLocation within window bounds. 25796 info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation); 25797 } 25798 } 25799 25800 /** 25801 * Gets the coordinates of this view in the coordinate space of the window 25802 * that contains the view, irrespective of system decorations. 25803 * 25804 * <p>In multi-window mode, the origin of the coordinate space is the 25805 * top left corner of the window that contains the view. In full screen 25806 * mode, the origin is the top left corner of the device screen. 25807 * 25808 * <p>In multiple-screen scenarios, if the app spans multiple screens, the 25809 * coordinate space also spans multiple screens. But if the app is 25810 * restricted to a single screen, the coordinate space includes only the 25811 * screen on which the app is running. 25812 * 25813 * <p>After the method returns, the argument array contains the x and y 25814 * coordinates of the view relative to the view's left and top edges, 25815 * respectively. 25816 * 25817 * @param outLocation A two-element integer array in which the view 25818 * coordinates are stored. The x-coordinate is at index 0; the 25819 * y-coordinate, at index 1. 25820 */ getLocationInWindow(@ize2) int[] outLocation)25821 public void getLocationInWindow(@Size(2) int[] outLocation) { 25822 if (outLocation == null || outLocation.length < 2) { 25823 throw new IllegalArgumentException("outLocation must be an array of two integers"); 25824 } 25825 25826 outLocation[0] = 0; 25827 outLocation[1] = 0; 25828 25829 transformFromViewToWindowSpace(outLocation); 25830 } 25831 25832 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)25833 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 25834 if (inOutLocation == null || inOutLocation.length < 2) { 25835 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 25836 } 25837 25838 if (mAttachInfo == null) { 25839 // When the view is not attached to a window, this method does not make sense 25840 inOutLocation[0] = inOutLocation[1] = 0; 25841 return; 25842 } 25843 25844 float position[] = mAttachInfo.mTmpTransformLocation; 25845 position[0] = inOutLocation[0]; 25846 position[1] = inOutLocation[1]; 25847 25848 if (!hasIdentityMatrix()) { 25849 getMatrix().mapPoints(position); 25850 } 25851 25852 position[0] += mLeft; 25853 position[1] += mTop; 25854 25855 ViewParent viewParent = mParent; 25856 while (viewParent instanceof View) { 25857 final View view = (View) viewParent; 25858 25859 position[0] -= view.mScrollX; 25860 position[1] -= view.mScrollY; 25861 25862 if (!view.hasIdentityMatrix()) { 25863 view.getMatrix().mapPoints(position); 25864 } 25865 25866 position[0] += view.mLeft; 25867 position[1] += view.mTop; 25868 25869 viewParent = view.mParent; 25870 } 25871 25872 if (viewParent instanceof ViewRootImpl) { 25873 // *cough* 25874 final ViewRootImpl vr = (ViewRootImpl) viewParent; 25875 position[1] -= vr.mCurScrollY; 25876 } 25877 25878 inOutLocation[0] = Math.round(position[0]); 25879 inOutLocation[1] = Math.round(position[1]); 25880 } 25881 25882 /** 25883 * @param id the id of the view to be found 25884 * @return the view of the specified id, null if cannot be found 25885 * @hide 25886 */ findViewTraversal(@dRes int id)25887 protected <T extends View> T findViewTraversal(@IdRes int id) { 25888 if (id == mID) { 25889 return (T) this; 25890 } 25891 return null; 25892 } 25893 25894 /** 25895 * @param tag the tag of the view to be found 25896 * @return the view of specified tag, null if cannot be found 25897 * @hide 25898 */ findViewWithTagTraversal(Object tag)25899 protected <T extends View> T findViewWithTagTraversal(Object tag) { 25900 if (tag != null && tag.equals(mTag)) { 25901 return (T) this; 25902 } 25903 return null; 25904 } 25905 25906 /** 25907 * @param predicate The predicate to evaluate. 25908 * @param childToSkip If not null, ignores this child during the recursive traversal. 25909 * @return The first view that matches the predicate or null. 25910 * @hide 25911 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)25912 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 25913 View childToSkip) { 25914 if (predicate.test(this)) { 25915 return (T) this; 25916 } 25917 return null; 25918 } 25919 25920 /** 25921 * Finds the first descendant view with the given ID, the view itself if 25922 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 25923 * (< 0) or there is no matching view in the hierarchy. 25924 * <p> 25925 * <strong>Note:</strong> In most cases -- depending on compiler support -- 25926 * the resulting view is automatically cast to the target class type. If 25927 * the target class type is unconstrained, an explicit cast may be 25928 * necessary. 25929 * 25930 * @param id the ID to search for 25931 * @return a view with given ID if found, or {@code null} otherwise 25932 * @see View#requireViewById(int) 25933 */ 25934 @Nullable findViewById(@dRes int id)25935 public final <T extends View> T findViewById(@IdRes int id) { 25936 if (id == NO_ID) { 25937 return null; 25938 } 25939 return findViewTraversal(id); 25940 } 25941 25942 /** 25943 * Finds the first descendant view with the given ID, the view itself if the ID matches 25944 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 25945 * matching view in the hierarchy. 25946 * <p> 25947 * <strong>Note:</strong> In most cases -- depending on compiler support -- 25948 * the resulting view is automatically cast to the target class type. If 25949 * the target class type is unconstrained, an explicit cast may be 25950 * necessary. 25951 * 25952 * @param id the ID to search for 25953 * @return a view with given ID 25954 * @see View#findViewById(int) 25955 */ 25956 @NonNull requireViewById(@dRes int id)25957 public final <T extends View> T requireViewById(@IdRes int id) { 25958 T view = findViewById(id); 25959 if (view == null) { 25960 throw new IllegalArgumentException("ID does not reference a View inside this View"); 25961 } 25962 return view; 25963 } 25964 25965 /** 25966 * Performs the traversal to find a view by its unique and stable accessibility id. 25967 * 25968 * <strong>Note:</strong>This method does not stop at the root namespace 25969 * boundary since the user can touch the screen at an arbitrary location 25970 * potentially crossing the root namespace boundary which will send an 25971 * accessibility event to accessibility services and they should be able 25972 * to obtain the event source. Also accessibility ids are guaranteed to be 25973 * unique in the window. 25974 * 25975 * @param accessibilityId The accessibility id. 25976 * @return The found view. 25977 * @hide 25978 */ findViewByAccessibilityIdTraversal(int accessibilityId)25979 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 25980 if (getAccessibilityViewId() == accessibilityId) { 25981 return (T) this; 25982 } 25983 return null; 25984 } 25985 25986 /** 25987 * Performs the traversal to find a view by its autofill id. 25988 * 25989 * <strong>Note:</strong>This method does not stop at the root namespace 25990 * boundary. 25991 * 25992 * @param autofillId The autofill id. 25993 * @return The found view. 25994 * @hide 25995 */ findViewByAutofillIdTraversal(int autofillId)25996 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 25997 if (getAutofillViewId() == autofillId) { 25998 return (T) this; 25999 } 26000 return null; 26001 } 26002 26003 /** 26004 * Look for a child view with the given tag. If this view has the given 26005 * tag, return this view. 26006 * 26007 * @param tag The tag to search for, using "tag.equals(getTag())". 26008 * @return The View that has the given tag in the hierarchy or null 26009 */ findViewWithTag(Object tag)26010 public final <T extends View> T findViewWithTag(Object tag) { 26011 if (tag == null) { 26012 return null; 26013 } 26014 return findViewWithTagTraversal(tag); 26015 } 26016 26017 /** 26018 * Look for a child view that matches the specified predicate. 26019 * If this view matches the predicate, return this view. 26020 * 26021 * @param predicate The predicate to evaluate. 26022 * @return The first view that matches the predicate or null. 26023 * @hide 26024 */ findViewByPredicate(Predicate<View> predicate)26025 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 26026 return findViewByPredicateTraversal(predicate, null); 26027 } 26028 26029 /** 26030 * Look for a child view that matches the specified predicate, 26031 * starting with the specified view and its descendents and then 26032 * recusively searching the ancestors and siblings of that view 26033 * until this view is reached. 26034 * 26035 * This method is useful in cases where the predicate does not match 26036 * a single unique view (perhaps multiple views use the same id) 26037 * and we are trying to find the view that is "closest" in scope to the 26038 * starting view. 26039 * 26040 * @param start The view to start from. 26041 * @param predicate The predicate to evaluate. 26042 * @return The first view that matches the predicate or null. 26043 * @hide 26044 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)26045 public final <T extends View> T findViewByPredicateInsideOut( 26046 View start, Predicate<View> predicate) { 26047 View childToSkip = null; 26048 for (;;) { 26049 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 26050 if (view != null || start == this) { 26051 return view; 26052 } 26053 26054 ViewParent parent = start.getParent(); 26055 if (parent == null || !(parent instanceof View)) { 26056 return null; 26057 } 26058 26059 childToSkip = start; 26060 start = (View) parent; 26061 } 26062 } 26063 26064 /** 26065 * Sets the identifier for this view. The identifier does not have to be 26066 * unique in this view's hierarchy. The identifier should be a positive 26067 * number. 26068 * 26069 * @see #NO_ID 26070 * @see #getId() 26071 * @see #findViewById(int) 26072 * 26073 * @param id a number used to identify the view 26074 * 26075 * @attr ref android.R.styleable#View_id 26076 */ setId(@dRes int id)26077 public void setId(@IdRes int id) { 26078 mID = id; 26079 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 26080 mID = generateViewId(); 26081 } 26082 } 26083 26084 /** 26085 * {@hide} 26086 * 26087 * @param isRoot true if the view belongs to the root namespace, false 26088 * otherwise 26089 */ 26090 @UnsupportedAppUsage 26091 @TestApi setIsRootNamespace(boolean isRoot)26092 public void setIsRootNamespace(boolean isRoot) { 26093 if (isRoot) { 26094 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 26095 } else { 26096 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 26097 } 26098 } 26099 26100 /** 26101 * {@hide} 26102 * 26103 * @return true if the view belongs to the root namespace, false otherwise 26104 */ 26105 @UnsupportedAppUsage isRootNamespace()26106 public boolean isRootNamespace() { 26107 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 26108 } 26109 26110 /** 26111 * Returns this view's identifier. 26112 * 26113 * @return a positive integer used to identify the view or {@link #NO_ID} 26114 * if the view has no ID 26115 * 26116 * @see #setId(int) 26117 * @see #findViewById(int) 26118 * @attr ref android.R.styleable#View_id 26119 */ 26120 @IdRes 26121 @ViewDebug.CapturedViewProperty 26122 @InspectableProperty getId()26123 public int getId() { 26124 return mID; 26125 } 26126 26127 /** 26128 * Get the identifier used for this view by the drawing system. 26129 * 26130 * @see RenderNode#getUniqueId() 26131 * @return A long that uniquely identifies this view's drawing component 26132 */ getUniqueDrawingId()26133 public long getUniqueDrawingId() { 26134 return mRenderNode.getUniqueId(); 26135 } 26136 26137 /** 26138 * Returns this view's tag. 26139 * 26140 * @return the Object stored in this view as a tag, or {@code null} if not 26141 * set 26142 * 26143 * @see #setTag(Object) 26144 * @see #getTag(int) 26145 */ 26146 @ViewDebug.ExportedProperty 26147 @InspectableProperty getTag()26148 public Object getTag() { 26149 return mTag; 26150 } 26151 26152 /** 26153 * Sets the tag associated with this view. A tag can be used to mark 26154 * a view in its hierarchy and does not have to be unique within the 26155 * hierarchy. Tags can also be used to store data within a view without 26156 * resorting to another data structure. 26157 * 26158 * @param tag an Object to tag the view with 26159 * 26160 * @see #getTag() 26161 * @see #setTag(int, Object) 26162 */ setTag(final Object tag)26163 public void setTag(final Object tag) { 26164 mTag = tag; 26165 } 26166 26167 /** 26168 * Returns the tag associated with this view and the specified key. 26169 * 26170 * @param key The key identifying the tag 26171 * 26172 * @return the Object stored in this view as a tag, or {@code null} if not 26173 * set 26174 * 26175 * @see #setTag(int, Object) 26176 * @see #getTag() 26177 */ getTag(int key)26178 public Object getTag(int key) { 26179 if (mKeyedTags != null) return mKeyedTags.get(key); 26180 return null; 26181 } 26182 26183 /** 26184 * Sets a tag associated with this view and a key. A tag can be used 26185 * to mark a view in its hierarchy and does not have to be unique within 26186 * the hierarchy. Tags can also be used to store data within a view 26187 * without resorting to another data structure. 26188 * 26189 * The specified key should be an id declared in the resources of the 26190 * application to ensure it is unique (see the <a 26191 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 26192 * Keys identified as belonging to 26193 * the Android framework or not associated with any package will cause 26194 * an {@link IllegalArgumentException} to be thrown. 26195 * 26196 * @param key The key identifying the tag 26197 * @param tag An Object to tag the view with 26198 * 26199 * @throws IllegalArgumentException If they specified key is not valid 26200 * 26201 * @see #setTag(Object) 26202 * @see #getTag(int) 26203 */ setTag(int key, final Object tag)26204 public void setTag(int key, final Object tag) { 26205 // If the package id is 0x00 or 0x01, it's either an undefined package 26206 // or a framework id 26207 if ((key >>> 24) < 2) { 26208 throw new IllegalArgumentException("The key must be an application-specific " 26209 + "resource id."); 26210 } 26211 26212 setKeyedTag(key, tag); 26213 } 26214 26215 /** 26216 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 26217 * framework id. 26218 * 26219 * @hide 26220 */ 26221 @UnsupportedAppUsage setTagInternal(int key, Object tag)26222 public void setTagInternal(int key, Object tag) { 26223 if ((key >>> 24) != 0x1) { 26224 throw new IllegalArgumentException("The key must be a framework-specific " 26225 + "resource id."); 26226 } 26227 26228 setKeyedTag(key, tag); 26229 } 26230 setKeyedTag(int key, Object tag)26231 private void setKeyedTag(int key, Object tag) { 26232 if (mKeyedTags == null) { 26233 mKeyedTags = new SparseArray<Object>(2); 26234 } 26235 26236 mKeyedTags.put(key, tag); 26237 } 26238 26239 /** 26240 * Prints information about this view in the log output, with the tag 26241 * {@link #VIEW_LOG_TAG}. 26242 * 26243 * @hide 26244 */ 26245 @UnsupportedAppUsage debug()26246 public void debug() { 26247 debug(0); 26248 } 26249 26250 /** 26251 * Prints information about this view in the log output, with the tag 26252 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 26253 * indentation defined by the <code>depth</code>. 26254 * 26255 * @param depth the indentation level 26256 * 26257 * @hide 26258 */ 26259 @UnsupportedAppUsage debug(int depth)26260 protected void debug(int depth) { 26261 String output = debugIndent(depth - 1); 26262 26263 output += "+ " + this; 26264 int id = getId(); 26265 if (id != -1) { 26266 output += " (id=" + id + ")"; 26267 } 26268 Object tag = getTag(); 26269 if (tag != null) { 26270 output += " (tag=" + tag + ")"; 26271 } 26272 Log.d(VIEW_LOG_TAG, output); 26273 26274 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 26275 output = debugIndent(depth) + " FOCUSED"; 26276 Log.d(VIEW_LOG_TAG, output); 26277 } 26278 26279 output = debugIndent(depth); 26280 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 26281 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 26282 + "} "; 26283 Log.d(VIEW_LOG_TAG, output); 26284 26285 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 26286 || mPaddingBottom != 0) { 26287 output = debugIndent(depth); 26288 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 26289 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 26290 Log.d(VIEW_LOG_TAG, output); 26291 } 26292 26293 output = debugIndent(depth); 26294 output += "mMeasureWidth=" + mMeasuredWidth + 26295 " mMeasureHeight=" + mMeasuredHeight; 26296 Log.d(VIEW_LOG_TAG, output); 26297 26298 output = debugIndent(depth); 26299 if (mLayoutParams == null) { 26300 output += "BAD! no layout params"; 26301 } else { 26302 output = mLayoutParams.debug(output); 26303 } 26304 Log.d(VIEW_LOG_TAG, output); 26305 26306 output = debugIndent(depth); 26307 output += "flags={"; 26308 output += View.printFlags(mViewFlags); 26309 output += "}"; 26310 Log.d(VIEW_LOG_TAG, output); 26311 26312 output = debugIndent(depth); 26313 output += "privateFlags={"; 26314 output += View.printPrivateFlags(mPrivateFlags); 26315 output += "}"; 26316 Log.d(VIEW_LOG_TAG, output); 26317 } 26318 26319 /** 26320 * Creates a string of whitespaces used for indentation. 26321 * 26322 * @param depth the indentation level 26323 * @return a String containing (depth * 2 + 3) * 2 white spaces 26324 * 26325 * @hide 26326 */ debugIndent(int depth)26327 protected static String debugIndent(int depth) { 26328 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 26329 for (int i = 0; i < (depth * 2) + 3; i++) { 26330 spaces.append(' ').append(' '); 26331 } 26332 return spaces.toString(); 26333 } 26334 26335 /** 26336 * <p>Return the offset of the widget's text baseline from the widget's top 26337 * boundary. If this widget does not support baseline alignment, this 26338 * method returns -1. </p> 26339 * 26340 * @return the offset of the baseline within the widget's bounds or -1 26341 * if baseline alignment is not supported 26342 */ 26343 @ViewDebug.ExportedProperty(category = "layout") 26344 @InspectableProperty getBaseline()26345 public int getBaseline() { 26346 return -1; 26347 } 26348 26349 /** 26350 * Returns whether the view hierarchy is currently undergoing a layout pass. This 26351 * information is useful to avoid situations such as calling {@link #requestLayout()} during 26352 * a layout pass. 26353 * 26354 * @return whether the view hierarchy is currently undergoing a layout pass 26355 */ isInLayout()26356 public boolean isInLayout() { 26357 ViewRootImpl viewRoot = getViewRootImpl(); 26358 return (viewRoot != null && viewRoot.isInLayout()); 26359 } 26360 26361 /** To be used only for debugging purposes. */ printStackStrace(String name)26362 private void printStackStrace(String name) { 26363 Log.d(VIEW_LOG_TAG, "---- ST:" + name); 26364 26365 StringBuilder sb = new StringBuilder(); 26366 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 26367 int startIndex = 1; 26368 int endIndex = Math.min(stackTraceElements.length, startIndex + 20); // max 20 entries. 26369 for (int i = startIndex; i < endIndex; i++) { 26370 StackTraceElement s = stackTraceElements[i]; 26371 sb.append(s.getMethodName()) 26372 .append("(") 26373 .append(s.getFileName()) 26374 .append(":") 26375 .append(s.getLineNumber()) 26376 .append(") <- "); 26377 } 26378 Log.d(VIEW_LOG_TAG, name + ": " + sb); 26379 } 26380 /** 26381 * Call this when something has changed which has invalidated the 26382 * layout of this view. This will schedule a layout pass of the view 26383 * tree. This should not be called while the view hierarchy is currently in a layout 26384 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 26385 * end of the current layout pass (and then layout will run again) or after the current 26386 * frame is drawn and the next layout occurs. 26387 * 26388 * <p>Subclasses which override this method should call the superclass method to 26389 * handle possible request-during-layout errors correctly.</p> 26390 */ 26391 @CallSuper requestLayout()26392 public void requestLayout() { 26393 if (isRelayoutTracingEnabled()) { 26394 Trace.instantForTrack(TRACE_TAG_APP, "requestLayoutTracing", 26395 mTracingStrings.classSimpleName); 26396 printStackStrace(mTracingStrings.requestLayoutStacktracePrefix); 26397 } 26398 26399 if (mMeasureCache != null) mMeasureCache.clear(); 26400 26401 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 26402 // Only trigger request-during-layout logic if this is the view requesting it, 26403 // not the views in its parent hierarchy 26404 ViewRootImpl viewRoot = getViewRootImpl(); 26405 if (viewRoot != null && viewRoot.isInLayout()) { 26406 if (!viewRoot.requestLayoutDuringLayout(this)) { 26407 return; 26408 } 26409 } 26410 mAttachInfo.mViewRequestingLayout = this; 26411 } 26412 26413 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 26414 mPrivateFlags |= PFLAG_INVALIDATED; 26415 26416 if (mParent != null && !mParent.isLayoutRequested()) { 26417 mParent.requestLayout(); 26418 } 26419 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 26420 mAttachInfo.mViewRequestingLayout = null; 26421 } 26422 } 26423 26424 /** 26425 * Forces this view to be laid out during the next layout pass. 26426 * This method does not call requestLayout() or forceLayout() 26427 * on the parent. 26428 */ forceLayout()26429 public void forceLayout() { 26430 if (mMeasureCache != null) mMeasureCache.clear(); 26431 26432 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 26433 mPrivateFlags |= PFLAG_INVALIDATED; 26434 } 26435 26436 /** 26437 * <p> 26438 * This is called to find out how big a view should be. The parent 26439 * supplies constraint information in the width and height parameters. 26440 * </p> 26441 * 26442 * <p> 26443 * The actual measurement work of a view is performed in 26444 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 26445 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 26446 * </p> 26447 * 26448 * 26449 * @param widthMeasureSpec Horizontal space requirements as imposed by the 26450 * parent 26451 * @param heightMeasureSpec Vertical space requirements as imposed by the 26452 * parent 26453 * 26454 * @see #onMeasure(int, int) 26455 */ measure(int widthMeasureSpec, int heightMeasureSpec)26456 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 26457 boolean optical = isLayoutModeOptical(this); 26458 if (optical != isLayoutModeOptical(mParent)) { 26459 Insets insets = getOpticalInsets(); 26460 int oWidth = insets.left + insets.right; 26461 int oHeight = insets.top + insets.bottom; 26462 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 26463 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 26464 } 26465 26466 // Suppress sign extension for the low bytes 26467 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 26468 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 26469 26470 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 26471 26472 // Optimize layout by avoiding an extra EXACTLY pass when the view is 26473 // already measured as the correct size. In API 23 and below, this 26474 // extra pass is required to make LinearLayout re-distribute weight. 26475 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 26476 || heightMeasureSpec != mOldHeightMeasureSpec; 26477 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 26478 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 26479 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 26480 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 26481 final boolean needsLayout = specChanged 26482 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 26483 26484 if (forceLayout || needsLayout) { 26485 // first clears the measured dimension flag 26486 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 26487 26488 resolveRtlPropertiesIfNeeded(); 26489 26490 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 26491 if (cacheIndex < 0 || sIgnoreMeasureCache) { 26492 if (isTraversalTracingEnabled()) { 26493 Trace.beginSection(mTracingStrings.onMeasure); 26494 } 26495 // measure ourselves, this should set the measured dimension flag back 26496 onMeasure(widthMeasureSpec, heightMeasureSpec); 26497 if (isTraversalTracingEnabled()) { 26498 Trace.endSection(); 26499 } 26500 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 26501 } else { 26502 long value = mMeasureCache.valueAt(cacheIndex); 26503 // Casting a long to int drops the high 32 bits, no mask needed 26504 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 26505 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 26506 } 26507 26508 // flag not set, setMeasuredDimension() was not invoked, we raise 26509 // an exception to warn the developer 26510 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 26511 throw new IllegalStateException("View with id " + getId() + ": " 26512 + getClass().getName() + "#onMeasure() did not set the" 26513 + " measured dimension by calling" 26514 + " setMeasuredDimension()"); 26515 } 26516 26517 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 26518 } 26519 26520 mOldWidthMeasureSpec = widthMeasureSpec; 26521 mOldHeightMeasureSpec = heightMeasureSpec; 26522 26523 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 26524 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 26525 } 26526 26527 /** 26528 * <p> 26529 * Measure the view and its content to determine the measured width and the 26530 * measured height. This method is invoked by {@link #measure(int, int)} and 26531 * should be overridden by subclasses to provide accurate and efficient 26532 * measurement of their contents. 26533 * </p> 26534 * 26535 * <p> 26536 * <strong>CONTRACT:</strong> When overriding this method, you 26537 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 26538 * measured width and height of this view. Failure to do so will trigger an 26539 * <code>IllegalStateException</code>, thrown by 26540 * {@link #measure(int, int)}. Calling the superclass' 26541 * {@link #onMeasure(int, int)} is a valid use. 26542 * </p> 26543 * 26544 * <p> 26545 * The base class implementation of measure defaults to the background size, 26546 * unless a larger size is allowed by the MeasureSpec. Subclasses should 26547 * override {@link #onMeasure(int, int)} to provide better measurements of 26548 * their content. 26549 * </p> 26550 * 26551 * <p> 26552 * If this method is overridden, it is the subclass's responsibility to make 26553 * sure the measured height and width are at least the view's minimum height 26554 * and width ({@link #getSuggestedMinimumHeight()} and 26555 * {@link #getSuggestedMinimumWidth()}). 26556 * </p> 26557 * 26558 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 26559 * The requirements are encoded with 26560 * {@link android.view.View.MeasureSpec}. 26561 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 26562 * The requirements are encoded with 26563 * {@link android.view.View.MeasureSpec}. 26564 * 26565 * @see #getMeasuredWidth() 26566 * @see #getMeasuredHeight() 26567 * @see #setMeasuredDimension(int, int) 26568 * @see #getSuggestedMinimumHeight() 26569 * @see #getSuggestedMinimumWidth() 26570 * @see android.view.View.MeasureSpec#getMode(int) 26571 * @see android.view.View.MeasureSpec#getSize(int) 26572 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)26573 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 26574 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 26575 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 26576 } 26577 26578 /** 26579 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 26580 * measured width and measured height. Failing to do so will trigger an 26581 * exception at measurement time.</p> 26582 * 26583 * @param measuredWidth The measured width of this view. May be a complex 26584 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 26585 * {@link #MEASURED_STATE_TOO_SMALL}. 26586 * @param measuredHeight The measured height of this view. May be a complex 26587 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 26588 * {@link #MEASURED_STATE_TOO_SMALL}. 26589 */ setMeasuredDimension(int measuredWidth, int measuredHeight)26590 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 26591 boolean optical = isLayoutModeOptical(this); 26592 if (optical != isLayoutModeOptical(mParent)) { 26593 Insets insets = getOpticalInsets(); 26594 int opticalWidth = insets.left + insets.right; 26595 int opticalHeight = insets.top + insets.bottom; 26596 26597 measuredWidth += optical ? opticalWidth : -opticalWidth; 26598 measuredHeight += optical ? opticalHeight : -opticalHeight; 26599 } 26600 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 26601 } 26602 26603 /** 26604 * Sets the measured dimension without extra processing for things like optical bounds. 26605 * Useful for reapplying consistent values that have already been cooked with adjustments 26606 * for optical bounds, etc. such as those from the measurement cache. 26607 * 26608 * @param measuredWidth The measured width of this view. May be a complex 26609 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 26610 * {@link #MEASURED_STATE_TOO_SMALL}. 26611 * @param measuredHeight The measured height of this view. May be a complex 26612 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 26613 * {@link #MEASURED_STATE_TOO_SMALL}. 26614 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)26615 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 26616 mMeasuredWidth = measuredWidth; 26617 mMeasuredHeight = measuredHeight; 26618 26619 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 26620 } 26621 26622 /** 26623 * Merge two states as returned by {@link #getMeasuredState()}. 26624 * @param curState The current state as returned from a view or the result 26625 * of combining multiple views. 26626 * @param newState The new view state to combine. 26627 * @return Returns a new integer reflecting the combination of the two 26628 * states. 26629 */ combineMeasuredStates(int curState, int newState)26630 public static int combineMeasuredStates(int curState, int newState) { 26631 return curState | newState; 26632 } 26633 26634 /** 26635 * Version of {@link #resolveSizeAndState(int, int, int)} 26636 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 26637 */ resolveSize(int size, int measureSpec)26638 public static int resolveSize(int size, int measureSpec) { 26639 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 26640 } 26641 26642 /** 26643 * Utility to reconcile a desired size and state, with constraints imposed 26644 * by a MeasureSpec. Will take the desired size, unless a different size 26645 * is imposed by the constraints. The returned value is a compound integer, 26646 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 26647 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 26648 * resulting size is smaller than the size the view wants to be. 26649 * 26650 * @param size How big the view wants to be. 26651 * @param measureSpec Constraints imposed by the parent. 26652 * @param childMeasuredState Size information bit mask for the view's 26653 * children. 26654 * @return Size information bit mask as defined by 26655 * {@link #MEASURED_SIZE_MASK} and 26656 * {@link #MEASURED_STATE_TOO_SMALL}. 26657 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)26658 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 26659 final int specMode = MeasureSpec.getMode(measureSpec); 26660 final int specSize = MeasureSpec.getSize(measureSpec); 26661 final int result; 26662 switch (specMode) { 26663 case MeasureSpec.AT_MOST: 26664 if (specSize < size) { 26665 result = specSize | MEASURED_STATE_TOO_SMALL; 26666 } else { 26667 result = size; 26668 } 26669 break; 26670 case MeasureSpec.EXACTLY: 26671 result = specSize; 26672 break; 26673 case MeasureSpec.UNSPECIFIED: 26674 default: 26675 result = size; 26676 } 26677 return result | (childMeasuredState & MEASURED_STATE_MASK); 26678 } 26679 26680 /** 26681 * Utility to return a default size. Uses the supplied size if the 26682 * MeasureSpec imposed no constraints. Will get larger if allowed 26683 * by the MeasureSpec. 26684 * 26685 * @param size Default size for this view 26686 * @param measureSpec Constraints imposed by the parent 26687 * @return The size this view should be. 26688 */ getDefaultSize(int size, int measureSpec)26689 public static int getDefaultSize(int size, int measureSpec) { 26690 int result = size; 26691 int specMode = MeasureSpec.getMode(measureSpec); 26692 int specSize = MeasureSpec.getSize(measureSpec); 26693 26694 switch (specMode) { 26695 case MeasureSpec.UNSPECIFIED: 26696 result = size; 26697 break; 26698 case MeasureSpec.AT_MOST: 26699 case MeasureSpec.EXACTLY: 26700 result = specSize; 26701 break; 26702 } 26703 return result; 26704 } 26705 26706 /** 26707 * Returns the suggested minimum height that the view should use. This 26708 * returns the maximum of the view's minimum height 26709 * and the background's minimum height 26710 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 26711 * <p> 26712 * When being used in {@link #onMeasure(int, int)}, the caller should still 26713 * ensure the returned height is within the requirements of the parent. 26714 * 26715 * @return The suggested minimum height of the view. 26716 */ getSuggestedMinimumHeight()26717 protected int getSuggestedMinimumHeight() { 26718 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 26719 26720 } 26721 26722 /** 26723 * Returns the suggested minimum width that the view should use. This 26724 * returns the maximum of the view's minimum width 26725 * and the background's minimum width 26726 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 26727 * <p> 26728 * When being used in {@link #onMeasure(int, int)}, the caller should still 26729 * ensure the returned width is within the requirements of the parent. 26730 * 26731 * @return The suggested minimum width of the view. 26732 */ getSuggestedMinimumWidth()26733 protected int getSuggestedMinimumWidth() { 26734 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 26735 } 26736 26737 /** 26738 * Returns the minimum height of the view. 26739 * 26740 * @return the minimum height the view will try to be, in pixels 26741 * 26742 * @see #setMinimumHeight(int) 26743 * 26744 * @attr ref android.R.styleable#View_minHeight 26745 */ 26746 @InspectableProperty(name = "minHeight") getMinimumHeight()26747 public int getMinimumHeight() { 26748 return mMinHeight; 26749 } 26750 26751 /** 26752 * Sets the minimum height of the view. It is not guaranteed the view will 26753 * be able to achieve this minimum height (for example, if its parent layout 26754 * constrains it with less available height). 26755 * 26756 * @param minHeight The minimum height the view will try to be, in pixels 26757 * 26758 * @see #getMinimumHeight() 26759 * 26760 * @attr ref android.R.styleable#View_minHeight 26761 */ 26762 @RemotableViewMethod setMinimumHeight(int minHeight)26763 public void setMinimumHeight(int minHeight) { 26764 mMinHeight = minHeight; 26765 requestLayout(); 26766 } 26767 26768 /** 26769 * Returns the minimum width of the view. 26770 * 26771 * @return the minimum width the view will try to be, in pixels 26772 * 26773 * @see #setMinimumWidth(int) 26774 * 26775 * @attr ref android.R.styleable#View_minWidth 26776 */ 26777 @InspectableProperty(name = "minWidth") getMinimumWidth()26778 public int getMinimumWidth() { 26779 return mMinWidth; 26780 } 26781 26782 /** 26783 * Sets the minimum width of the view. It is not guaranteed the view will 26784 * be able to achieve this minimum width (for example, if its parent layout 26785 * constrains it with less available width). 26786 * 26787 * @param minWidth The minimum width the view will try to be, in pixels 26788 * 26789 * @see #getMinimumWidth() 26790 * 26791 * @attr ref android.R.styleable#View_minWidth 26792 */ 26793 @RemotableViewMethod setMinimumWidth(int minWidth)26794 public void setMinimumWidth(int minWidth) { 26795 mMinWidth = minWidth; 26796 requestLayout(); 26797 26798 } 26799 26800 /** 26801 * Get the animation currently associated with this view. 26802 * 26803 * @return The animation that is currently playing or 26804 * scheduled to play for this view. 26805 */ getAnimation()26806 public Animation getAnimation() { 26807 return mCurrentAnimation; 26808 } 26809 26810 /** 26811 * Start the specified animation now. 26812 * 26813 * @param animation the animation to start now 26814 */ startAnimation(Animation animation)26815 public void startAnimation(Animation animation) { 26816 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 26817 setAnimation(animation); 26818 invalidateParentCaches(); 26819 invalidate(true); 26820 } 26821 26822 /** 26823 * Cancels any animations for this view. 26824 */ clearAnimation()26825 public void clearAnimation() { 26826 if (mCurrentAnimation != null) { 26827 mCurrentAnimation.detach(); 26828 } 26829 mCurrentAnimation = null; 26830 invalidateParentIfNeeded(); 26831 } 26832 26833 /** 26834 * Sets the next animation to play for this view. 26835 * If you want the animation to play immediately, use 26836 * {@link #startAnimation(android.view.animation.Animation)} instead. 26837 * This method provides allows fine-grained 26838 * control over the start time and invalidation, but you 26839 * must make sure that 1) the animation has a start time set, and 26840 * 2) the view's parent (which controls animations on its children) 26841 * will be invalidated when the animation is supposed to 26842 * start. 26843 * 26844 * @param animation The next animation, or null. 26845 */ setAnimation(Animation animation)26846 public void setAnimation(Animation animation) { 26847 mCurrentAnimation = animation; 26848 26849 if (animation != null) { 26850 // If the screen is off assume the animation start time is now instead of 26851 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 26852 // would cause the animation to start when the screen turns back on 26853 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 26854 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 26855 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 26856 } 26857 animation.reset(); 26858 } 26859 } 26860 26861 /** 26862 * Invoked by a parent ViewGroup to notify the start of the animation 26863 * currently associated with this view. If you override this method, 26864 * always call super.onAnimationStart(); 26865 * 26866 * @see #setAnimation(android.view.animation.Animation) 26867 * @see #getAnimation() 26868 */ 26869 @CallSuper onAnimationStart()26870 protected void onAnimationStart() { 26871 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 26872 } 26873 26874 /** 26875 * Invoked by a parent ViewGroup to notify the end of the animation 26876 * currently associated with this view. If you override this method, 26877 * always call super.onAnimationEnd(); 26878 * 26879 * @see #setAnimation(android.view.animation.Animation) 26880 * @see #getAnimation() 26881 */ 26882 @CallSuper onAnimationEnd()26883 protected void onAnimationEnd() { 26884 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 26885 } 26886 26887 /** 26888 * Invoked if there is a Transform that involves alpha. Subclass that can 26889 * draw themselves with the specified alpha should return true, and then 26890 * respect that alpha when their onDraw() is called. If this returns false 26891 * then the view may be redirected to draw into an offscreen buffer to 26892 * fulfill the request, which will look fine, but may be slower than if the 26893 * subclass handles it internally. The default implementation returns false. 26894 * 26895 * @param alpha The alpha (0..255) to apply to the view's drawing 26896 * @return true if the view can draw with the specified alpha. 26897 */ onSetAlpha(int alpha)26898 protected boolean onSetAlpha(int alpha) { 26899 return false; 26900 } 26901 26902 /** 26903 * This is used by the ViewRoot to perform an optimization when 26904 * the view hierarchy contains one or several SurfaceView. 26905 * SurfaceView is always considered transparent, but its children are not, 26906 * therefore all View objects remove themselves from the global transparent 26907 * region (passed as a parameter to this function). 26908 * 26909 * @param region The transparent region for this ViewAncestor (window). 26910 * 26911 * @return Returns true if the effective visibility of the view at this 26912 * point is opaque, regardless of the transparent region; returns false 26913 * if it is possible for underlying windows to be seen behind the view. 26914 * 26915 */ gatherTransparentRegion(@ullable Region region)26916 public boolean gatherTransparentRegion(@Nullable Region region) { 26917 final AttachInfo attachInfo = mAttachInfo; 26918 if (region != null && attachInfo != null) { 26919 final int pflags = mPrivateFlags; 26920 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 26921 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 26922 // remove it from the transparent region. 26923 final int[] location = attachInfo.mTransparentLocation; 26924 getLocationInWindow(location); 26925 // When a view has Z value, then it will be better to leave some area below the view 26926 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 26927 // the bottom part needs more offset than the left, top and right parts due to the 26928 // spot light effects. 26929 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 26930 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 26931 location[0] + mRight - mLeft + shadowOffset, 26932 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 26933 } else { 26934 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 26935 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 26936 // the background drawable's non-transparent parts from this transparent region. 26937 applyDrawableToTransparentRegion(mBackground, region); 26938 } 26939 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 26940 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 26941 // Similarly, we remove the foreground drawable's non-transparent parts. 26942 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 26943 } 26944 if (mDefaultFocusHighlight != null 26945 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 26946 // Similarly, we remove the default focus highlight's non-transparent parts. 26947 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 26948 } 26949 } 26950 } 26951 return true; 26952 } 26953 26954 /** 26955 * Play a sound effect for this view. 26956 * 26957 * <p>The framework will play sound effects for some built in actions, such as 26958 * clicking, but you may wish to play these effects in your widget, 26959 * for instance, for internal navigation. 26960 * 26961 * <p>The sound effect will only be played if sound effects are enabled by the user, and 26962 * {@link #isSoundEffectsEnabled()} is true. 26963 * 26964 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}. 26965 */ playSoundEffect(@oundEffectConstants.SoundEffect int soundConstant)26966 public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { 26967 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 26968 return; 26969 } 26970 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 26971 } 26972 26973 /** 26974 * BZZZTT!!1! 26975 * 26976 * <p>Provide haptic feedback to the user for this view. 26977 * 26978 * <p>The framework will provide haptic feedback for some built in actions, 26979 * such as long presses, but you may wish to provide feedback for your 26980 * own widget. 26981 * 26982 * <p>The feedback will only be performed if 26983 * {@link #isHapticFeedbackEnabled()} is true. 26984 * 26985 * @param feedbackConstant One of the constants defined in 26986 * {@link HapticFeedbackConstants} 26987 */ performHapticFeedback(int feedbackConstant)26988 public boolean performHapticFeedback(int feedbackConstant) { 26989 return performHapticFeedback(feedbackConstant, 0); 26990 } 26991 26992 /** 26993 * BZZZTT!!1! 26994 * 26995 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 26996 * 26997 * @param feedbackConstant One of the constants defined in 26998 * {@link HapticFeedbackConstants} 26999 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 27000 */ performHapticFeedback(int feedbackConstant, int flags)27001 public boolean performHapticFeedback(int feedbackConstant, int flags) { 27002 if (mAttachInfo == null) { 27003 return false; 27004 } 27005 //noinspection SimplifiableIfStatement 27006 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 27007 && !isHapticFeedbackEnabled()) { 27008 return false; 27009 } 27010 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 27011 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 27012 } 27013 27014 /** 27015 * Request that the visibility of the status bar or other screen/window 27016 * decorations be changed. 27017 * 27018 * <p>This method is used to put the over device UI into temporary modes 27019 * where the user's attention is focused more on the application content, 27020 * by dimming or hiding surrounding system affordances. This is typically 27021 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 27022 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 27023 * to be placed behind the action bar (and with these flags other system 27024 * affordances) so that smooth transitions between hiding and showing them 27025 * can be done. 27026 * 27027 * <p>Two representative examples of the use of system UI visibility is 27028 * implementing a content browsing application (like a magazine reader) 27029 * and a video playing application. 27030 * 27031 * <p>The first code shows a typical implementation of a View in a content 27032 * browsing application. In this implementation, the application goes 27033 * into a content-oriented mode by hiding the status bar and action bar, 27034 * and putting the navigation elements into lights out mode. The user can 27035 * then interact with content while in this mode. Such an application should 27036 * provide an easy way for the user to toggle out of the mode (such as to 27037 * check information in the status bar or access notifications). In the 27038 * implementation here, this is done simply by tapping on the content. 27039 * 27040 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 27041 * content} 27042 * 27043 * <p>This second code sample shows a typical implementation of a View 27044 * in a video playing application. In this situation, while the video is 27045 * playing the application would like to go into a complete full-screen mode, 27046 * to use as much of the display as possible for the video. When in this state 27047 * the user can not interact with the application; the system intercepts 27048 * touching on the screen to pop the UI out of full screen mode. See 27049 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 27050 * 27051 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 27052 * content} 27053 * 27054 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 27055 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 27056 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 27057 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 27058 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 27059 * 27060 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27061 * instead. 27062 */ 27063 @Deprecated setSystemUiVisibility(int visibility)27064 public void setSystemUiVisibility(int visibility) { 27065 if (visibility != mSystemUiVisibility) { 27066 mSystemUiVisibility = visibility; 27067 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 27068 mParent.recomputeViewAttributes(this); 27069 } 27070 } 27071 } 27072 27073 /** 27074 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 27075 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 27076 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 27077 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 27078 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 27079 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 27080 * 27081 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27082 * instead. 27083 */ 27084 @Deprecated getSystemUiVisibility()27085 public int getSystemUiVisibility() { 27086 return mSystemUiVisibility; 27087 } 27088 27089 /** 27090 * Returns the current system UI visibility that is currently set for 27091 * the entire window. This is the combination of the 27092 * {@link #setSystemUiVisibility(int)} values supplied by all of the 27093 * views in the window. 27094 * 27095 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27096 * instead. 27097 */ 27098 @Deprecated getWindowSystemUiVisibility()27099 public int getWindowSystemUiVisibility() { 27100 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 27101 } 27102 27103 /** 27104 * Override to find out when the window's requested system UI visibility 27105 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 27106 * This is different from the callbacks received through 27107 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 27108 * in that this is only telling you about the local request of the window, 27109 * not the actual values applied by the system. 27110 * 27111 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27112 * instead. 27113 */ 27114 @Deprecated onWindowSystemUiVisibilityChanged(int visible)27115 public void onWindowSystemUiVisibilityChanged(int visible) { 27116 } 27117 27118 /** 27119 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 27120 * the view hierarchy. 27121 * 27122 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27123 * instead. 27124 */ 27125 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)27126 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 27127 onWindowSystemUiVisibilityChanged(visible); 27128 } 27129 27130 /** 27131 * Set a listener to receive callbacks when the visibility of the system bar changes. 27132 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 27133 * 27134 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 27135 * by setting a {@link OnApplyWindowInsetsListener} on this view. 27136 */ 27137 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)27138 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 27139 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 27140 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 27141 mParent.recomputeViewAttributes(this); 27142 } 27143 } 27144 27145 /** 27146 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 27147 * the view hierarchy. 27148 * 27149 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 27150 * by setting a {@link OnApplyWindowInsetsListener} on this view. 27151 */ 27152 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)27153 public void dispatchSystemUiVisibilityChanged(int visibility) { 27154 ListenerInfo li = mListenerInfo; 27155 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 27156 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 27157 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 27158 } 27159 } 27160 updateLocalSystemUiVisibility(int localValue, int localChanges)27161 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 27162 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 27163 if (val != mSystemUiVisibility) { 27164 setSystemUiVisibility(val); 27165 return true; 27166 } 27167 return false; 27168 } 27169 27170 /** @hide */ 27171 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setDisabledSystemUiVisibility(int flags)27172 public void setDisabledSystemUiVisibility(int flags) { 27173 if (mAttachInfo != null) { 27174 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 27175 mAttachInfo.mDisabledSystemUiVisibility = flags; 27176 if (mParent != null) { 27177 mParent.recomputeViewAttributes(this); 27178 } 27179 } 27180 } 27181 } 27182 27183 /** 27184 * This needs to be a better API before it is exposed. For now, only the root view will get 27185 * notified. 27186 * @hide 27187 */ onSystemBarAppearanceChanged(@indowInsetsController.Appearance int appearance)27188 public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { 27189 } 27190 27191 /** 27192 * Creates an image that the system displays during the drag and drop 27193 * operation. This is called a "drag shadow". The default implementation 27194 * for a DragShadowBuilder based on a View returns an image that has exactly the same 27195 * appearance as the given View. The default also positions the center of the drag shadow 27196 * directly under the touch point. If no View is provided (the constructor with no parameters 27197 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 27198 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 27199 * default is an invisible drag shadow. 27200 * <p> 27201 * You are not required to use the View you provide to the constructor as the basis of the 27202 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 27203 * anything you want as the drag shadow. 27204 * </p> 27205 * <p> 27206 * You pass a DragShadowBuilder object to the system when you start the drag. The system 27207 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 27208 * size and position of the drag shadow. It uses this data to construct a 27209 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 27210 * so that your application can draw the shadow image in the Canvas. 27211 * </p> 27212 * 27213 * <div class="special reference"> 27214 * <h3>Developer Guides</h3> 27215 * <p>For a guide to implementing drag and drop features, read the 27216 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 27217 * </div> 27218 */ 27219 public static class DragShadowBuilder { 27220 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 27221 private final WeakReference<View> mView; 27222 27223 /** 27224 * Constructs a shadow image builder based on a View. By default, the resulting drag 27225 * shadow will have the same appearance and dimensions as the View, with the touch point 27226 * over the center of the View. 27227 * @param view A View. Any View in scope can be used. 27228 */ DragShadowBuilder(View view)27229 public DragShadowBuilder(View view) { 27230 mView = new WeakReference<View>(view); 27231 } 27232 27233 /** 27234 * Construct a shadow builder object with no associated View. This 27235 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 27236 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 27237 * to supply the drag shadow's dimensions and appearance without 27238 * reference to any View object. 27239 */ DragShadowBuilder()27240 public DragShadowBuilder() { 27241 mView = new WeakReference<View>(null); 27242 } 27243 27244 /** 27245 * Returns the View object that had been passed to the 27246 * {@link #DragShadowBuilder(View)} 27247 * constructor. If that View parameter was {@code null} or if the 27248 * {@link #DragShadowBuilder()} 27249 * constructor was used to instantiate the builder object, this method will return 27250 * null. 27251 * 27252 * @return The View object associate with this builder object. 27253 */ 27254 @SuppressWarnings({"JavadocReference"}) getView()27255 final public View getView() { 27256 return mView.get(); 27257 } 27258 27259 /** 27260 * Provides the metrics for the shadow image. These include the dimensions of 27261 * the shadow image, and the point within that shadow that should 27262 * be centered under the touch location while dragging. 27263 * <p> 27264 * The default implementation sets the dimensions of the shadow to be the 27265 * same as the dimensions of the View itself and centers the shadow under 27266 * the touch point. 27267 * </p> 27268 * 27269 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 27270 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 27271 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 27272 * image. Since Android P, the width and height must be positive values. 27273 * 27274 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 27275 * shadow image that should be underneath the touch point during the drag and drop 27276 * operation. Your application must set {@link android.graphics.Point#x} to the 27277 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 27278 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)27279 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 27280 final View view = mView.get(); 27281 if (view != null) { 27282 outShadowSize.set(view.getWidth(), view.getHeight()); 27283 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 27284 } else { 27285 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 27286 } 27287 } 27288 27289 /** 27290 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 27291 * based on the dimensions it received from the 27292 * {@link #onProvideShadowMetrics(Point, Point)} callback. 27293 * 27294 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 27295 */ onDrawShadow(Canvas canvas)27296 public void onDrawShadow(Canvas canvas) { 27297 final View view = mView.get(); 27298 if (view != null) { 27299 view.draw(canvas); 27300 } else { 27301 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 27302 } 27303 } 27304 } 27305 27306 /** 27307 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 27308 * startDragAndDrop()} for newer platform versions. 27309 */ 27310 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)27311 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 27312 Object myLocalState, int flags) { 27313 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 27314 } 27315 27316 /** 27317 * Starts a drag and drop operation. When your application calls this method, it passes a 27318 * {@link android.view.View.DragShadowBuilder} object to the system. The 27319 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 27320 * to get metrics for the drag shadow, and then calls the object's 27321 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 27322 * <p> 27323 * Once the system has the drag shadow, it begins the drag and drop operation by sending 27324 * drag events to all the View objects in your application that are currently visible. It does 27325 * this either by calling the View object's drag listener (an implementation of 27326 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 27327 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 27328 * Both are passed a {@link android.view.DragEvent} object that has a 27329 * {@link android.view.DragEvent#getAction()} value of 27330 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 27331 * </p> 27332 * <p> 27333 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 27334 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 27335 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 27336 * to the View the user selected for dragging. 27337 * </p> 27338 * @param data A {@link android.content.ClipData} object pointing to the data to be 27339 * transferred by the drag and drop operation. 27340 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 27341 * drag shadow. 27342 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 27343 * drop operation. When dispatching drag events to views in the same activity this object 27344 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 27345 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 27346 * will return null). 27347 * <p> 27348 * myLocalState is a lightweight mechanism for the sending information from the dragged View 27349 * to the target Views. For example, it can contain flags that differentiate between a 27350 * a copy operation and a move operation. 27351 * </p> 27352 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 27353 * flags, or any combination of the following: 27354 * <ul> 27355 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 27356 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 27357 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 27358 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 27359 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 27360 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 27361 * <li>{@link #DRAG_FLAG_ACCESSIBILITY_ACTION}</li> 27362 * </ul> 27363 * @return {@code true} if the method completes successfully, or 27364 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 27365 * do a drag because of another ongoing operation or some other reasons. 27366 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)27367 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 27368 Object myLocalState, int flags) { 27369 if (ViewDebug.DEBUG_DRAG) { 27370 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 27371 } 27372 if (mAttachInfo == null) { 27373 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 27374 return false; 27375 } 27376 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 27377 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 27378 return false; 27379 } 27380 27381 if (data != null) { 27382 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 27383 } 27384 27385 Rect bounds = new Rect(); 27386 getBoundsOnScreen(bounds, true); 27387 27388 Point lastTouchPoint = new Point(); 27389 mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); 27390 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 27391 27392 // Skip surface logic since shadows and animation are not required during the a11y drag 27393 final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); 27394 if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { 27395 try { 27396 IBinder token = mAttachInfo.mSession.performDrag( 27397 mAttachInfo.mWindow, flags, null, 27398 mAttachInfo.mViewRootImpl.getLastTouchSource(), 27399 0f, 0f, 0f, 0f, data); 27400 if (ViewDebug.DEBUG_DRAG) { 27401 Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); 27402 } 27403 if (token != null) { 27404 root.setLocalDragState(myLocalState); 27405 mAttachInfo.mDragToken = token; 27406 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 27407 setAccessibilityDragStarted(true); 27408 } 27409 return token != null; 27410 } catch (Exception e) { 27411 Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); 27412 return false; 27413 } 27414 } 27415 27416 Point shadowSize = new Point(); 27417 Point shadowTouchPoint = new Point(); 27418 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 27419 27420 if ((shadowSize.x < 0) || (shadowSize.y < 0) 27421 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 27422 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 27423 } 27424 27425 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 27426 // does not accept zero size surface. 27427 if (shadowSize.x == 0 || shadowSize.y == 0) { 27428 if (!sAcceptZeroSizeDragShadow) { 27429 throw new IllegalStateException("Drag shadow dimensions must be positive"); 27430 } 27431 shadowSize.x = 1; 27432 shadowSize.y = 1; 27433 } 27434 27435 if (ViewDebug.DEBUG_DRAG) { 27436 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 27437 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 27438 } 27439 27440 final SurfaceSession session = new SurfaceSession(); 27441 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 27442 .setName("drag surface") 27443 .setParent(root.getSurfaceControl()) 27444 .setBufferSize(shadowSize.x, shadowSize.y) 27445 .setFormat(PixelFormat.TRANSLUCENT) 27446 .setCallsite("View.startDragAndDrop") 27447 .build(); 27448 final Surface surface = new Surface(); 27449 surface.copyFrom(surfaceControl); 27450 IBinder token = null; 27451 try { 27452 final Canvas canvas = isHardwareAccelerated() 27453 ? surface.lockHardwareCanvas() 27454 : surface.lockCanvas(null); 27455 try { 27456 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 27457 shadowBuilder.onDrawShadow(canvas); 27458 } finally { 27459 surface.unlockCanvasAndPost(canvas); 27460 } 27461 27462 token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, 27463 root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y, 27464 shadowTouchPoint.x, shadowTouchPoint.y, data); 27465 if (ViewDebug.DEBUG_DRAG) { 27466 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 27467 } 27468 if (token != null) { 27469 if (mAttachInfo.mDragSurface != null) { 27470 mAttachInfo.mDragSurface.release(); 27471 } 27472 mAttachInfo.mDragSurface = surface; 27473 mAttachInfo.mDragToken = token; 27474 // Cache the local state object for delivery with DragEvents 27475 root.setLocalDragState(myLocalState); 27476 if (a11yEnabled) { 27477 // Set for AccessibilityEvents 27478 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 27479 } 27480 } 27481 return token != null; 27482 } catch (Exception e) { 27483 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 27484 return false; 27485 } finally { 27486 if (token == null) { 27487 surface.destroy(); 27488 } 27489 session.kill(); 27490 } 27491 } 27492 setAccessibilityDragStarted(boolean started)27493 void setAccessibilityDragStarted(boolean started) { 27494 int pflags4 = mPrivateFlags4; 27495 if (started) { 27496 pflags4 |= PFLAG4_DRAG_A11Y_STARTED; 27497 } else { 27498 pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; 27499 } 27500 27501 if (pflags4 != mPrivateFlags4) { 27502 mPrivateFlags4 = pflags4; 27503 sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); 27504 } 27505 } 27506 startedSystemDragForAccessibility()27507 private boolean startedSystemDragForAccessibility() { 27508 return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; 27509 } 27510 27511 /** 27512 * Cancels an ongoing drag and drop operation. 27513 * <p> 27514 * A {@link android.view.DragEvent} object with 27515 * {@link android.view.DragEvent#getAction()} value of 27516 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 27517 * {@link android.view.DragEvent#getResult()} value of {@code false} 27518 * will be sent to every 27519 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 27520 * even if they are not currently visible. 27521 * </p> 27522 * <p> 27523 * This method can be called on any View in the same window as the View on which 27524 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 27525 * was called. 27526 * </p> 27527 */ cancelDragAndDrop()27528 public final void cancelDragAndDrop() { 27529 if (ViewDebug.DEBUG_DRAG) { 27530 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 27531 } 27532 if (mAttachInfo == null) { 27533 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 27534 return; 27535 } 27536 if (mAttachInfo.mDragToken != null) { 27537 try { 27538 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 27539 } catch (Exception e) { 27540 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 27541 } 27542 mAttachInfo.mDragToken = null; 27543 } else { 27544 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 27545 } 27546 } 27547 27548 /** 27549 * Updates the drag shadow for the ongoing drag and drop operation. 27550 * 27551 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 27552 * new drag shadow. 27553 */ updateDragShadow(DragShadowBuilder shadowBuilder)27554 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 27555 if (ViewDebug.DEBUG_DRAG) { 27556 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 27557 } 27558 if (mAttachInfo == null) { 27559 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 27560 return; 27561 } 27562 if (mAttachInfo.mDragToken != null) { 27563 try { 27564 Canvas canvas = isHardwareAccelerated() 27565 ? mAttachInfo.mDragSurface.lockHardwareCanvas() 27566 : mAttachInfo.mDragSurface.lockCanvas(null); 27567 try { 27568 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 27569 shadowBuilder.onDrawShadow(canvas); 27570 } finally { 27571 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 27572 } 27573 } catch (Exception e) { 27574 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 27575 } 27576 } else { 27577 Log.e(VIEW_LOG_TAG, "No active drag"); 27578 } 27579 } 27580 27581 /** 27582 * Starts a move from {startX, startY}, the amount of the movement will be the offset 27583 * between {startX, startY} and the new cursor positon. 27584 * @param startX horizontal coordinate where the move started. 27585 * @param startY vertical coordinate where the move started. 27586 * @return whether moving was started successfully. 27587 * @hide 27588 */ startMovingTask(float startX, float startY)27589 public final boolean startMovingTask(float startX, float startY) { 27590 if (ViewDebug.DEBUG_POSITIONING) { 27591 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 27592 } 27593 try { 27594 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 27595 } catch (RemoteException e) { 27596 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 27597 } 27598 return false; 27599 } 27600 27601 /** 27602 * Finish a window move task. 27603 * @hide 27604 */ finishMovingTask()27605 public void finishMovingTask() { 27606 if (ViewDebug.DEBUG_POSITIONING) { 27607 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 27608 } 27609 try { 27610 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 27611 } catch (RemoteException e) { 27612 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 27613 } 27614 } 27615 27616 /** 27617 * Handles drag events sent by the system following a call to 27618 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 27619 * startDragAndDrop()}. 27620 * <p> 27621 * The system calls this method and passes a {@link DragEvent} object in response to drag and 27622 * drop events. This method can then call {@link DragEvent#getAction()} to determine the state 27623 * of the drag and drop operation. 27624 * <p> 27625 * The default implementation returns {@code false} unless an {@link OnReceiveContentListener} 27626 * has been set for this view (see {@link #setOnReceiveContentListener}), in which case 27627 * the default implementation does the following: 27628 * <ul> 27629 * <li>Returns {@code true} for an 27630 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event 27631 * <li>Calls {@link #performReceiveContent} for an 27632 * {@link DragEvent#ACTION_DROP ACTION_DROP} event 27633 * <li>Returns {@code true} for an {@link DragEvent#ACTION_DROP ACTION_DROP} event if the 27634 * {@code OnReceiveContentListener} consumed some or all of the content 27635 * </ul> 27636 * 27637 * @param event The {@link DragEvent} object sent by the system. The 27638 * {@link DragEvent#getAction()} method returns an action type constant that indicates the 27639 * type of drag event represented by this object. 27640 * @return {@code true} if the method successfully handled the drag event, otherwise 27641 * {@code false}. 27642 * <p> 27643 * The method must return {@code true} in response to an 27644 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} action type to continue to 27645 * receive drag events for the current drag and drop operation. 27646 * <p> 27647 * The method should return {@code true} in response to an 27648 * {@link DragEvent#ACTION_DROP ACTION_DROP} action type if the dropped data was consumed 27649 * (at least partially); {@code false}, if none of the data was consumed. 27650 * <p> 27651 * For all other events, the return value is {@code false}. 27652 */ onDragEvent(DragEvent event)27653 public boolean onDragEvent(DragEvent event) { 27654 if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { 27655 return false; 27656 } 27657 // Accept drag events by default if there's an OnReceiveContentListener set. 27658 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { 27659 return true; 27660 } 27661 if (event.getAction() == DragEvent.ACTION_DROP) { 27662 final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); 27663 if (permissions != null) { 27664 permissions.takeTransient(); 27665 } 27666 final ContentInfo payload = 27667 new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) 27668 .setDragAndDropPermissions(permissions) 27669 .build(); 27670 ContentInfo remainingPayload = performReceiveContent(payload); 27671 // Return true unless none of the payload was consumed. 27672 return remainingPayload != payload; 27673 } 27674 return false; 27675 } 27676 27677 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)27678 boolean dispatchDragEnterExitInPreN(DragEvent event) { 27679 return callDragEventHandler(event); 27680 } 27681 27682 /** 27683 * Detects if this View is enabled and has a drag event listener. 27684 * If both are true, then it calls the drag event listener with the 27685 * {@link android.view.DragEvent} it received. If the drag event listener returns 27686 * {@code true}, then dispatchDragEvent() returns {@code true}. 27687 * <p> 27688 * For all other cases, the method calls the 27689 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 27690 * method and returns its result. 27691 * </p> 27692 * <p> 27693 * This ensures that a drag event is always consumed, even if the View does not have a drag 27694 * event listener. However, if the View has a listener and the listener returns true, then 27695 * onDragEvent() is not called. 27696 * </p> 27697 */ dispatchDragEvent(DragEvent event)27698 public boolean dispatchDragEvent(DragEvent event) { 27699 event.mEventHandlerWasCalled = true; 27700 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 27701 event.mAction == DragEvent.ACTION_DROP) { 27702 // About to deliver an event with coordinates to this view. Notify that now this view 27703 // has drag focus. This will send exit/enter events as needed. 27704 getViewRootImpl().setDragFocus(this, event); 27705 } 27706 return callDragEventHandler(event); 27707 } 27708 callDragEventHandler(DragEvent event)27709 final boolean callDragEventHandler(DragEvent event) { 27710 final boolean result; 27711 27712 ListenerInfo li = mListenerInfo; 27713 //noinspection SimplifiableIfStatement 27714 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 27715 && li.mOnDragListener.onDrag(this, event)) { 27716 result = true; 27717 } else { 27718 result = onDragEvent(event); 27719 } 27720 27721 switch (event.mAction) { 27722 case DragEvent.ACTION_DRAG_STARTED: { 27723 if (result && li != null && li.mOnDragListener != null) { 27724 sendWindowContentChangedAccessibilityEvent( 27725 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 27726 } 27727 } break; 27728 case DragEvent.ACTION_DRAG_ENTERED: { 27729 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 27730 refreshDrawableState(); 27731 } break; 27732 case DragEvent.ACTION_DRAG_EXITED: { 27733 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 27734 refreshDrawableState(); 27735 } break; 27736 case DragEvent.ACTION_DROP: { 27737 if (result && li != null && (li.mOnDragListener != null 27738 || li.mOnReceiveContentListener != null)) { 27739 sendWindowContentChangedAccessibilityEvent( 27740 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); 27741 } 27742 } break; 27743 case DragEvent.ACTION_DRAG_ENDED: { 27744 sendWindowContentChangedAccessibilityEvent( 27745 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 27746 mPrivateFlags2 &= ~View.DRAG_MASK; 27747 refreshDrawableState(); 27748 } break; 27749 } 27750 27751 return result; 27752 } 27753 canAcceptDrag()27754 boolean canAcceptDrag() { 27755 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 27756 } 27757 sendWindowContentChangedAccessibilityEvent(int changeType)27758 void sendWindowContentChangedAccessibilityEvent(int changeType) { 27759 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 27760 AccessibilityEvent event = AccessibilityEvent.obtain(); 27761 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 27762 event.setContentChangeTypes(changeType); 27763 sendAccessibilityEventUnchecked(event); 27764 } 27765 } 27766 27767 /** 27768 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 27769 * it is ever exposed at all. 27770 * @hide 27771 */ 27772 @UnsupportedAppUsage onCloseSystemDialogs(String reason)27773 public void onCloseSystemDialogs(String reason) { 27774 } 27775 27776 /** 27777 * Given a Drawable whose bounds have been set to draw into this view, 27778 * update a Region being computed for 27779 * {@link #gatherTransparentRegion(android.graphics.Region)} so 27780 * that any non-transparent parts of the Drawable are removed from the 27781 * given transparent region. 27782 * 27783 * @param dr The Drawable whose transparency is to be applied to the region. 27784 * @param region A Region holding the current transparency information, 27785 * where any parts of the region that are set are considered to be 27786 * transparent. On return, this region will be modified to have the 27787 * transparency information reduced by the corresponding parts of the 27788 * Drawable that are not transparent. 27789 * {@hide} 27790 */ 27791 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyDrawableToTransparentRegion(Drawable dr, Region region)27792 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 27793 if (DBG) { 27794 Log.i("View", "Getting transparent region for: " + this); 27795 } 27796 final Region r = dr.getTransparentRegion(); 27797 final Rect db = dr.getBounds(); 27798 final AttachInfo attachInfo = mAttachInfo; 27799 if (r != null && attachInfo != null) { 27800 final int w = getRight()-getLeft(); 27801 final int h = getBottom()-getTop(); 27802 if (db.left > 0) { 27803 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 27804 r.op(0, 0, db.left, h, Region.Op.UNION); 27805 } 27806 if (db.right < w) { 27807 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 27808 r.op(db.right, 0, w, h, Region.Op.UNION); 27809 } 27810 if (db.top > 0) { 27811 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 27812 r.op(0, 0, w, db.top, Region.Op.UNION); 27813 } 27814 if (db.bottom < h) { 27815 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 27816 r.op(0, db.bottom, w, h, Region.Op.UNION); 27817 } 27818 final int[] location = attachInfo.mTransparentLocation; 27819 getLocationInWindow(location); 27820 r.translate(location[0], location[1]); 27821 region.op(r, Region.Op.INTERSECT); 27822 } else { 27823 region.op(db, Region.Op.DIFFERENCE); 27824 } 27825 } 27826 checkForLongClick(long delay, float x, float y, int classification)27827 private void checkForLongClick(long delay, float x, float y, int classification) { 27828 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 27829 mHasPerformedLongPress = false; 27830 27831 if (mPendingCheckForLongPress == null) { 27832 mPendingCheckForLongPress = new CheckForLongPress(); 27833 } 27834 mPendingCheckForLongPress.setAnchor(x, y); 27835 mPendingCheckForLongPress.rememberWindowAttachCount(); 27836 mPendingCheckForLongPress.rememberPressedState(); 27837 mPendingCheckForLongPress.setClassification(classification); 27838 postDelayed(mPendingCheckForLongPress, delay); 27839 } 27840 } 27841 27842 /** 27843 * Inflate a view from an XML resource. This convenience method wraps the {@link 27844 * LayoutInflater} class, which provides a full range of options for view inflation. 27845 * 27846 * @param context The Context object for your activity or application. 27847 * @param resource The resource ID to inflate 27848 * @param root A view group that will be the parent. Used to properly inflate the 27849 * layout_* parameters. 27850 * @see LayoutInflater 27851 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)27852 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 27853 LayoutInflater factory = LayoutInflater.from(context); 27854 return factory.inflate(resource, root); 27855 } 27856 27857 /** 27858 * Scroll the view with standard behavior for scrolling beyond the normal 27859 * content boundaries. Views that call this method should override 27860 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 27861 * results of an over-scroll operation. 27862 * 27863 * Views can use this method to handle any touch or fling-based scrolling. 27864 * 27865 * @param deltaX Change in X in pixels 27866 * @param deltaY Change in Y in pixels 27867 * @param scrollX Current X scroll value in pixels before applying deltaX 27868 * @param scrollY Current Y scroll value in pixels before applying deltaY 27869 * @param scrollRangeX Maximum content scroll range along the X axis 27870 * @param scrollRangeY Maximum content scroll range along the Y axis 27871 * @param maxOverScrollX Number of pixels to overscroll by in either direction 27872 * along the X axis. 27873 * @param maxOverScrollY Number of pixels to overscroll by in either direction 27874 * along the Y axis. 27875 * @param isTouchEvent true if this scroll operation is the result of a touch event. 27876 * @return true if scrolling was clamped to an over-scroll boundary along either 27877 * axis, false otherwise. 27878 */ 27879 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)27880 protected boolean overScrollBy(int deltaX, int deltaY, 27881 int scrollX, int scrollY, 27882 int scrollRangeX, int scrollRangeY, 27883 int maxOverScrollX, int maxOverScrollY, 27884 boolean isTouchEvent) { 27885 final int overScrollMode = mOverScrollMode; 27886 final boolean canScrollHorizontal = 27887 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 27888 final boolean canScrollVertical = 27889 computeVerticalScrollRange() > computeVerticalScrollExtent(); 27890 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 27891 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 27892 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 27893 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 27894 27895 int newScrollX = scrollX + deltaX; 27896 if (!overScrollHorizontal) { 27897 maxOverScrollX = 0; 27898 } 27899 27900 int newScrollY = scrollY + deltaY; 27901 if (!overScrollVertical) { 27902 maxOverScrollY = 0; 27903 } 27904 27905 // Clamp values if at the limits and record 27906 final int left = -maxOverScrollX; 27907 final int right = maxOverScrollX + scrollRangeX; 27908 final int top = -maxOverScrollY; 27909 final int bottom = maxOverScrollY + scrollRangeY; 27910 27911 boolean clampedX = false; 27912 if (newScrollX > right) { 27913 newScrollX = right; 27914 clampedX = true; 27915 } else if (newScrollX < left) { 27916 newScrollX = left; 27917 clampedX = true; 27918 } 27919 27920 boolean clampedY = false; 27921 if (newScrollY > bottom) { 27922 newScrollY = bottom; 27923 clampedY = true; 27924 } else if (newScrollY < top) { 27925 newScrollY = top; 27926 clampedY = true; 27927 } 27928 27929 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 27930 27931 return clampedX || clampedY; 27932 } 27933 27934 /** 27935 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 27936 * respond to the results of an over-scroll operation. 27937 * 27938 * @param scrollX New X scroll value in pixels 27939 * @param scrollY New Y scroll value in pixels 27940 * @param clampedX True if scrollX was clamped to an over-scroll boundary 27941 * @param clampedY True if scrollY was clamped to an over-scroll boundary 27942 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)27943 protected void onOverScrolled(int scrollX, int scrollY, 27944 boolean clampedX, boolean clampedY) { 27945 // Intentionally empty. 27946 } 27947 27948 /** 27949 * Returns the over-scroll mode for this view. The result will be 27950 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 27951 * (allow over-scrolling only if the view content is larger than the container), 27952 * or {@link #OVER_SCROLL_NEVER}. 27953 * 27954 * @return This view's over-scroll mode. 27955 */ 27956 @InspectableProperty(enumMapping = { 27957 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 27958 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 27959 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 27960 }) getOverScrollMode()27961 public int getOverScrollMode() { 27962 return mOverScrollMode; 27963 } 27964 27965 /** 27966 * Set the over-scroll mode for this view. Valid over-scroll modes are 27967 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 27968 * (allow over-scrolling only if the view content is larger than the container), 27969 * or {@link #OVER_SCROLL_NEVER}. 27970 * 27971 * Setting the over-scroll mode of a view will have an effect only if the 27972 * view is capable of scrolling. 27973 * 27974 * @param overScrollMode The new over-scroll mode for this view. 27975 */ setOverScrollMode(int overScrollMode)27976 public void setOverScrollMode(int overScrollMode) { 27977 if (overScrollMode != OVER_SCROLL_ALWAYS && 27978 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 27979 overScrollMode != OVER_SCROLL_NEVER) { 27980 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 27981 } 27982 mOverScrollMode = overScrollMode; 27983 } 27984 27985 /** 27986 * Enable or disable nested scrolling for this view. 27987 * 27988 * <p>If this property is set to true the view will be permitted to initiate nested 27989 * scrolling operations with a compatible parent view in the current hierarchy. If this 27990 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 27991 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 27992 * the nested scroll.</p> 27993 * 27994 * @param enabled true to enable nested scrolling, false to disable 27995 * 27996 * @see #isNestedScrollingEnabled() 27997 */ setNestedScrollingEnabled(boolean enabled)27998 public void setNestedScrollingEnabled(boolean enabled) { 27999 if (enabled) { 28000 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 28001 } else { 28002 stopNestedScroll(); 28003 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 28004 } 28005 } 28006 28007 /** 28008 * Returns true if nested scrolling is enabled for this view. 28009 * 28010 * <p>If nested scrolling is enabled and this View class implementation supports it, 28011 * this view will act as a nested scrolling child view when applicable, forwarding data 28012 * about the scroll operation in progress to a compatible and cooperating nested scrolling 28013 * parent.</p> 28014 * 28015 * @return true if nested scrolling is enabled 28016 * 28017 * @see #setNestedScrollingEnabled(boolean) 28018 */ 28019 @InspectableProperty isNestedScrollingEnabled()28020 public boolean isNestedScrollingEnabled() { 28021 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 28022 PFLAG3_NESTED_SCROLLING_ENABLED; 28023 } 28024 28025 /** 28026 * Begin a nestable scroll operation along the given axes. 28027 * 28028 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 28029 * 28030 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 28031 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 28032 * In the case of touch scrolling the nested scroll will be terminated automatically in 28033 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 28034 * In the event of programmatic scrolling the caller must explicitly call 28035 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 28036 * 28037 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 28038 * If it returns false the caller may ignore the rest of this contract until the next scroll. 28039 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 28040 * 28041 * <p>At each incremental step of the scroll the caller should invoke 28042 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 28043 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 28044 * parent at least partially consumed the scroll and the caller should adjust the amount it 28045 * scrolls by.</p> 28046 * 28047 * <p>After applying the remainder of the scroll delta the caller should invoke 28048 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 28049 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 28050 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 28051 * </p> 28052 * 28053 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 28054 * {@link #SCROLL_AXIS_VERTICAL}. 28055 * @return true if a cooperative parent was found and nested scrolling has been enabled for 28056 * the current gesture. 28057 * 28058 * @see #stopNestedScroll() 28059 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 28060 * @see #dispatchNestedScroll(int, int, int, int, int[]) 28061 */ startNestedScroll(int axes)28062 public boolean startNestedScroll(int axes) { 28063 if (hasNestedScrollingParent()) { 28064 // Already in progress 28065 return true; 28066 } 28067 if (isNestedScrollingEnabled()) { 28068 ViewParent p = getParent(); 28069 View child = this; 28070 while (p != null) { 28071 try { 28072 if (p.onStartNestedScroll(child, this, axes)) { 28073 mNestedScrollingParent = p; 28074 p.onNestedScrollAccepted(child, this, axes); 28075 return true; 28076 } 28077 } catch (AbstractMethodError e) { 28078 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 28079 "method onStartNestedScroll", e); 28080 // Allow the search upward to continue 28081 } 28082 if (p instanceof View) { 28083 child = (View) p; 28084 } 28085 p = p.getParent(); 28086 } 28087 } 28088 return false; 28089 } 28090 28091 /** 28092 * Stop a nested scroll in progress. 28093 * 28094 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 28095 * 28096 * @see #startNestedScroll(int) 28097 */ stopNestedScroll()28098 public void stopNestedScroll() { 28099 if (mNestedScrollingParent != null) { 28100 mNestedScrollingParent.onStopNestedScroll(this); 28101 mNestedScrollingParent = null; 28102 } 28103 } 28104 28105 /** 28106 * Returns true if this view has a nested scrolling parent. 28107 * 28108 * <p>The presence of a nested scrolling parent indicates that this view has initiated 28109 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 28110 * 28111 * @return whether this view has a nested scrolling parent 28112 */ hasNestedScrollingParent()28113 public boolean hasNestedScrollingParent() { 28114 return mNestedScrollingParent != null; 28115 } 28116 28117 /** 28118 * Dispatch one step of a nested scroll in progress. 28119 * 28120 * <p>Implementations of views that support nested scrolling should call this to report 28121 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 28122 * is not currently in progress or nested scrolling is not 28123 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 28124 * 28125 * <p>Compatible View implementations should also call 28126 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 28127 * consuming a component of the scroll event themselves.</p> 28128 * 28129 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 28130 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 28131 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 28132 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 28133 * @param offsetInWindow Optional. If not null, on return this will contain the offset 28134 * in local view coordinates of this view from before this operation 28135 * to after it completes. View implementations may use this to adjust 28136 * expected input coordinate tracking. 28137 * @return true if the event was dispatched, false if it could not be dispatched. 28138 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 28139 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)28140 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 28141 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 28142 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28143 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 28144 int startX = 0; 28145 int startY = 0; 28146 if (offsetInWindow != null) { 28147 getLocationInWindow(offsetInWindow); 28148 startX = offsetInWindow[0]; 28149 startY = offsetInWindow[1]; 28150 } 28151 28152 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 28153 dxUnconsumed, dyUnconsumed); 28154 28155 if (offsetInWindow != null) { 28156 getLocationInWindow(offsetInWindow); 28157 offsetInWindow[0] -= startX; 28158 offsetInWindow[1] -= startY; 28159 } 28160 return true; 28161 } else if (offsetInWindow != null) { 28162 // No motion, no dispatch. Keep offsetInWindow up to date. 28163 offsetInWindow[0] = 0; 28164 offsetInWindow[1] = 0; 28165 } 28166 } 28167 return false; 28168 } 28169 28170 /** 28171 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 28172 * 28173 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 28174 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 28175 * scrolling operation to consume some or all of the scroll operation before the child view 28176 * consumes it.</p> 28177 * 28178 * @param dx Horizontal scroll distance in pixels 28179 * @param dy Vertical scroll distance in pixels 28180 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 28181 * and consumed[1] the consumed dy. 28182 * @param offsetInWindow Optional. If not null, on return this will contain the offset 28183 * in local view coordinates of this view from before this operation 28184 * to after it completes. View implementations may use this to adjust 28185 * expected input coordinate tracking. 28186 * @return true if the parent consumed some or all of the scroll delta 28187 * @see #dispatchNestedScroll(int, int, int, int, int[]) 28188 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)28189 public boolean dispatchNestedPreScroll(int dx, int dy, 28190 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 28191 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28192 if (dx != 0 || dy != 0) { 28193 int startX = 0; 28194 int startY = 0; 28195 if (offsetInWindow != null) { 28196 getLocationInWindow(offsetInWindow); 28197 startX = offsetInWindow[0]; 28198 startY = offsetInWindow[1]; 28199 } 28200 28201 if (consumed == null) { 28202 if (mTempNestedScrollConsumed == null) { 28203 mTempNestedScrollConsumed = new int[2]; 28204 } 28205 consumed = mTempNestedScrollConsumed; 28206 } 28207 consumed[0] = 0; 28208 consumed[1] = 0; 28209 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 28210 28211 if (offsetInWindow != null) { 28212 getLocationInWindow(offsetInWindow); 28213 offsetInWindow[0] -= startX; 28214 offsetInWindow[1] -= startY; 28215 } 28216 return consumed[0] != 0 || consumed[1] != 0; 28217 } else if (offsetInWindow != null) { 28218 offsetInWindow[0] = 0; 28219 offsetInWindow[1] = 0; 28220 } 28221 } 28222 return false; 28223 } 28224 28225 /** 28226 * Dispatch a fling to a nested scrolling parent. 28227 * 28228 * <p>This method should be used to indicate that a nested scrolling child has detected 28229 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 28230 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 28231 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 28232 * along a scrollable axis.</p> 28233 * 28234 * <p>If a nested scrolling child view would normally fling but it is at the edge of 28235 * its own content, it can use this method to delegate the fling to its nested scrolling 28236 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 28237 * 28238 * @param velocityX Horizontal fling velocity in pixels per second 28239 * @param velocityY Vertical fling velocity in pixels per second 28240 * @param consumed true if the child consumed the fling, false otherwise 28241 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 28242 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)28243 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 28244 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28245 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 28246 } 28247 return false; 28248 } 28249 28250 /** 28251 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 28252 * 28253 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 28254 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 28255 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 28256 * before the child view consumes it. If this method returns <code>true</code>, a nested 28257 * parent view consumed the fling and this view should not scroll as a result.</p> 28258 * 28259 * <p>For a better user experience, only one view in a nested scrolling chain should consume 28260 * the fling at a time. If a parent view consumed the fling this method will return false. 28261 * Custom view implementations should account for this in two ways:</p> 28262 * 28263 * <ul> 28264 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 28265 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 28266 * position regardless.</li> 28267 * <li>If a nested parent does consume the fling, this view should not scroll at all, 28268 * even to settle back to a valid idle position.</li> 28269 * </ul> 28270 * 28271 * <p>Views should also not offer fling velocities to nested parent views along an axis 28272 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 28273 * should not offer a horizontal fling velocity to its parents since scrolling along that 28274 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 28275 * 28276 * @param velocityX Horizontal fling velocity in pixels per second 28277 * @param velocityY Vertical fling velocity in pixels per second 28278 * @return true if a nested scrolling parent consumed the fling 28279 */ dispatchNestedPreFling(float velocityX, float velocityY)28280 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 28281 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28282 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 28283 } 28284 return false; 28285 } 28286 28287 /** 28288 * Gets a scale factor that determines the distance the view should scroll 28289 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 28290 * @return The vertical scroll scale factor. 28291 * @hide 28292 */ 28293 @UnsupportedAppUsage getVerticalScrollFactor()28294 protected float getVerticalScrollFactor() { 28295 if (mVerticalScrollFactor == 0) { 28296 TypedValue outValue = new TypedValue(); 28297 if (!mContext.getTheme().resolveAttribute( 28298 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 28299 throw new IllegalStateException( 28300 "Expected theme to define listPreferredItemHeight."); 28301 } 28302 mVerticalScrollFactor = outValue.getDimension( 28303 mContext.getResources().getDisplayMetrics()); 28304 } 28305 return mVerticalScrollFactor; 28306 } 28307 28308 /** 28309 * Gets a scale factor that determines the distance the view should scroll 28310 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 28311 * @return The horizontal scroll scale factor. 28312 * @hide 28313 */ 28314 @UnsupportedAppUsage getHorizontalScrollFactor()28315 protected float getHorizontalScrollFactor() { 28316 // TODO: Should use something else. 28317 return getVerticalScrollFactor(); 28318 } 28319 28320 /** 28321 * Return the value specifying the text direction or policy that was set with 28322 * {@link #setTextDirection(int)}. 28323 * 28324 * @return the defined text direction. It can be one of: 28325 * 28326 * {@link #TEXT_DIRECTION_INHERIT}, 28327 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 28328 * {@link #TEXT_DIRECTION_ANY_RTL}, 28329 * {@link #TEXT_DIRECTION_LTR}, 28330 * {@link #TEXT_DIRECTION_RTL}, 28331 * {@link #TEXT_DIRECTION_LOCALE}, 28332 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 28333 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 28334 * 28335 * @attr ref android.R.styleable#View_textDirection 28336 * 28337 * @hide 28338 */ 28339 @ViewDebug.ExportedProperty(category = "text", mapping = { 28340 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 28341 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 28342 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 28343 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 28344 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 28345 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 28346 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 28347 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 28348 }) 28349 @InspectableProperty(hasAttributeId = false, enumMapping = { 28350 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 28351 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 28352 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 28353 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 28354 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 28355 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 28356 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 28357 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 28358 }) 28359 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextDirection()28360 public int getRawTextDirection() { 28361 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 28362 } 28363 28364 /** 28365 * Set the text direction. 28366 * 28367 * @param textDirection the direction to set. Should be one of: 28368 * 28369 * {@link #TEXT_DIRECTION_INHERIT}, 28370 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 28371 * {@link #TEXT_DIRECTION_ANY_RTL}, 28372 * {@link #TEXT_DIRECTION_LTR}, 28373 * {@link #TEXT_DIRECTION_RTL}, 28374 * {@link #TEXT_DIRECTION_LOCALE} 28375 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 28376 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 28377 * 28378 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 28379 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 28380 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 28381 * 28382 * @attr ref android.R.styleable#View_textDirection 28383 */ setTextDirection(int textDirection)28384 public void setTextDirection(int textDirection) { 28385 if (getRawTextDirection() != textDirection) { 28386 // Reset the current text direction and the resolved one 28387 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 28388 resetResolvedTextDirection(); 28389 // Set the new text direction 28390 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 28391 // Do resolution 28392 resolveTextDirection(); 28393 // Notify change 28394 onRtlPropertiesChanged(getLayoutDirection()); 28395 // Refresh 28396 requestLayout(); 28397 invalidate(true); 28398 } 28399 } 28400 28401 /** 28402 * Return the resolved text direction. 28403 * 28404 * @return the resolved text direction. Returns one of: 28405 * 28406 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 28407 * {@link #TEXT_DIRECTION_ANY_RTL}, 28408 * {@link #TEXT_DIRECTION_LTR}, 28409 * {@link #TEXT_DIRECTION_RTL}, 28410 * {@link #TEXT_DIRECTION_LOCALE}, 28411 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 28412 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 28413 * 28414 * @attr ref android.R.styleable#View_textDirection 28415 */ 28416 @ViewDebug.ExportedProperty(category = "text", mapping = { 28417 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 28418 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 28419 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 28420 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 28421 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 28422 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 28423 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 28424 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 28425 }) 28426 @InspectableProperty(hasAttributeId = false, enumMapping = { 28427 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 28428 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 28429 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 28430 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 28431 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 28432 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 28433 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 28434 }) getTextDirection()28435 public int getTextDirection() { 28436 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 28437 } 28438 28439 /** 28440 * Resolve the text direction. 28441 * 28442 * @return true if resolution has been done, false otherwise. 28443 * 28444 * @hide 28445 */ resolveTextDirection()28446 public boolean resolveTextDirection() { 28447 // Reset any previous text direction resolution 28448 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 28449 28450 if (hasRtlSupport()) { 28451 // Set resolved text direction flag depending on text direction flag 28452 final int textDirection = getRawTextDirection(); 28453 switch(textDirection) { 28454 case TEXT_DIRECTION_INHERIT: 28455 if (!canResolveTextDirection()) { 28456 // We cannot do the resolution if there is no parent, so use the default one 28457 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28458 // Resolution will need to happen again later 28459 return false; 28460 } 28461 28462 // Parent has not yet resolved, so we still return the default 28463 try { 28464 if (!mParent.isTextDirectionResolved()) { 28465 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28466 // Resolution will need to happen again later 28467 return false; 28468 } 28469 } catch (AbstractMethodError e) { 28470 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28471 " does not fully implement ViewParent", e); 28472 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 28473 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28474 return true; 28475 } 28476 28477 // Set current resolved direction to the same value as the parent's one 28478 int parentResolvedDirection; 28479 try { 28480 parentResolvedDirection = mParent.getTextDirection(); 28481 } catch (AbstractMethodError e) { 28482 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28483 " does not fully implement ViewParent", e); 28484 parentResolvedDirection = TEXT_DIRECTION_LTR; 28485 } 28486 switch (parentResolvedDirection) { 28487 case TEXT_DIRECTION_FIRST_STRONG: 28488 case TEXT_DIRECTION_ANY_RTL: 28489 case TEXT_DIRECTION_LTR: 28490 case TEXT_DIRECTION_RTL: 28491 case TEXT_DIRECTION_LOCALE: 28492 case TEXT_DIRECTION_FIRST_STRONG_LTR: 28493 case TEXT_DIRECTION_FIRST_STRONG_RTL: 28494 mPrivateFlags2 |= 28495 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 28496 break; 28497 default: 28498 // Default resolved direction is "first strong" heuristic 28499 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28500 } 28501 break; 28502 case TEXT_DIRECTION_FIRST_STRONG: 28503 case TEXT_DIRECTION_ANY_RTL: 28504 case TEXT_DIRECTION_LTR: 28505 case TEXT_DIRECTION_RTL: 28506 case TEXT_DIRECTION_LOCALE: 28507 case TEXT_DIRECTION_FIRST_STRONG_LTR: 28508 case TEXT_DIRECTION_FIRST_STRONG_RTL: 28509 // Resolved direction is the same as text direction 28510 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 28511 break; 28512 default: 28513 // Default resolved direction is "first strong" heuristic 28514 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28515 } 28516 } else { 28517 // Default resolved direction is "first strong" heuristic 28518 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28519 } 28520 28521 // Set to resolved 28522 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 28523 return true; 28524 } 28525 28526 /** 28527 * Check if text direction resolution can be done. 28528 * 28529 * @return true if text direction resolution can be done otherwise return false. 28530 */ canResolveTextDirection()28531 public boolean canResolveTextDirection() { 28532 switch (getRawTextDirection()) { 28533 case TEXT_DIRECTION_INHERIT: 28534 if (mParent != null) { 28535 try { 28536 return mParent.canResolveTextDirection(); 28537 } catch (AbstractMethodError e) { 28538 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28539 " does not fully implement ViewParent", e); 28540 } 28541 } 28542 return false; 28543 28544 default: 28545 return true; 28546 } 28547 } 28548 28549 /** 28550 * Reset resolved text direction. Text direction will be resolved during a call to 28551 * {@link #onMeasure(int, int)}. 28552 * 28553 * @hide 28554 */ 28555 @TestApi resetResolvedTextDirection()28556 public void resetResolvedTextDirection() { 28557 // Reset any previous text direction resolution 28558 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 28559 // Set to default value 28560 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 28561 } 28562 28563 /** 28564 * @return true if text direction is inherited. 28565 * 28566 * @hide 28567 */ isTextDirectionInherited()28568 public boolean isTextDirectionInherited() { 28569 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 28570 } 28571 28572 /** 28573 * @return true if text direction is resolved. 28574 */ isTextDirectionResolved()28575 public boolean isTextDirectionResolved() { 28576 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 28577 } 28578 28579 /** 28580 * Return the value specifying the text alignment or policy that was set with 28581 * {@link #setTextAlignment(int)}. 28582 * 28583 * @return the defined text alignment. It can be one of: 28584 * 28585 * {@link #TEXT_ALIGNMENT_INHERIT}, 28586 * {@link #TEXT_ALIGNMENT_GRAVITY}, 28587 * {@link #TEXT_ALIGNMENT_CENTER}, 28588 * {@link #TEXT_ALIGNMENT_TEXT_START}, 28589 * {@link #TEXT_ALIGNMENT_TEXT_END}, 28590 * {@link #TEXT_ALIGNMENT_VIEW_START}, 28591 * {@link #TEXT_ALIGNMENT_VIEW_END} 28592 * 28593 * @attr ref android.R.styleable#View_textAlignment 28594 * 28595 * @hide 28596 */ 28597 @ViewDebug.ExportedProperty(category = "text", mapping = { 28598 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 28599 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 28600 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 28601 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 28602 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 28603 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 28604 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 28605 }) 28606 @InspectableProperty(hasAttributeId = false, enumMapping = { 28607 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 28608 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 28609 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 28610 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 28611 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 28612 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 28613 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 28614 }) 28615 @TextAlignment 28616 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextAlignment()28617 public int getRawTextAlignment() { 28618 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 28619 } 28620 28621 /** 28622 * Set the text alignment. 28623 * 28624 * @param textAlignment The text alignment to set. Should be one of 28625 * 28626 * {@link #TEXT_ALIGNMENT_INHERIT}, 28627 * {@link #TEXT_ALIGNMENT_GRAVITY}, 28628 * {@link #TEXT_ALIGNMENT_CENTER}, 28629 * {@link #TEXT_ALIGNMENT_TEXT_START}, 28630 * {@link #TEXT_ALIGNMENT_TEXT_END}, 28631 * {@link #TEXT_ALIGNMENT_VIEW_START}, 28632 * {@link #TEXT_ALIGNMENT_VIEW_END} 28633 * 28634 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 28635 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 28636 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 28637 * 28638 * @attr ref android.R.styleable#View_textAlignment 28639 */ setTextAlignment(@extAlignment int textAlignment)28640 public void setTextAlignment(@TextAlignment int textAlignment) { 28641 if (textAlignment != getRawTextAlignment()) { 28642 // Reset the current and resolved text alignment 28643 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 28644 resetResolvedTextAlignment(); 28645 // Set the new text alignment 28646 mPrivateFlags2 |= 28647 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 28648 // Do resolution 28649 resolveTextAlignment(); 28650 // Notify change 28651 onRtlPropertiesChanged(getLayoutDirection()); 28652 // Refresh 28653 requestLayout(); 28654 invalidate(true); 28655 } 28656 } 28657 28658 /** 28659 * Return the resolved text alignment. 28660 * 28661 * @return the resolved text alignment. Returns one of: 28662 * 28663 * {@link #TEXT_ALIGNMENT_GRAVITY}, 28664 * {@link #TEXT_ALIGNMENT_CENTER}, 28665 * {@link #TEXT_ALIGNMENT_TEXT_START}, 28666 * {@link #TEXT_ALIGNMENT_TEXT_END}, 28667 * {@link #TEXT_ALIGNMENT_VIEW_START}, 28668 * {@link #TEXT_ALIGNMENT_VIEW_END} 28669 * 28670 * @attr ref android.R.styleable#View_textAlignment 28671 */ 28672 @ViewDebug.ExportedProperty(category = "text", mapping = { 28673 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 28674 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 28675 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 28676 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 28677 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 28678 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 28679 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 28680 }) 28681 @InspectableProperty(enumMapping = { 28682 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 28683 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 28684 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 28685 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 28686 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 28687 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 28688 }) 28689 @TextAlignment getTextAlignment()28690 public int getTextAlignment() { 28691 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 28692 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 28693 } 28694 28695 /** 28696 * Resolve the text alignment. 28697 * 28698 * @return true if resolution has been done, false otherwise. 28699 * 28700 * @hide 28701 */ resolveTextAlignment()28702 public boolean resolveTextAlignment() { 28703 // Reset any previous text alignment resolution 28704 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 28705 28706 if (hasRtlSupport()) { 28707 // Set resolved text alignment flag depending on text alignment flag 28708 final int textAlignment = getRawTextAlignment(); 28709 switch (textAlignment) { 28710 case TEXT_ALIGNMENT_INHERIT: 28711 // Check if we can resolve the text alignment 28712 if (!canResolveTextAlignment()) { 28713 // We cannot do the resolution if there is no parent so use the default 28714 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28715 // Resolution will need to happen again later 28716 return false; 28717 } 28718 28719 // Parent has not yet resolved, so we still return the default 28720 try { 28721 if (!mParent.isTextAlignmentResolved()) { 28722 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28723 // Resolution will need to happen again later 28724 return false; 28725 } 28726 } catch (AbstractMethodError e) { 28727 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28728 " does not fully implement ViewParent", e); 28729 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 28730 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28731 return true; 28732 } 28733 28734 int parentResolvedTextAlignment; 28735 try { 28736 parentResolvedTextAlignment = mParent.getTextAlignment(); 28737 } catch (AbstractMethodError e) { 28738 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28739 " does not fully implement ViewParent", e); 28740 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 28741 } 28742 switch (parentResolvedTextAlignment) { 28743 case TEXT_ALIGNMENT_GRAVITY: 28744 case TEXT_ALIGNMENT_TEXT_START: 28745 case TEXT_ALIGNMENT_TEXT_END: 28746 case TEXT_ALIGNMENT_CENTER: 28747 case TEXT_ALIGNMENT_VIEW_START: 28748 case TEXT_ALIGNMENT_VIEW_END: 28749 // Resolved text alignment is the same as the parent resolved 28750 // text alignment 28751 mPrivateFlags2 |= 28752 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 28753 break; 28754 default: 28755 // Use default resolved text alignment 28756 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28757 } 28758 break; 28759 case TEXT_ALIGNMENT_GRAVITY: 28760 case TEXT_ALIGNMENT_TEXT_START: 28761 case TEXT_ALIGNMENT_TEXT_END: 28762 case TEXT_ALIGNMENT_CENTER: 28763 case TEXT_ALIGNMENT_VIEW_START: 28764 case TEXT_ALIGNMENT_VIEW_END: 28765 // Resolved text alignment is the same as text alignment 28766 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 28767 break; 28768 default: 28769 // Use default resolved text alignment 28770 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28771 } 28772 } else { 28773 // Use default resolved text alignment 28774 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28775 } 28776 28777 // Set the resolved 28778 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 28779 return true; 28780 } 28781 28782 /** 28783 * Check if text alignment resolution can be done. 28784 * 28785 * @return true if text alignment resolution can be done otherwise return false. 28786 */ canResolveTextAlignment()28787 public boolean canResolveTextAlignment() { 28788 switch (getRawTextAlignment()) { 28789 case TEXT_DIRECTION_INHERIT: 28790 if (mParent != null) { 28791 try { 28792 return mParent.canResolveTextAlignment(); 28793 } catch (AbstractMethodError e) { 28794 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28795 " does not fully implement ViewParent", e); 28796 } 28797 } 28798 return false; 28799 28800 default: 28801 return true; 28802 } 28803 } 28804 28805 /** 28806 * Reset resolved text alignment. Text alignment will be resolved during a call to 28807 * {@link #onMeasure(int, int)}. 28808 * 28809 * @hide 28810 */ 28811 @TestApi resetResolvedTextAlignment()28812 public void resetResolvedTextAlignment() { 28813 // Reset any previous text alignment resolution 28814 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 28815 // Set to default 28816 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28817 } 28818 28819 /** 28820 * @return true if text alignment is inherited. 28821 * 28822 * @hide 28823 */ isTextAlignmentInherited()28824 public boolean isTextAlignmentInherited() { 28825 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 28826 } 28827 28828 /** 28829 * @return true if text alignment is resolved. 28830 */ isTextAlignmentResolved()28831 public boolean isTextAlignmentResolved() { 28832 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 28833 } 28834 28835 /** 28836 * Generate a value suitable for use in {@link #setId(int)}. 28837 * This value will not collide with ID values generated at build time by aapt for R.id. 28838 * 28839 * @return a generated ID value 28840 */ generateViewId()28841 public static int generateViewId() { 28842 for (;;) { 28843 final int result = sNextGeneratedId.get(); 28844 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 28845 int newValue = result + 1; 28846 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 28847 if (sNextGeneratedId.compareAndSet(result, newValue)) { 28848 return result; 28849 } 28850 } 28851 } 28852 isViewIdGenerated(int id)28853 private static boolean isViewIdGenerated(int id) { 28854 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 28855 } 28856 28857 /** 28858 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 28859 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 28860 * a normal View or a ViewGroup with 28861 * {@link android.view.ViewGroup#isTransitionGroup()} true. 28862 * @hide 28863 */ captureTransitioningViews(List<View> transitioningViews)28864 public void captureTransitioningViews(List<View> transitioningViews) { 28865 if (getVisibility() == View.VISIBLE) { 28866 transitioningViews.add(this); 28867 } 28868 } 28869 28870 /** 28871 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 28872 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 28873 * @hide 28874 */ findNamedViews(Map<String, View> namedElements)28875 public void findNamedViews(Map<String, View> namedElements) { 28876 if (getVisibility() == VISIBLE || mGhostView != null) { 28877 String transitionName = getTransitionName(); 28878 if (transitionName != null) { 28879 namedElements.put(transitionName, this); 28880 } 28881 } 28882 } 28883 28884 /** 28885 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 28886 * The default implementation does not care the location or event types, but some subclasses 28887 * may use it (such as WebViews). 28888 * @param event The MotionEvent from a mouse 28889 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 28890 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 28891 * @see PointerIcon 28892 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)28893 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 28894 final float x = event.getX(pointerIndex); 28895 final float y = event.getY(pointerIndex); 28896 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 28897 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 28898 } 28899 return mPointerIcon; 28900 } 28901 28902 /** 28903 * Set the pointer icon for the current view. 28904 * Passing {@code null} will restore the pointer icon to its default value. 28905 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 28906 */ setPointerIcon(PointerIcon pointerIcon)28907 public void setPointerIcon(PointerIcon pointerIcon) { 28908 mPointerIcon = pointerIcon; 28909 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 28910 return; 28911 } 28912 try { 28913 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 28914 } catch (RemoteException e) { 28915 } 28916 } 28917 28918 /** 28919 * Gets the pointer icon for the current view. 28920 */ 28921 @InspectableProperty getPointerIcon()28922 public PointerIcon getPointerIcon() { 28923 return mPointerIcon; 28924 } 28925 28926 /** 28927 * Checks pointer capture status. 28928 * 28929 * @return true if the view has pointer capture. 28930 * @see #requestPointerCapture() 28931 * @see #hasPointerCapture() 28932 */ hasPointerCapture()28933 public boolean hasPointerCapture() { 28934 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28935 if (viewRootImpl == null) { 28936 return false; 28937 } 28938 return viewRootImpl.hasPointerCapture(); 28939 } 28940 28941 /** 28942 * Requests pointer capture mode. 28943 * <p> 28944 * When the window has pointer capture, the mouse pointer icon will disappear and will not 28945 * change its position. Enabling pointer capture will change the behavior of input devices in 28946 * the following ways: 28947 * <ul> 28948 * <li>Events from a mouse will be delivered with the source 28949 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be 28950 * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li> 28951 * 28952 * <li>Events from a touchpad or trackpad will be delivered with the source 28953 * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers 28954 * on the touchpad will be available through {@link MotionEvent#getX(int)} and 28955 * {@link MotionEvent#getY(int)}, and their relative movements are stored in 28956 * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li> 28957 * 28958 * <li>Events from other types of devices, such as touchscreens, will not be affected.</li> 28959 * </ul> 28960 * <p> 28961 * When pointer capture changes, connected mouse and trackpad devices may be reconfigured, 28962 * and their properties (such as their sources or motion ranges) may change. Use an 28963 * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device 28964 * changes (which may happen after enabling or disabling pointer capture), and use 28965 * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}. 28966 * <p> 28967 * Events captured through pointer capture will be dispatched to 28968 * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an 28969 * {@link OnCapturedPointerListener} is set, and otherwise to 28970 * {@link #onCapturedPointerEvent(MotionEvent)}. 28971 * <p> 28972 * If the window already has pointer capture, this call does nothing. 28973 * <p> 28974 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 28975 * automatically when the window loses focus. 28976 * 28977 * @see #releasePointerCapture() 28978 * @see #hasPointerCapture() 28979 * @see #onPointerCaptureChange(boolean) 28980 */ requestPointerCapture()28981 public void requestPointerCapture() { 28982 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28983 if (viewRootImpl != null) { 28984 viewRootImpl.requestPointerCapture(true); 28985 } 28986 } 28987 28988 28989 /** 28990 * Releases the pointer capture. 28991 * <p> 28992 * If the window does not have pointer capture, this call will do nothing. 28993 * @see #requestPointerCapture() 28994 * @see #hasPointerCapture() 28995 * @see #onPointerCaptureChange(boolean) 28996 */ releasePointerCapture()28997 public void releasePointerCapture() { 28998 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28999 if (viewRootImpl != null) { 29000 viewRootImpl.requestPointerCapture(false); 29001 } 29002 } 29003 29004 /** 29005 * Called when the window has just acquired or lost pointer capture. 29006 * 29007 * @param hasCapture True if the view now has pointerCapture, false otherwise. 29008 */ 29009 @CallSuper onPointerCaptureChange(boolean hasCapture)29010 public void onPointerCaptureChange(boolean hasCapture) { 29011 } 29012 29013 /** 29014 * @see #onPointerCaptureChange 29015 */ dispatchPointerCaptureChanged(boolean hasCapture)29016 public void dispatchPointerCaptureChanged(boolean hasCapture) { 29017 onPointerCaptureChange(hasCapture); 29018 } 29019 29020 /** 29021 * Implement this method to handle captured pointer events 29022 * 29023 * @param event The captured pointer event. 29024 * @return True if the event was handled, false otherwise. 29025 * @see #requestPointerCapture() 29026 */ onCapturedPointerEvent(MotionEvent event)29027 public boolean onCapturedPointerEvent(MotionEvent event) { 29028 return false; 29029 } 29030 29031 /** 29032 * Interface definition for a callback to be invoked when a captured pointer event 29033 * is being dispatched this view. The callback will be invoked before the event is 29034 * given to the view. 29035 */ 29036 public interface OnCapturedPointerListener { 29037 /** 29038 * Called when a captured pointer event is dispatched to a view. 29039 * @param view The view this event has been dispatched to. 29040 * @param event The captured event. 29041 * @return True if the listener has consumed the event, false otherwise. 29042 */ onCapturedPointer(View view, MotionEvent event)29043 boolean onCapturedPointer(View view, MotionEvent event); 29044 } 29045 29046 /** 29047 * Set a listener to receive callbacks when the pointer capture state of a view changes. 29048 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 29049 */ setOnCapturedPointerListener(OnCapturedPointerListener l)29050 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 29051 getListenerInfo().mOnCapturedPointerListener = l; 29052 } 29053 29054 // Properties 29055 // 29056 /** 29057 * A Property wrapper around the <code>alpha</code> functionality handled by the 29058 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 29059 */ 29060 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 29061 @Override 29062 public void setValue(View object, float value) { 29063 object.setAlpha(value); 29064 } 29065 29066 @Override 29067 public Float get(View object) { 29068 return object.getAlpha(); 29069 } 29070 }; 29071 29072 /** 29073 * A Property wrapper around the <code>translationX</code> functionality handled by the 29074 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 29075 */ 29076 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 29077 @Override 29078 public void setValue(View object, float value) { 29079 object.setTranslationX(value); 29080 } 29081 29082 @Override 29083 public Float get(View object) { 29084 return object.getTranslationX(); 29085 } 29086 }; 29087 29088 /** 29089 * A Property wrapper around the <code>translationY</code> functionality handled by the 29090 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 29091 */ 29092 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 29093 @Override 29094 public void setValue(View object, float value) { 29095 object.setTranslationY(value); 29096 } 29097 29098 @Override 29099 public Float get(View object) { 29100 return object.getTranslationY(); 29101 } 29102 }; 29103 29104 /** 29105 * A Property wrapper around the <code>translationZ</code> functionality handled by the 29106 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 29107 */ 29108 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 29109 @Override 29110 public void setValue(View object, float value) { 29111 object.setTranslationZ(value); 29112 } 29113 29114 @Override 29115 public Float get(View object) { 29116 return object.getTranslationZ(); 29117 } 29118 }; 29119 29120 /** 29121 * A Property wrapper around the <code>x</code> functionality handled by the 29122 * {@link View#setX(float)} and {@link View#getX()} methods. 29123 */ 29124 public static final Property<View, Float> X = new FloatProperty<View>("x") { 29125 @Override 29126 public void setValue(View object, float value) { 29127 object.setX(value); 29128 } 29129 29130 @Override 29131 public Float get(View object) { 29132 return object.getX(); 29133 } 29134 }; 29135 29136 /** 29137 * A Property wrapper around the <code>y</code> functionality handled by the 29138 * {@link View#setY(float)} and {@link View#getY()} methods. 29139 */ 29140 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 29141 @Override 29142 public void setValue(View object, float value) { 29143 object.setY(value); 29144 } 29145 29146 @Override 29147 public Float get(View object) { 29148 return object.getY(); 29149 } 29150 }; 29151 29152 /** 29153 * A Property wrapper around the <code>z</code> functionality handled by the 29154 * {@link View#setZ(float)} and {@link View#getZ()} methods. 29155 */ 29156 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 29157 @Override 29158 public void setValue(View object, float value) { 29159 object.setZ(value); 29160 } 29161 29162 @Override 29163 public Float get(View object) { 29164 return object.getZ(); 29165 } 29166 }; 29167 29168 /** 29169 * A Property wrapper around the <code>rotation</code> functionality handled by the 29170 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 29171 */ 29172 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 29173 @Override 29174 public void setValue(View object, float value) { 29175 object.setRotation(value); 29176 } 29177 29178 @Override 29179 public Float get(View object) { 29180 return object.getRotation(); 29181 } 29182 }; 29183 29184 /** 29185 * A Property wrapper around the <code>rotationX</code> functionality handled by the 29186 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 29187 */ 29188 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 29189 @Override 29190 public void setValue(View object, float value) { 29191 object.setRotationX(value); 29192 } 29193 29194 @Override 29195 public Float get(View object) { 29196 return object.getRotationX(); 29197 } 29198 }; 29199 29200 /** 29201 * A Property wrapper around the <code>rotationY</code> functionality handled by the 29202 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 29203 */ 29204 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 29205 @Override 29206 public void setValue(View object, float value) { 29207 object.setRotationY(value); 29208 } 29209 29210 @Override 29211 public Float get(View object) { 29212 return object.getRotationY(); 29213 } 29214 }; 29215 29216 /** 29217 * A Property wrapper around the <code>scaleX</code> functionality handled by the 29218 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 29219 */ 29220 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 29221 @Override 29222 public void setValue(View object, float value) { 29223 object.setScaleX(value); 29224 } 29225 29226 @Override 29227 public Float get(View object) { 29228 return object.getScaleX(); 29229 } 29230 }; 29231 29232 /** 29233 * A Property wrapper around the <code>scaleY</code> functionality handled by the 29234 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 29235 */ 29236 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 29237 @Override 29238 public void setValue(View object, float value) { 29239 object.setScaleY(value); 29240 } 29241 29242 @Override 29243 public Float get(View object) { 29244 return object.getScaleY(); 29245 } 29246 }; 29247 29248 /** 29249 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 29250 * Each MeasureSpec represents a requirement for either the width or the height. 29251 * A MeasureSpec is comprised of a size and a mode. There are three possible 29252 * modes: 29253 * <dl> 29254 * <dt>UNSPECIFIED</dt> 29255 * <dd> 29256 * The parent has not imposed any constraint on the child. It can be whatever size 29257 * it wants. 29258 * </dd> 29259 * 29260 * <dt>EXACTLY</dt> 29261 * <dd> 29262 * The parent has determined an exact size for the child. The child is going to be 29263 * given those bounds regardless of how big it wants to be. 29264 * </dd> 29265 * 29266 * <dt>AT_MOST</dt> 29267 * <dd> 29268 * The child can be as large as it wants up to the specified size. 29269 * </dd> 29270 * </dl> 29271 * 29272 * MeasureSpecs are implemented as ints to reduce object allocation. This class 29273 * is provided to pack and unpack the <size, mode> tuple into the int. 29274 */ 29275 public static class MeasureSpec { 29276 private static final int MODE_SHIFT = 30; 29277 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 29278 29279 /** @hide */ 29280 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 29281 @Retention(RetentionPolicy.SOURCE) 29282 public @interface MeasureSpecMode {} 29283 29284 /** 29285 * Measure specification mode: The parent has not imposed any constraint 29286 * on the child. It can be whatever size it wants. 29287 */ 29288 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 29289 29290 /** 29291 * Measure specification mode: The parent has determined an exact size 29292 * for the child. The child is going to be given those bounds regardless 29293 * of how big it wants to be. 29294 */ 29295 public static final int EXACTLY = 1 << MODE_SHIFT; 29296 29297 /** 29298 * Measure specification mode: The child can be as large as it wants up 29299 * to the specified size. 29300 */ 29301 public static final int AT_MOST = 2 << MODE_SHIFT; 29302 29303 /** 29304 * Creates a measure specification based on the supplied size and mode. 29305 * 29306 * The mode must always be one of the following: 29307 * <ul> 29308 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 29309 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 29310 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 29311 * </ul> 29312 * 29313 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 29314 * implementation was such that the order of arguments did not matter 29315 * and overflow in either value could impact the resulting MeasureSpec. 29316 * {@link android.widget.RelativeLayout} was affected by this bug. 29317 * Apps targeting API levels greater than 17 will get the fixed, more strict 29318 * behavior.</p> 29319 * 29320 * @param size the size of the measure specification 29321 * @param mode the mode of the measure specification 29322 * @return the measure specification based on size and mode 29323 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)29324 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 29325 @MeasureSpecMode int mode) { 29326 if (sUseBrokenMakeMeasureSpec) { 29327 return size + mode; 29328 } else { 29329 return (size & ~MODE_MASK) | (mode & MODE_MASK); 29330 } 29331 } 29332 29333 /** 29334 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 29335 * will automatically get a size of 0. Older apps expect this. 29336 * 29337 * @hide internal use only for compatibility with system widgets and older apps 29338 */ 29339 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)29340 public static int makeSafeMeasureSpec(int size, int mode) { 29341 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 29342 return 0; 29343 } 29344 return makeMeasureSpec(size, mode); 29345 } 29346 29347 /** 29348 * Extracts the mode from the supplied measure specification. 29349 * 29350 * @param measureSpec the measure specification to extract the mode from 29351 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 29352 * {@link android.view.View.MeasureSpec#AT_MOST} or 29353 * {@link android.view.View.MeasureSpec#EXACTLY} 29354 */ 29355 @MeasureSpecMode getMode(int measureSpec)29356 public static int getMode(int measureSpec) { 29357 //noinspection ResourceType 29358 return (measureSpec & MODE_MASK); 29359 } 29360 29361 /** 29362 * Extracts the size from the supplied measure specification. 29363 * 29364 * @param measureSpec the measure specification to extract the size from 29365 * @return the size in pixels defined in the supplied measure specification 29366 */ getSize(int measureSpec)29367 public static int getSize(int measureSpec) { 29368 return (measureSpec & ~MODE_MASK); 29369 } 29370 adjust(int measureSpec, int delta)29371 static int adjust(int measureSpec, int delta) { 29372 final int mode = getMode(measureSpec); 29373 int size = getSize(measureSpec); 29374 if (mode == UNSPECIFIED) { 29375 // No need to adjust size for UNSPECIFIED mode. 29376 return makeMeasureSpec(size, UNSPECIFIED); 29377 } 29378 size += delta; 29379 if (size < 0) { 29380 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 29381 ") spec: " + toString(measureSpec) + " delta: " + delta); 29382 size = 0; 29383 } 29384 return makeMeasureSpec(size, mode); 29385 } 29386 29387 /** 29388 * Returns a String representation of the specified measure 29389 * specification. 29390 * 29391 * @param measureSpec the measure specification to convert to a String 29392 * @return a String with the following format: "MeasureSpec: MODE SIZE" 29393 */ toString(int measureSpec)29394 public static String toString(int measureSpec) { 29395 int mode = getMode(measureSpec); 29396 int size = getSize(measureSpec); 29397 29398 StringBuilder sb = new StringBuilder("MeasureSpec: "); 29399 29400 if (mode == UNSPECIFIED) 29401 sb.append("UNSPECIFIED "); 29402 else if (mode == EXACTLY) 29403 sb.append("EXACTLY "); 29404 else if (mode == AT_MOST) 29405 sb.append("AT_MOST "); 29406 else 29407 sb.append(mode).append(" "); 29408 29409 sb.append(size); 29410 return sb.toString(); 29411 } 29412 } 29413 29414 private final class CheckForLongPress implements Runnable { 29415 private int mOriginalWindowAttachCount; 29416 private float mX; 29417 private float mY; 29418 private boolean mOriginalPressedState; 29419 /** 29420 * The classification of the long click being checked: one of the 29421 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 29422 */ 29423 private int mClassification; 29424 29425 @UnsupportedAppUsage CheckForLongPress()29426 private CheckForLongPress() { 29427 } 29428 29429 @Override run()29430 public void run() { 29431 if ((mOriginalPressedState == isPressed()) && (mParent != null) 29432 && mOriginalWindowAttachCount == mWindowAttachCount) { 29433 recordGestureClassification(mClassification); 29434 if (performLongClick(mX, mY)) { 29435 mHasPerformedLongPress = true; 29436 } 29437 } 29438 } 29439 setAnchor(float x, float y)29440 public void setAnchor(float x, float y) { 29441 mX = x; 29442 mY = y; 29443 } 29444 rememberWindowAttachCount()29445 public void rememberWindowAttachCount() { 29446 mOriginalWindowAttachCount = mWindowAttachCount; 29447 } 29448 rememberPressedState()29449 public void rememberPressedState() { 29450 mOriginalPressedState = isPressed(); 29451 } 29452 setClassification(int classification)29453 public void setClassification(int classification) { 29454 mClassification = classification; 29455 } 29456 } 29457 29458 private final class CheckForTap implements Runnable { 29459 public float x; 29460 public float y; 29461 29462 @Override run()29463 public void run() { 29464 mPrivateFlags &= ~PFLAG_PREPRESSED; 29465 setPressed(true, x, y); 29466 final long delay = 29467 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 29468 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 29469 } 29470 } 29471 29472 private final class PerformClick implements Runnable { 29473 @Override run()29474 public void run() { 29475 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 29476 performClickInternal(); 29477 } 29478 } 29479 29480 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)29481 private void recordGestureClassification(int classification) { 29482 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 29483 return; 29484 } 29485 // To avoid negatively impacting View performance, the latency and displacement metrics 29486 // are omitted. 29487 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 29488 classification); 29489 } 29490 29491 /** 29492 * This method returns a ViewPropertyAnimator object, which can be used to animate 29493 * specific properties on this View. 29494 * 29495 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 29496 */ animate()29497 public ViewPropertyAnimator animate() { 29498 if (mAnimator == null) { 29499 mAnimator = new ViewPropertyAnimator(this); 29500 } 29501 return mAnimator; 29502 } 29503 29504 /** 29505 * Sets the name of the View to be used to identify Views in Transitions. 29506 * Names should be unique in the View hierarchy. 29507 * 29508 * @param transitionName The name of the View to uniquely identify it for Transitions. 29509 */ setTransitionName(String transitionName)29510 public final void setTransitionName(String transitionName) { 29511 mTransitionName = transitionName; 29512 } 29513 29514 /** 29515 * Returns the name of the View to be used to identify Views in Transitions. 29516 * Names should be unique in the View hierarchy. 29517 * 29518 * <p>This returns null if the View has not been given a name.</p> 29519 * 29520 * @return The name used of the View to be used to identify Views in Transitions or null 29521 * if no name has been given. 29522 */ 29523 @ViewDebug.ExportedProperty 29524 @InspectableProperty getTransitionName()29525 public String getTransitionName() { 29526 return mTransitionName; 29527 } 29528 29529 /** 29530 * @hide 29531 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)29532 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 29533 // Do nothing. 29534 } 29535 29536 /** 29537 * Interface definition for a callback to be invoked when a hardware key event is 29538 * dispatched to this view. The callback will be invoked before the key event is 29539 * given to the view. This is only useful for hardware keyboards; a software input 29540 * method has no obligation to trigger this listener. 29541 */ 29542 public interface OnKeyListener { 29543 /** 29544 * Called when a hardware key is dispatched to a view. This allows listeners to 29545 * get a chance to respond before the target view. 29546 * <p>Key presses in software keyboards will generally NOT trigger this method, 29547 * although some may elect to do so in some situations. Do not assume a 29548 * software input method has to be key-based; even if it is, it may use key presses 29549 * in a different way than you expect, so there is no way to reliably catch soft 29550 * input key presses. 29551 * 29552 * @param v The view the key has been dispatched to. 29553 * @param keyCode The code for the physical key that was pressed 29554 * @param event The KeyEvent object containing full information about 29555 * the event. 29556 * @return True if the listener has consumed the event, false otherwise. 29557 */ onKey(View v, int keyCode, KeyEvent event)29558 boolean onKey(View v, int keyCode, KeyEvent event); 29559 } 29560 29561 /** 29562 * Interface definition for a callback to be invoked when a hardware key event hasn't 29563 * been handled by the view hierarchy. 29564 */ 29565 public interface OnUnhandledKeyEventListener { 29566 /** 29567 * Called when a hardware key is dispatched to a view after being unhandled during normal 29568 * {@link KeyEvent} dispatch. 29569 * 29570 * @param v The view the key has been dispatched to. 29571 * @param event The KeyEvent object containing information about the event. 29572 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 29573 */ onUnhandledKeyEvent(View v, KeyEvent event)29574 boolean onUnhandledKeyEvent(View v, KeyEvent event); 29575 } 29576 29577 /** 29578 * Interface definition for a callback to be invoked when a touch event is 29579 * dispatched to this view. The callback will be invoked before the touch 29580 * event is given to the view. 29581 */ 29582 public interface OnTouchListener { 29583 /** 29584 * Called when a touch event is dispatched to a view. This allows listeners to 29585 * get a chance to respond before the target view. 29586 * 29587 * @param v The view the touch event has been dispatched to. 29588 * @param event The MotionEvent object containing full information about 29589 * the event. 29590 * @return True if the listener has consumed the event, false otherwise. 29591 */ onTouch(View v, MotionEvent event)29592 boolean onTouch(View v, MotionEvent event); 29593 } 29594 29595 /** 29596 * Interface definition for a callback to be invoked when a hover event is 29597 * dispatched to this view. The callback will be invoked before the hover 29598 * event is given to the view. 29599 */ 29600 public interface OnHoverListener { 29601 /** 29602 * Called when a hover event is dispatched to a view. This allows listeners to 29603 * get a chance to respond before the target view. 29604 * 29605 * @param v The view the hover event has been dispatched to. 29606 * @param event The MotionEvent object containing full information about 29607 * the event. 29608 * @return True if the listener has consumed the event, false otherwise. 29609 */ onHover(View v, MotionEvent event)29610 boolean onHover(View v, MotionEvent event); 29611 } 29612 29613 /** 29614 * Interface definition for a callback to be invoked when a generic motion event is 29615 * dispatched to this view. The callback will be invoked before the generic motion 29616 * event is given to the view. 29617 */ 29618 public interface OnGenericMotionListener { 29619 /** 29620 * Called when a generic motion event is dispatched to a view. This allows listeners to 29621 * get a chance to respond before the target view. 29622 * 29623 * @param v The view the generic motion event has been dispatched to. 29624 * @param event The MotionEvent object containing full information about 29625 * the event. 29626 * @return True if the listener has consumed the event, false otherwise. 29627 */ onGenericMotion(View v, MotionEvent event)29628 boolean onGenericMotion(View v, MotionEvent event); 29629 } 29630 29631 /** 29632 * Interface definition for a callback to be invoked when a view has been clicked and held. 29633 */ 29634 public interface OnLongClickListener { 29635 /** 29636 * Called when a view has been clicked and held. 29637 * 29638 * @param v The view that was clicked and held. 29639 * 29640 * @return true if the callback consumed the long click, false otherwise. 29641 */ onLongClick(View v)29642 boolean onLongClick(View v); 29643 } 29644 29645 /** 29646 * Interface definition for a listener that's invoked when a drag event is dispatched to this 29647 * view. The listener is invoked before the view's own 29648 * {@link #onDragEvent(DragEvent)} method. To fall back to the view's 29649 * {@code onDragEvent(DragEvent)} behavior, return {@code false} from the listener method. 29650 * 29651 * <div class="special reference"> 29652 * <h3>Developer Guides</h3> 29653 * <p>For a guide to implementing drag and drop features, see the 29654 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and drop</a> developer guide.</p> 29655 * </div> 29656 */ 29657 public interface OnDragListener { 29658 /** 29659 * Called when a drag event is dispatched to a view. Enables listeners to override the 29660 * base behavior provided by {@link #onDragEvent(DragEvent)}. 29661 * 29662 * @param v The {@code View} that received the drag event. 29663 * @param event The event object for the drag event. 29664 * @return {@code true} if the drag event was handled successfully; {@code false}, if the 29665 * drag event was not handled. <b>Note:</b> A {@code false} return value triggers the 29666 * view's {@link #onDragEvent(DragEvent)} handler. 29667 */ onDrag(View v, DragEvent event)29668 boolean onDrag(View v, DragEvent event); 29669 } 29670 29671 /** 29672 * Interface definition for a callback to be invoked when the focus state of 29673 * a view changed. 29674 */ 29675 public interface OnFocusChangeListener { 29676 /** 29677 * Called when the focus state of a view has changed. 29678 * 29679 * @param v The view whose state has changed. 29680 * @param hasFocus The new focus state of v. 29681 */ onFocusChange(View v, boolean hasFocus)29682 void onFocusChange(View v, boolean hasFocus); 29683 } 29684 29685 /** 29686 * Interface definition for a callback to be invoked when a view is clicked. 29687 */ 29688 public interface OnClickListener { 29689 /** 29690 * Called when a view has been clicked. 29691 * 29692 * @param v The view that was clicked. 29693 */ onClick(View v)29694 void onClick(View v); 29695 } 29696 29697 /** 29698 * Interface definition for a callback to be invoked when a view is context clicked. 29699 */ 29700 public interface OnContextClickListener { 29701 /** 29702 * Called when a view is context clicked. 29703 * 29704 * @param v The view that has been context clicked. 29705 * @return true if the callback consumed the context click, false otherwise. 29706 */ onContextClick(View v)29707 boolean onContextClick(View v); 29708 } 29709 29710 /** 29711 * Interface definition for a callback to be invoked when the context menu 29712 * for this view is being built. 29713 */ 29714 public interface OnCreateContextMenuListener { 29715 /** 29716 * Called when the context menu for this view is being built. It is not 29717 * safe to hold onto the menu after this method returns. 29718 * 29719 * @param menu The context menu that is being built 29720 * @param v The view for which the context menu is being built 29721 * @param menuInfo Extra information about the item for which the 29722 * context menu should be shown. This information will vary 29723 * depending on the class of v. 29724 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)29725 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 29726 } 29727 29728 /** 29729 * Interface definition for a callback to be invoked when the status bar changes 29730 * visibility. This reports <strong>global</strong> changes to the system UI 29731 * state, not what the application is requesting. 29732 * 29733 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 29734 * 29735 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 29736 * by setting a {@link OnApplyWindowInsetsListener} on this view. 29737 */ 29738 @Deprecated 29739 public interface OnSystemUiVisibilityChangeListener { 29740 /** 29741 * Called when the status bar changes visibility because of a call to 29742 * {@link View#setSystemUiVisibility(int)}. 29743 * 29744 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 29745 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 29746 * This tells you the <strong>global</strong> state of these UI visibility 29747 * flags, not what your app is currently applying. 29748 */ onSystemUiVisibilityChange(int visibility)29749 public void onSystemUiVisibilityChange(int visibility); 29750 } 29751 29752 /** 29753 * Interface definition for a callback to be invoked when this view is attached 29754 * or detached from its window. 29755 */ 29756 public interface OnAttachStateChangeListener { 29757 /** 29758 * Called when the view is attached to a window. 29759 * @param v The view that was attached 29760 */ onViewAttachedToWindow(@onNull View v)29761 public void onViewAttachedToWindow(@NonNull View v); 29762 /** 29763 * Called when the view is detached from a window. 29764 * @param v The view that was detached 29765 */ onViewDetachedFromWindow(@onNull View v)29766 public void onViewDetachedFromWindow(@NonNull View v); 29767 } 29768 29769 /** 29770 * Listener for applying window insets on a view in a custom way. 29771 * 29772 * <p>Apps may choose to implement this interface if they want to apply custom policy 29773 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 29774 * is set, its 29775 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 29776 * method will be called instead of the View's own 29777 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 29778 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 29779 * the View's normal behavior as part of its own.</p> 29780 */ 29781 public interface OnApplyWindowInsetsListener { 29782 /** 29783 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 29784 * on a View, this listener method will be called instead of the view's own 29785 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 29786 * 29787 * @param v The view applying window insets 29788 * @param insets The insets to apply 29789 * @return The insets supplied, minus any insets that were consumed 29790 */ onApplyWindowInsets(@onNull View v, @NonNull WindowInsets insets)29791 public @NonNull WindowInsets onApplyWindowInsets(@NonNull View v, 29792 @NonNull WindowInsets insets); 29793 } 29794 29795 private final class UnsetPressedState implements Runnable { 29796 @Override run()29797 public void run() { 29798 setPressed(false); 29799 } 29800 } 29801 29802 /** 29803 * When a view becomes invisible checks if autofill considers the view invisible too. This 29804 * happens after the regular removal operation to make sure the operation is finished by the 29805 * time this is called. 29806 */ 29807 private static class VisibilityChangeForAutofillHandler extends Handler { 29808 private final AutofillManager mAfm; 29809 private final View mView; 29810 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)29811 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 29812 @NonNull View view) { 29813 mAfm = afm; 29814 mView = view; 29815 } 29816 29817 @Override handleMessage(Message msg)29818 public void handleMessage(Message msg) { 29819 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 29820 } 29821 } 29822 29823 /** 29824 * Base class for derived classes that want to save and restore their own 29825 * state in {@link android.view.View#onSaveInstanceState()}. 29826 */ 29827 public static class BaseSavedState extends AbsSavedState { 29828 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 29829 static final int IS_AUTOFILLED = 0b10; 29830 static final int AUTOFILL_ID = 0b100; 29831 29832 // Flags that describe what data in this state is valid 29833 int mSavedData; 29834 String mStartActivityRequestWhoSaved; 29835 boolean mIsAutofilled; 29836 boolean mHideHighlight; 29837 int mAutofillViewId; 29838 29839 /** 29840 * Constructor used when reading from a parcel. Reads the state of the superclass. 29841 * 29842 * @param source parcel to read from 29843 */ BaseSavedState(Parcel source)29844 public BaseSavedState(Parcel source) { 29845 this(source, null); 29846 } 29847 29848 /** 29849 * Constructor used when reading from a parcel using a given class loader. 29850 * Reads the state of the superclass. 29851 * 29852 * @param source parcel to read from 29853 * @param loader ClassLoader to use for reading 29854 */ BaseSavedState(Parcel source, ClassLoader loader)29855 public BaseSavedState(Parcel source, ClassLoader loader) { 29856 super(source, loader); 29857 mSavedData = source.readInt(); 29858 mStartActivityRequestWhoSaved = source.readString(); 29859 mIsAutofilled = source.readBoolean(); 29860 mHideHighlight = source.readBoolean(); 29861 mAutofillViewId = source.readInt(); 29862 } 29863 29864 /** 29865 * Constructor called by derived classes when creating their SavedState objects 29866 * 29867 * @param superState The state of the superclass of this view 29868 */ BaseSavedState(Parcelable superState)29869 public BaseSavedState(Parcelable superState) { 29870 super(superState); 29871 } 29872 29873 @Override writeToParcel(Parcel out, int flags)29874 public void writeToParcel(Parcel out, int flags) { 29875 super.writeToParcel(out, flags); 29876 29877 out.writeInt(mSavedData); 29878 out.writeString(mStartActivityRequestWhoSaved); 29879 out.writeBoolean(mIsAutofilled); 29880 out.writeBoolean(mHideHighlight); 29881 out.writeInt(mAutofillViewId); 29882 } 29883 29884 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 29885 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 29886 @Override 29887 public BaseSavedState createFromParcel(Parcel in) { 29888 return new BaseSavedState(in); 29889 } 29890 29891 @Override 29892 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 29893 return new BaseSavedState(in, loader); 29894 } 29895 29896 @Override 29897 public BaseSavedState[] newArray(int size) { 29898 return new BaseSavedState[size]; 29899 } 29900 }; 29901 } 29902 29903 /** 29904 * A set of information given to a view when it is attached to its parent 29905 * window. 29906 */ 29907 final static class AttachInfo { 29908 29909 interface Callbacks { playSoundEffect(int effectId)29910 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)29911 boolean performHapticFeedback(int effectId, boolean always); 29912 } 29913 29914 /** 29915 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 29916 * to a Handler. This class contains the target (View) to invalidate and 29917 * the coordinates of the dirty rectangle. 29918 * 29919 * For performance purposes, this class also implements a pool of up to 29920 * POOL_LIMIT objects that get reused. This reduces memory allocations 29921 * whenever possible. 29922 */ 29923 static class InvalidateInfo { 29924 29925 @UnsupportedAppUsage InvalidateInfo()29926 InvalidateInfo() { 29927 } 29928 29929 private static final int POOL_LIMIT = 10; 29930 29931 private static final SynchronizedPool<InvalidateInfo> sPool = 29932 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 29933 29934 @UnsupportedAppUsage 29935 View target; 29936 29937 @UnsupportedAppUsage 29938 int left; 29939 @UnsupportedAppUsage 29940 int top; 29941 @UnsupportedAppUsage 29942 int right; 29943 @UnsupportedAppUsage 29944 int bottom; 29945 obtain()29946 public static InvalidateInfo obtain() { 29947 InvalidateInfo instance = sPool.acquire(); 29948 return (instance != null) ? instance : new InvalidateInfo(); 29949 } 29950 recycle()29951 public void recycle() { 29952 target = null; 29953 sPool.release(this); 29954 } 29955 } 29956 29957 @UnsupportedAppUsage 29958 final IWindowSession mSession; 29959 29960 @UnsupportedAppUsage 29961 final IWindow mWindow; 29962 29963 final IBinder mWindowToken; 29964 29965 Display mDisplay; 29966 29967 final Callbacks mRootCallbacks; 29968 29969 IWindowId mIWindowId; 29970 WindowId mWindowId; 29971 29972 /** 29973 * The top view of the hierarchy. 29974 */ 29975 View mRootView; 29976 29977 IBinder mPanelParentWindowToken; 29978 29979 boolean mHardwareAccelerated; 29980 boolean mHardwareAccelerationRequested; 29981 ThreadedRenderer mThreadedRenderer; 29982 List<RenderNode> mPendingAnimatingRenderNodes; 29983 29984 /** 29985 * The state of the display to which the window is attached, as reported 29986 * by {@link Display#getState()}. Note that the display state constants 29987 * declared by {@link Display} do not exactly line up with the screen state 29988 * constants declared by {@link View} (there are more display states than 29989 * screen states). 29990 */ 29991 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29992 int mDisplayState = Display.STATE_UNKNOWN; 29993 29994 /** 29995 * Scale factor used by the compatibility mode 29996 */ 29997 @UnsupportedAppUsage 29998 float mApplicationScale; 29999 30000 /** 30001 * Indicates whether the application is in compatibility mode 30002 */ 30003 @UnsupportedAppUsage 30004 boolean mScalingRequired; 30005 30006 /** 30007 * Left position of this view's window 30008 */ 30009 int mWindowLeft; 30010 30011 /** 30012 * Top position of this view's window 30013 */ 30014 int mWindowTop; 30015 30016 /** 30017 * Indicates whether views need to use 32-bit drawing caches 30018 */ 30019 boolean mUse32BitDrawingCache; 30020 30021 /** 30022 * For windows that are full-screen but using insets to layout inside 30023 * of the screen decorations, these are the current insets for the 30024 * content of the window. 30025 */ 30026 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 30027 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 30028 final Rect mContentInsets = new Rect(); 30029 30030 /** 30031 * For windows that are full-screen but using insets to layout inside 30032 * of the screen decorations, these are the current insets for the 30033 * actual visible parts of the window. 30034 */ 30035 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 30036 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 30037 final Rect mVisibleInsets = new Rect(); 30038 30039 /** 30040 * For windows that are full-screen but using insets to layout inside 30041 * of the screen decorations, these are the current insets for the 30042 * stable system windows. 30043 */ 30044 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 30045 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 30046 final Rect mStableInsets = new Rect(); 30047 30048 /** 30049 * Current caption insets to the display coordinate. 30050 */ 30051 final Rect mCaptionInsets = new Rect(); 30052 30053 /** 30054 * In multi-window we force show the system bars. Because we don't want that the surface 30055 * size changes in this mode, we instead have a flag whether the system bars sizes should 30056 * always be consumed, so the app is treated like there are no virtual system bars at all. 30057 */ 30058 boolean mAlwaysConsumeSystemBars; 30059 30060 /** 30061 * The internal insets given by this window. This value is 30062 * supplied by the client (through 30063 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 30064 * be given to the window manager when changed to be used in laying 30065 * out windows behind it. 30066 */ 30067 @UnsupportedAppUsage 30068 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 30069 = new ViewTreeObserver.InternalInsetsInfo(); 30070 30071 /** 30072 * Set to true when mGivenInternalInsets is non-empty. 30073 */ 30074 boolean mHasNonEmptyGivenInternalInsets; 30075 30076 /** 30077 * All views in the window's hierarchy that serve as scroll containers, 30078 * used to determine if the window can be resized or must be panned 30079 * to adjust for a soft input area. 30080 */ 30081 @UnsupportedAppUsage 30082 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 30083 30084 @UnsupportedAppUsage 30085 final KeyEvent.DispatcherState mKeyDispatchState 30086 = new KeyEvent.DispatcherState(); 30087 30088 /** 30089 * Indicates whether the view's window currently has the focus. 30090 */ 30091 @UnsupportedAppUsage 30092 boolean mHasWindowFocus; 30093 30094 /** 30095 * The current visibility of the window. 30096 */ 30097 int mWindowVisibility; 30098 30099 /** 30100 * Indicates the time at which drawing started to occur. 30101 */ 30102 @UnsupportedAppUsage 30103 long mDrawingTime; 30104 30105 /** 30106 * Indicates whether the view's window is currently in touch mode. 30107 */ 30108 @UnsupportedAppUsage 30109 boolean mInTouchMode; 30110 30111 /** 30112 * Indicates whether the view has requested unbuffered input dispatching for the current 30113 * event stream. 30114 */ 30115 boolean mUnbufferedDispatchRequested; 30116 30117 /** 30118 * Indicates that ViewAncestor should trigger a global layout change 30119 * the next time it performs a traversal 30120 */ 30121 @UnsupportedAppUsage 30122 boolean mRecomputeGlobalAttributes; 30123 30124 /** 30125 * Always report new attributes at next traversal. 30126 */ 30127 boolean mForceReportNewAttributes; 30128 30129 /** 30130 * Set during a traveral if any views want to keep the screen on. 30131 */ 30132 @UnsupportedAppUsage 30133 boolean mKeepScreenOn; 30134 30135 /** 30136 * Set during a traveral if the light center needs to be updated. 30137 */ 30138 boolean mNeedsUpdateLightCenter; 30139 30140 /** 30141 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 30142 */ 30143 int mSystemUiVisibility; 30144 30145 /** 30146 * Hack to force certain system UI visibility flags to be cleared. 30147 */ 30148 int mDisabledSystemUiVisibility; 30149 30150 /** 30151 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 30152 * attached. 30153 */ 30154 boolean mHasSystemUiListeners; 30155 30156 /** 30157 * Set if the visibility of any views has changed. 30158 */ 30159 @UnsupportedAppUsage 30160 boolean mViewVisibilityChanged; 30161 30162 /** 30163 * Set to true if a view has been scrolled. 30164 */ 30165 @UnsupportedAppUsage 30166 boolean mViewScrollChanged; 30167 30168 /** 30169 * Set to true if a pointer event is currently being handled. 30170 */ 30171 boolean mHandlingPointerEvent; 30172 30173 /** 30174 * The window matrix of this view when it's on a {@link SurfaceControlViewHost} that is 30175 * embedded within a SurfaceView. 30176 */ 30177 Matrix mWindowMatrixInEmbeddedHierarchy; 30178 30179 /** 30180 * Global to the view hierarchy used as a temporary for dealing with 30181 * x/y points in the transparent region computations. 30182 */ 30183 final int[] mTransparentLocation = new int[2]; 30184 30185 /** 30186 * Global to the view hierarchy used as a temporary for dealing with 30187 * x/y points in the ViewGroup.invalidateChild implementation. 30188 */ 30189 final int[] mInvalidateChildLocation = new int[2]; 30190 30191 /** 30192 * Global to the view hierarchy used as a temporary for dealing with 30193 * computing absolute on-screen location. 30194 */ 30195 final int[] mTmpLocation = new int[2]; 30196 30197 /** 30198 * Global to the view hierarchy used as a temporary for dealing with 30199 * x/y location when view is transformed. 30200 */ 30201 final float[] mTmpTransformLocation = new float[2]; 30202 30203 /** 30204 * The view tree observer used to dispatch global events like 30205 * layout, pre-draw, touch mode change, etc. 30206 */ 30207 @UnsupportedAppUsage 30208 final ViewTreeObserver mTreeObserver; 30209 30210 /** 30211 * A Canvas used by the view hierarchy to perform bitmap caching. 30212 */ 30213 Canvas mCanvas; 30214 30215 /** 30216 * The view root impl. 30217 */ 30218 final ViewRootImpl mViewRootImpl; 30219 30220 /** 30221 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 30222 * handler can be used to pump events in the UI events queue. 30223 */ 30224 @UnsupportedAppUsage 30225 final Handler mHandler; 30226 30227 /** 30228 * Temporary for use in computing invalidate rectangles while 30229 * calling up the hierarchy. 30230 */ 30231 final Rect mTmpInvalRect = new Rect(); 30232 30233 /** 30234 * Temporary for use in computing hit areas with transformed views 30235 */ 30236 final RectF mTmpTransformRect = new RectF(); 30237 30238 /** 30239 * Temporary for use in computing hit areas with transformed views 30240 */ 30241 final RectF mTmpTransformRect1 = new RectF(); 30242 30243 /** 30244 * Temporary list of rectanges. 30245 */ 30246 final List<RectF> mTmpRectList = new ArrayList<>(); 30247 30248 /** 30249 * Temporary for use in transforming invalidation rect 30250 */ 30251 final Matrix mTmpMatrix = new Matrix(); 30252 30253 /** 30254 * Temporary for use in transforming invalidation rect 30255 */ 30256 final Transformation mTmpTransformation = new Transformation(); 30257 30258 /** 30259 * Temporary for use in querying outlines from OutlineProviders 30260 */ 30261 final Outline mTmpOutline = new Outline(); 30262 30263 /** 30264 * Temporary list for use in collecting focusable descendents of a view. 30265 */ 30266 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 30267 30268 /** 30269 * The id of the window for accessibility purposes. 30270 */ 30271 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 30272 30273 /** 30274 * Flags related to accessibility processing. 30275 * 30276 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 30277 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 30278 */ 30279 int mAccessibilityFetchFlags; 30280 30281 /** 30282 * The drawable for highlighting accessibility focus. 30283 */ 30284 Drawable mAccessibilityFocusDrawable; 30285 30286 /** 30287 * The drawable for highlighting autofilled views. 30288 * 30289 * @see #isAutofilled() 30290 */ 30291 Drawable mAutofilledDrawable; 30292 30293 /** 30294 * Show where the margins, bounds and layout bounds are for each view. 30295 */ 30296 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 30297 30298 /** 30299 * Point used to compute visible regions. 30300 */ 30301 final Point mPoint = new Point(); 30302 30303 /** 30304 * Used to track which View originated a requestLayout() call, used when 30305 * requestLayout() is called during layout. 30306 */ 30307 View mViewRequestingLayout; 30308 30309 /** 30310 * Used to track the identity of the current drag operation. 30311 */ 30312 IBinder mDragToken; 30313 30314 /** 30315 * The drag shadow surface for the current drag operation. 30316 */ 30317 public Surface mDragSurface; 30318 30319 30320 /** 30321 * The view that currently has a tooltip displayed. 30322 */ 30323 View mTooltipHost; 30324 30325 /** 30326 * The initial structure has been reported so the view is ready to report updates. 30327 */ 30328 boolean mReadyForContentCaptureUpdates; 30329 30330 /** 30331 * Map(keyed by session) of content capture events that need to be notified after the view 30332 * hierarchy is traversed: value is either the view itself for appearead events, or its 30333 * autofill id for disappeared. 30334 */ 30335 SparseArray<ArrayList<Object>> mContentCaptureEvents; 30336 30337 /** 30338 * Cached reference to the {@link ContentCaptureManager}. 30339 */ 30340 ContentCaptureManager mContentCaptureManager; 30341 30342 /** 30343 * Listener used to fit content on window level. 30344 */ 30345 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 30346 30347 /** 30348 * The leash token of this view's parent when it's in an embedded hierarchy that is 30349 * re-parented to another window. 30350 */ 30351 IBinder mLeashedParentToken; 30352 30353 /** 30354 * The accessibility view id of this view's parent when it's in an embedded 30355 * hierarchy that is re-parented to another window. 30356 */ 30357 int mLeashedParentAccessibilityViewId; 30358 30359 /** 30360 * 30361 */ 30362 ScrollCaptureInternal mScrollCaptureInternal; 30363 30364 /** 30365 * Creates a new set of attachment information with the specified 30366 * events handler and thread. 30367 * 30368 * @param handler the events handler the view must use 30369 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)30370 AttachInfo(IWindowSession session, IWindow window, Display display, 30371 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 30372 Context context) { 30373 mSession = session; 30374 mWindow = window; 30375 mWindowToken = window.asBinder(); 30376 mDisplay = display; 30377 mViewRootImpl = viewRootImpl; 30378 mHandler = handler; 30379 mRootCallbacks = effectPlayer; 30380 mTreeObserver = new ViewTreeObserver(context); 30381 } 30382 30383 @Nullable getContentCaptureManager(@onNull Context context)30384 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 30385 if (mContentCaptureManager != null) { 30386 return mContentCaptureManager; 30387 } 30388 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 30389 return mContentCaptureManager; 30390 } 30391 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)30392 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 30393 if (mContentCaptureManager == null) { 30394 return; 30395 } 30396 30397 ArrayList<Object> events = ensureEvents( 30398 mContentCaptureManager.getMainContentCaptureSession()); 30399 events.add(insets); 30400 } 30401 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)30402 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 30403 @NonNull View view, boolean appeared) { 30404 ArrayList<Object> events = ensureEvents(session); 30405 events.add(appeared ? view : view.getAutofillId()); 30406 } 30407 30408 @NonNull ensureEvents(@onNull ContentCaptureSession session)30409 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 30410 if (mContentCaptureEvents == null) { 30411 // Most of the time there will be just one session, so intial capacity is 1 30412 mContentCaptureEvents = new SparseArray<>(1); 30413 } 30414 int sessionId = session.getId(); 30415 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 30416 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 30417 if (events == null) { 30418 events = new ArrayList<>(); 30419 mContentCaptureEvents.put(sessionId, events); 30420 } 30421 30422 return events; 30423 } 30424 30425 @Nullable getScrollCaptureInternal()30426 ScrollCaptureInternal getScrollCaptureInternal() { 30427 if (mScrollCaptureInternal != null) { 30428 mScrollCaptureInternal = new ScrollCaptureInternal(); 30429 } 30430 return mScrollCaptureInternal; 30431 } 30432 getRootSurfaceControl()30433 AttachedSurfaceControl getRootSurfaceControl() { 30434 return mViewRootImpl; 30435 } 30436 dump(String prefix, PrintWriter writer)30437 public void dump(String prefix, PrintWriter writer) { 30438 String innerPrefix = prefix + " "; 30439 writer.println(prefix + "AttachInfo:"); 30440 writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); 30441 writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); 30442 writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); 30443 writer.println(innerPrefix + "mUnbufferedDispatchRequested=" 30444 + mUnbufferedDispatchRequested); 30445 } 30446 } 30447 30448 /** 30449 * <p>ScrollabilityCache holds various fields used by a View when scrolling 30450 * is supported. This avoids keeping too many unused fields in most 30451 * instances of View.</p> 30452 */ 30453 private static class ScrollabilityCache implements Runnable { 30454 30455 /** 30456 * Scrollbars are not visible 30457 */ 30458 public static final int OFF = 0; 30459 30460 /** 30461 * Scrollbars are visible 30462 */ 30463 public static final int ON = 1; 30464 30465 /** 30466 * Scrollbars are fading away 30467 */ 30468 public static final int FADING = 2; 30469 30470 public boolean fadeScrollBars; 30471 30472 public int fadingEdgeLength; 30473 public int scrollBarDefaultDelayBeforeFade; 30474 public int scrollBarFadeDuration; 30475 30476 public int scrollBarSize; 30477 public int scrollBarMinTouchTarget; 30478 @UnsupportedAppUsage 30479 public ScrollBarDrawable scrollBar; 30480 public float[] interpolatorValues; 30481 @UnsupportedAppUsage 30482 public View host; 30483 30484 public final Paint paint; 30485 public final Matrix matrix; 30486 public Shader shader; 30487 30488 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 30489 30490 private static final float[] OPAQUE = { 255 }; 30491 private static final float[] TRANSPARENT = { 0.0f }; 30492 30493 /** 30494 * When fading should start. This time moves into the future every time 30495 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 30496 */ 30497 public long fadeStartTime; 30498 30499 30500 /** 30501 * The current state of the scrollbars: ON, OFF, or FADING 30502 */ 30503 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 30504 public int state = OFF; 30505 30506 private int mLastColor; 30507 30508 public final Rect mScrollBarBounds = new Rect(); 30509 public final Rect mScrollBarTouchBounds = new Rect(); 30510 30511 public static final int NOT_DRAGGING = 0; 30512 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 30513 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 30514 public int mScrollBarDraggingState = NOT_DRAGGING; 30515 30516 public float mScrollBarDraggingPos = 0; 30517 ScrollabilityCache(ViewConfiguration configuration, View host)30518 public ScrollabilityCache(ViewConfiguration configuration, View host) { 30519 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 30520 scrollBarSize = configuration.getScaledScrollBarSize(); 30521 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 30522 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 30523 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 30524 30525 paint = new Paint(); 30526 matrix = new Matrix(); 30527 // use use a height of 1, and then wack the matrix each time we 30528 // actually use it. 30529 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 30530 paint.setShader(shader); 30531 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 30532 30533 this.host = host; 30534 } 30535 setFadeColor(int color)30536 public void setFadeColor(int color) { 30537 if (color != mLastColor) { 30538 mLastColor = color; 30539 30540 if (color != 0) { 30541 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 30542 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 30543 paint.setShader(shader); 30544 // Restore the default transfer mode (src_over) 30545 paint.setXfermode(null); 30546 } else { 30547 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 30548 paint.setShader(shader); 30549 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 30550 } 30551 } 30552 } 30553 run()30554 public void run() { 30555 long now = AnimationUtils.currentAnimationTimeMillis(); 30556 if (now >= fadeStartTime) { 30557 30558 // the animation fades the scrollbars out by changing 30559 // the opacity (alpha) from fully opaque to fully 30560 // transparent 30561 int nextFrame = (int) now; 30562 int framesCount = 0; 30563 30564 Interpolator interpolator = scrollBarInterpolator; 30565 30566 // Start opaque 30567 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 30568 30569 // End transparent 30570 nextFrame += scrollBarFadeDuration; 30571 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 30572 30573 state = FADING; 30574 30575 // Kick off the fade animation 30576 host.invalidate(true); 30577 } 30578 } 30579 } 30580 30581 private class SendAccessibilityEventThrottle implements Runnable { 30582 public volatile boolean mIsPending; 30583 private AccessibilityEvent mAccessibilityEvent; 30584 post(AccessibilityEvent accessibilityEvent)30585 public void post(AccessibilityEvent accessibilityEvent) { 30586 updateWithAccessibilityEvent(accessibilityEvent); 30587 if (!mIsPending) { 30588 mIsPending = true; 30589 postDelayed(this, 30590 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 30591 } 30592 } 30593 30594 @Override run()30595 public void run() { 30596 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 30597 requestParentSendAccessibilityEvent(mAccessibilityEvent); 30598 } 30599 reset(); 30600 } 30601 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)30602 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 30603 mAccessibilityEvent = accessibilityEvent; 30604 } 30605 reset()30606 public void reset() { 30607 mIsPending = false; 30608 mAccessibilityEvent = null; 30609 } 30610 30611 } 30612 30613 /** 30614 * Resuable callback for sending 30615 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 30616 */ 30617 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 30618 public int mDeltaX; 30619 public int mDeltaY; 30620 30621 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)30622 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 30623 super.updateWithAccessibilityEvent(accessibilityEvent); 30624 mDeltaX += accessibilityEvent.getScrollDeltaX(); 30625 mDeltaY += accessibilityEvent.getScrollDeltaY(); 30626 accessibilityEvent.setScrollDeltaX(mDeltaX); 30627 accessibilityEvent.setScrollDeltaY(mDeltaY); 30628 } 30629 30630 @Override reset()30631 public void reset() { 30632 super.reset(); 30633 mDeltaX = 0; 30634 mDeltaY = 0; 30635 } 30636 } 30637 /** 30638 * Remove the pending callback for sending a throttled accessibility event. 30639 */ 30640 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)30641 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 30642 if (callback == null || !callback.mIsPending) return; 30643 removeCallbacks(callback); 30644 callback.reset(); 30645 } 30646 30647 /** 30648 * <p> 30649 * This class represents a delegate that can be registered in a {@link View} 30650 * to enhance accessibility support via composition rather via inheritance. 30651 * It is specifically targeted to widget developers that extend basic View 30652 * classes i.e. classes in package android.view, that would like their 30653 * applications to be backwards compatible. 30654 * </p> 30655 * <div class="special reference"> 30656 * <h3>Developer Guides</h3> 30657 * <p>For more information about making applications accessible, read the 30658 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 30659 * developer guide.</p> 30660 * </div> 30661 * <p> 30662 * A scenario in which a developer would like to use an accessibility delegate 30663 * is overriding a method introduced in a later API version than the minimal API 30664 * version supported by the application. For example, the method 30665 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 30666 * in API version 4 when the accessibility APIs were first introduced. If a 30667 * developer would like their application to run on API version 4 devices (assuming 30668 * all other APIs used by the application are version 4 or lower) and take advantage 30669 * of this method, instead of overriding the method which would break the application's 30670 * backwards compatibility, they can override the corresponding method in this 30671 * delegate and register the delegate in the target View if the API version of 30672 * the system is high enough, i.e. the API version is the same as or higher than the API 30673 * version that introduced 30674 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 30675 * </p> 30676 * <p> 30677 * Here is an example implementation: 30678 * </p> 30679 * <code><pre><p> 30680 * if (Build.VERSION.SDK_INT >= 14) { 30681 * // If the API version is equal of higher than the version in 30682 * // which onInitializeAccessibilityNodeInfo was introduced we 30683 * // register a delegate with a customized implementation. 30684 * View view = findViewById(R.id.view_id); 30685 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 30686 * public void onInitializeAccessibilityNodeInfo(View host, 30687 * AccessibilityNodeInfo info) { 30688 * // Let the default implementation populate the info. 30689 * super.onInitializeAccessibilityNodeInfo(host, info); 30690 * // Set some other information. 30691 * info.setEnabled(host.isEnabled()); 30692 * } 30693 * }); 30694 * } 30695 * </code></pre></p> 30696 * <p> 30697 * This delegate contains methods that correspond to the accessibility methods 30698 * in View. If a delegate has been specified the implementation in View hands 30699 * off handling to the corresponding method in this delegate. The default 30700 * implementation the delegate methods behaves exactly as the corresponding 30701 * method in View for the case of no accessibility delegate been set. Hence, 30702 * to customize the behavior of a View method, clients can override only the 30703 * corresponding delegate method without altering the behavior of the rest 30704 * accessibility related methods of the host view. 30705 * </p> 30706 * <p> 30707 * <strong>Note:</strong> On platform versions prior to 30708 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 30709 * views in the {@code android.widget.*} package are called <i>before</i> 30710 * host methods. This prevents certain properties such as class name from 30711 * being modified by overriding 30712 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 30713 * as any changes will be overwritten by the host class. 30714 * <p> 30715 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 30716 * methods are called <i>after</i> host methods, which all properties to be 30717 * modified without being overwritten by the host class. 30718 */ 30719 public static class AccessibilityDelegate { 30720 30721 /** 30722 * Sends an accessibility event of the given type. If accessibility is not 30723 * enabled this method has no effect. 30724 * <p> 30725 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 30726 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 30727 * been set. 30728 * </p> 30729 * 30730 * @param host The View hosting the delegate. 30731 * @param eventType The type of the event to send. 30732 * 30733 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 30734 */ sendAccessibilityEvent(@onNull View host, int eventType)30735 public void sendAccessibilityEvent(@NonNull View host, int eventType) { 30736 host.sendAccessibilityEventInternal(eventType); 30737 } 30738 30739 /** 30740 * Performs the specified accessibility action on the view. For 30741 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 30742 * <p> 30743 * The default implementation behaves as 30744 * {@link View#performAccessibilityAction(int, Bundle) 30745 * View#performAccessibilityAction(int, Bundle)} for the case of 30746 * no accessibility delegate been set. 30747 * </p> 30748 * 30749 * @param action The action to perform. 30750 * @return Whether the action was performed. 30751 * 30752 * @see View#performAccessibilityAction(int, Bundle) 30753 * View#performAccessibilityAction(int, Bundle) 30754 */ performAccessibilityAction(@onNull View host, int action, @Nullable Bundle args)30755 public boolean performAccessibilityAction(@NonNull View host, int action, 30756 @Nullable Bundle args) { 30757 return host.performAccessibilityActionInternal(action, args); 30758 } 30759 30760 /** 30761 * Sends an accessibility event. This method behaves exactly as 30762 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 30763 * empty {@link AccessibilityEvent} and does not perform a check whether 30764 * accessibility is enabled. 30765 * <p> 30766 * The default implementation behaves as 30767 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 30768 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 30769 * the case of no accessibility delegate been set. 30770 * </p> 30771 * 30772 * @param host The View hosting the delegate. 30773 * @param event The event to send. 30774 * 30775 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 30776 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 30777 */ sendAccessibilityEventUnchecked(@onNull View host, @NonNull AccessibilityEvent event)30778 public void sendAccessibilityEventUnchecked(@NonNull View host, 30779 @NonNull AccessibilityEvent event) { 30780 host.sendAccessibilityEventUncheckedInternal(event); 30781 } 30782 30783 /** 30784 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 30785 * to its children for adding their text content to the event. 30786 * <p> 30787 * The default implementation behaves as 30788 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30789 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 30790 * the case of no accessibility delegate been set. 30791 * </p> 30792 * 30793 * @param host The View hosting the delegate. 30794 * @param event The event. 30795 * @return True if the event population was completed. 30796 * 30797 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30798 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30799 */ dispatchPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)30800 public boolean dispatchPopulateAccessibilityEvent(@NonNull View host, 30801 @NonNull AccessibilityEvent event) { 30802 return host.dispatchPopulateAccessibilityEventInternal(event); 30803 } 30804 30805 /** 30806 * Gives a chance to the host View to populate the accessibility event with its 30807 * text content. 30808 * <p> 30809 * The default implementation behaves as 30810 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 30811 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 30812 * the case of no accessibility delegate been set. 30813 * </p> 30814 * 30815 * @param host The View hosting the delegate. 30816 * @param event The accessibility event which to populate. 30817 * 30818 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 30819 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 30820 */ onPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)30821 public void onPopulateAccessibilityEvent(@NonNull View host, 30822 @NonNull AccessibilityEvent event) { 30823 host.onPopulateAccessibilityEventInternal(event); 30824 } 30825 30826 /** 30827 * Initializes an {@link AccessibilityEvent} with information about the 30828 * the host View which is the event source. 30829 * <p> 30830 * The default implementation behaves as 30831 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 30832 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 30833 * the case of no accessibility delegate been set. 30834 * </p> 30835 * 30836 * @param host The View hosting the delegate. 30837 * @param event The event to initialize. 30838 * 30839 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 30840 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 30841 */ onInitializeAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)30842 public void onInitializeAccessibilityEvent(@NonNull View host, 30843 @NonNull AccessibilityEvent event) { 30844 host.onInitializeAccessibilityEventInternal(event); 30845 } 30846 30847 /** 30848 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 30849 * <p> 30850 * The default implementation behaves as 30851 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30852 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 30853 * the case of no accessibility delegate been set. 30854 * </p> 30855 * 30856 * @param host The View hosting the delegate. 30857 * @param info The instance to initialize. 30858 * 30859 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30860 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30861 */ onInitializeAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info)30862 public void onInitializeAccessibilityNodeInfo(@NonNull View host, 30863 @NonNull AccessibilityNodeInfo info) { 30864 host.onInitializeAccessibilityNodeInfoInternal(info); 30865 } 30866 30867 /** 30868 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 30869 * additional data. 30870 * <p> 30871 * This method only needs to be implemented if the View offers to provide additional data. 30872 * </p> 30873 * <p> 30874 * The default implementation behaves as 30875 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 30876 * for the case where no accessibility delegate is set. 30877 * </p> 30878 * 30879 * @param host The View hosting the delegate. Never {@code null}. 30880 * @param info The info to which to add the extra data. Never {@code null}. 30881 * @param extraDataKey A key specifying the type of extra data to add to the info. The 30882 * extra data should be added to the {@link Bundle} returned by 30883 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 30884 * {@code null}. 30885 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 30886 * May be {@code null} if the if the service provided no arguments. 30887 * 30888 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 30889 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)30890 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 30891 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 30892 @Nullable Bundle arguments) { 30893 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 30894 } 30895 30896 /** 30897 * Called when a child of the host View has requested sending an 30898 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 30899 * to augment the event. 30900 * <p> 30901 * The default implementation behaves as 30902 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30903 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 30904 * the case of no accessibility delegate been set. 30905 * </p> 30906 * 30907 * @param host The View hosting the delegate. 30908 * @param child The child which requests sending the event. 30909 * @param event The event to be sent. 30910 * @return True if the event should be sent 30911 * 30912 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30913 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30914 */ onRequestSendAccessibilityEvent(@onNull ViewGroup host, @NonNull View child, @NonNull AccessibilityEvent event)30915 public boolean onRequestSendAccessibilityEvent(@NonNull ViewGroup host, @NonNull View child, 30916 @NonNull AccessibilityEvent event) { 30917 return host.onRequestSendAccessibilityEventInternal(child, event); 30918 } 30919 30920 /** 30921 * Gets the provider for managing a virtual view hierarchy rooted at this View 30922 * and reported to {@link android.accessibilityservice.AccessibilityService}s 30923 * that explore the window content. 30924 * <p> 30925 * The default implementation behaves as 30926 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 30927 * the case of no accessibility delegate been set. 30928 * </p> 30929 * 30930 * @return The provider. 30931 * 30932 * @see AccessibilityNodeProvider 30933 */ getAccessibilityNodeProvider( @onNull View host)30934 public @Nullable AccessibilityNodeProvider getAccessibilityNodeProvider( 30935 @NonNull View host) { 30936 return null; 30937 } 30938 30939 /** 30940 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 30941 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 30942 * This method is responsible for obtaining an accessibility node info from a 30943 * pool of reusable instances and calling 30944 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 30945 * view to initialize the former. 30946 * <p> 30947 * <strong>Note:</strong> The client is responsible for recycling the obtained 30948 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 30949 * creation. 30950 * </p> 30951 * <p> 30952 * The default implementation behaves as 30953 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 30954 * the case of no accessibility delegate been set. 30955 * </p> 30956 * @return A populated {@link AccessibilityNodeInfo}. 30957 * 30958 * @see AccessibilityNodeInfo 30959 * 30960 * @hide 30961 */ 30962 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) createAccessibilityNodeInfo(@onNull View host)30963 public AccessibilityNodeInfo createAccessibilityNodeInfo(@NonNull View host) { 30964 return host.createAccessibilityNodeInfoInternal(); 30965 } 30966 } 30967 30968 private static class MatchIdPredicate implements Predicate<View> { 30969 public int mId; 30970 30971 @Override test(View view)30972 public boolean test(View view) { 30973 return (view.mID == mId); 30974 } 30975 } 30976 30977 private static class MatchLabelForPredicate implements Predicate<View> { 30978 private int mLabeledId; 30979 30980 @Override test(View view)30981 public boolean test(View view) { 30982 return (view.mLabelForId == mLabeledId); 30983 } 30984 } 30985 30986 30987 /** 30988 * Returns the current scroll capture hint for this view. 30989 * 30990 * @return the current scroll capture hint 30991 */ 30992 @ScrollCaptureHint getScrollCaptureHint()30993 public int getScrollCaptureHint() { 30994 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 30995 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 30996 } 30997 30998 /** 30999 * Sets the scroll capture hint for this View. These flags affect the search for a potential 31000 * scroll capture targets. 31001 * 31002 * @param hint the scrollCaptureHint flags value to set 31003 */ setScrollCaptureHint(@crollCaptureHint int hint)31004 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 31005 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 31006 // Since include/exclude are mutually exclusive, exclude takes precedence. 31007 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 31008 hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; 31009 } 31010 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 31011 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 31012 } 31013 31014 /** 31015 * Sets the callback to receive scroll capture requests. This component is the adapter between 31016 * the scroll capture API and application UI code. If no callback is set, the system may provide 31017 * an implementation. Any value provided here will take precedence over a system version. 31018 * <p> 31019 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 31020 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 31021 * <p> 31022 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 31023 * setting a custom callback to help ensure it is selected as the target. 31024 * 31025 * @param callback the new callback to assign 31026 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)31027 public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 31028 getListenerInfo().mScrollCaptureCallback = callback; 31029 } 31030 31031 /** {@hide} */ 31032 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)31033 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 31034 @NonNull Point windowOffset) { 31035 if (mAttachInfo == null) { 31036 return null; 31037 } 31038 if (mAttachInfo.mScrollCaptureInternal == null) { 31039 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 31040 } 31041 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 31042 windowOffset); 31043 } 31044 31045 /** 31046 * Dispatch a scroll capture search request down the view hierarchy. 31047 * 31048 * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to 31049 * the parent 31050 * @param windowOffset the offset of this view within the window 31051 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 31052 * results.accept} may be called zero or more times on the calling 31053 * thread before onScrollCaptureSearch returns 31054 */ dispatchScrollCaptureSearch( @onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)31055 public void dispatchScrollCaptureSearch( 31056 @NonNull Rect localVisibleRect, @NonNull Point windowOffset, 31057 @NonNull Consumer<ScrollCaptureTarget> targets) { 31058 onScrollCaptureSearch(localVisibleRect, windowOffset, targets); 31059 } 31060 31061 /** 31062 * Called when scroll capture is requested, to search for appropriate content to scroll. If 31063 * applicable, this view adds itself to the provided list for consideration, subject to the 31064 * flags set by {@link #setScrollCaptureHint}. 31065 * 31066 * @param localVisibleRect the local visible rect of this view 31067 * @param windowOffset the offset of localVisibleRect within the window 31068 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 31069 * results.accept} may be called zero or more times on the calling 31070 * thread before onScrollCaptureSearch returns 31071 * @throws IllegalStateException if this view is not attached to a window 31072 */ onScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)31073 public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, 31074 @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { 31075 int hint = getScrollCaptureHint(); 31076 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 31077 return; 31078 } 31079 boolean rectIsVisible = true; 31080 31081 // Apply clipBounds if present. 31082 if (mClipBounds != null) { 31083 rectIsVisible = localVisibleRect.intersect(mClipBounds); 31084 } 31085 if (!rectIsVisible) { 31086 return; 31087 } 31088 31089 // Get a callback provided by the framework, library or application. 31090 ScrollCaptureCallback callback = 31091 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 31092 31093 // Try framework support for standard scrolling containers. 31094 if (callback == null) { 31095 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 31096 } 31097 31098 // If found, then add it to the list. 31099 if (callback != null) { 31100 // Add to the list for consideration 31101 Point offset = new Point(windowOffset.x, windowOffset.y); 31102 Rect rect = new Rect(localVisibleRect); 31103 targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); 31104 } 31105 } 31106 31107 /** 31108 * Dump all private flags in readable format, useful for documentation and 31109 * consistency checking. 31110 */ dumpFlags()31111 private static void dumpFlags() { 31112 final HashMap<String, String> found = Maps.newHashMap(); 31113 try { 31114 for (Field field : View.class.getDeclaredFields()) { 31115 final int modifiers = field.getModifiers(); 31116 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 31117 if (field.getType().equals(int.class)) { 31118 final int value = field.getInt(null); 31119 dumpFlag(found, field.getName(), value); 31120 } else if (field.getType().equals(int[].class)) { 31121 final int[] values = (int[]) field.get(null); 31122 for (int i = 0; i < values.length; i++) { 31123 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 31124 } 31125 } 31126 } 31127 } 31128 } catch (IllegalAccessException e) { 31129 throw new RuntimeException(e); 31130 } 31131 31132 final ArrayList<String> keys = Lists.newArrayList(); 31133 keys.addAll(found.keySet()); 31134 Collections.sort(keys); 31135 for (String key : keys) { 31136 Log.d(VIEW_LOG_TAG, found.get(key)); 31137 } 31138 } 31139 dumpFlag(HashMap<String, String> found, String name, int value)31140 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 31141 // Sort flags by prefix, then by bits, always keeping unique keys 31142 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 31143 final int prefix = name.indexOf('_'); 31144 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 31145 final String output = bits + " " + name; 31146 found.put(key, output); 31147 } 31148 31149 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)31150 public void encode(@NonNull ViewHierarchyEncoder stream) { 31151 stream.beginObject(this); 31152 encodeProperties(stream); 31153 stream.endObject(); 31154 } 31155 31156 /** {@hide} */ 31157 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)31158 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 31159 Object resolveId = ViewDebug.resolveId(getContext(), mID); 31160 if (resolveId instanceof String) { 31161 stream.addProperty("id", (String) resolveId); 31162 } else { 31163 stream.addProperty("id", mID); 31164 } 31165 31166 stream.addProperty("misc:transformation.alpha", 31167 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 31168 stream.addProperty("misc:transitionName", getTransitionName()); 31169 31170 // layout 31171 stream.addProperty("layout:left", mLeft); 31172 stream.addProperty("layout:right", mRight); 31173 stream.addProperty("layout:top", mTop); 31174 stream.addProperty("layout:bottom", mBottom); 31175 stream.addProperty("layout:width", getWidth()); 31176 stream.addProperty("layout:height", getHeight()); 31177 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 31178 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 31179 stream.addProperty("layout:hasTransientState", hasTransientState()); 31180 stream.addProperty("layout:baseline", getBaseline()); 31181 31182 // layout params 31183 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 31184 if (layoutParams != null) { 31185 stream.addPropertyKey("layoutParams"); 31186 layoutParams.encode(stream); 31187 } 31188 31189 // scrolling 31190 stream.addProperty("scrolling:scrollX", mScrollX); 31191 stream.addProperty("scrolling:scrollY", mScrollY); 31192 31193 // padding 31194 stream.addProperty("padding:paddingLeft", mPaddingLeft); 31195 stream.addProperty("padding:paddingRight", mPaddingRight); 31196 stream.addProperty("padding:paddingTop", mPaddingTop); 31197 stream.addProperty("padding:paddingBottom", mPaddingBottom); 31198 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 31199 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 31200 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 31201 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 31202 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 31203 31204 // measurement 31205 stream.addProperty("measurement:minHeight", mMinHeight); 31206 stream.addProperty("measurement:minWidth", mMinWidth); 31207 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 31208 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 31209 31210 // drawing 31211 stream.addProperty("drawing:elevation", getElevation()); 31212 stream.addProperty("drawing:translationX", getTranslationX()); 31213 stream.addProperty("drawing:translationY", getTranslationY()); 31214 stream.addProperty("drawing:translationZ", getTranslationZ()); 31215 stream.addProperty("drawing:rotation", getRotation()); 31216 stream.addProperty("drawing:rotationX", getRotationX()); 31217 stream.addProperty("drawing:rotationY", getRotationY()); 31218 stream.addProperty("drawing:scaleX", getScaleX()); 31219 stream.addProperty("drawing:scaleY", getScaleY()); 31220 stream.addProperty("drawing:pivotX", getPivotX()); 31221 stream.addProperty("drawing:pivotY", getPivotY()); 31222 stream.addProperty("drawing:clipBounds", 31223 mClipBounds == null ? null : mClipBounds.toString()); 31224 stream.addProperty("drawing:opaque", isOpaque()); 31225 stream.addProperty("drawing:alpha", getAlpha()); 31226 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 31227 stream.addProperty("drawing:shadow", hasShadow()); 31228 stream.addProperty("drawing:solidColor", getSolidColor()); 31229 stream.addProperty("drawing:layerType", mLayerType); 31230 stream.addProperty("drawing:willNotDraw", willNotDraw()); 31231 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 31232 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 31233 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 31234 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 31235 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 31236 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 31237 31238 // focus 31239 stream.addProperty("focus:hasFocus", hasFocus()); 31240 stream.addProperty("focus:isFocused", isFocused()); 31241 stream.addProperty("focus:focusable", getFocusable()); 31242 stream.addProperty("focus:isFocusable", isFocusable()); 31243 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 31244 31245 stream.addProperty("misc:clickable", isClickable()); 31246 stream.addProperty("misc:pressed", isPressed()); 31247 stream.addProperty("misc:selected", isSelected()); 31248 stream.addProperty("misc:touchMode", isInTouchMode()); 31249 stream.addProperty("misc:hovered", isHovered()); 31250 stream.addProperty("misc:activated", isActivated()); 31251 31252 stream.addProperty("misc:visibility", getVisibility()); 31253 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 31254 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 31255 31256 stream.addProperty("misc:enabled", isEnabled()); 31257 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 31258 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 31259 31260 // theme attributes 31261 Resources.Theme theme = getContext().getTheme(); 31262 if (theme != null) { 31263 stream.addPropertyKey("theme"); 31264 theme.encode(stream); 31265 } 31266 31267 // view attribute information 31268 int n = mAttributes != null ? mAttributes.length : 0; 31269 stream.addProperty("meta:__attrCount__", n/2); 31270 for (int i = 0; i < n; i += 2) { 31271 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 31272 } 31273 31274 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 31275 31276 // text 31277 stream.addProperty("text:textDirection", getTextDirection()); 31278 stream.addProperty("text:textAlignment", getTextAlignment()); 31279 31280 // accessibility 31281 CharSequence contentDescription = getContentDescription(); 31282 stream.addUserProperty("accessibility:contentDescription", 31283 contentDescription == null ? "" : contentDescription.toString()); 31284 stream.addProperty("accessibility:labelFor", getLabelFor()); 31285 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 31286 } 31287 31288 /** 31289 * Determine if this view is rendered on a round wearable device and is the main view 31290 * on the screen. 31291 */ shouldDrawRoundScrollbar()31292 boolean shouldDrawRoundScrollbar() { 31293 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 31294 return false; 31295 } 31296 31297 final View rootView = getRootView(); 31298 final WindowInsets insets = getRootWindowInsets(); 31299 31300 int height = getHeight(); 31301 int width = getWidth(); 31302 int displayHeight = rootView.getHeight(); 31303 int displayWidth = rootView.getWidth(); 31304 31305 if (height != displayHeight || width != displayWidth) { 31306 return false; 31307 } 31308 31309 getLocationInWindow(mAttachInfo.mTmpLocation); 31310 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 31311 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 31312 } 31313 31314 /** 31315 * Sets the tooltip text which will be displayed in a small popup next to the view. 31316 * <p> 31317 * The tooltip will be displayed: 31318 * <ul> 31319 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 31320 * menu). </li> 31321 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 31322 * </ul> 31323 * <p> 31324 * <strong>Note:</strong> Do not override this method, as it will have no 31325 * effect on the text displayed in the tooltip. 31326 * 31327 * @param tooltipText the tooltip text, or null if no tooltip is required 31328 * @see #getTooltipText() 31329 * @attr ref android.R.styleable#View_tooltipText 31330 */ setTooltipText(@ullable CharSequence tooltipText)31331 public void setTooltipText(@Nullable CharSequence tooltipText) { 31332 if (TextUtils.isEmpty(tooltipText)) { 31333 setFlags(0, TOOLTIP); 31334 hideTooltip(); 31335 mTooltipInfo = null; 31336 } else { 31337 setFlags(TOOLTIP, TOOLTIP); 31338 if (mTooltipInfo == null) { 31339 mTooltipInfo = new TooltipInfo(); 31340 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 31341 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 31342 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 31343 mTooltipInfo.clearAnchorPos(); 31344 } 31345 mTooltipInfo.mTooltipText = tooltipText; 31346 } 31347 } 31348 31349 /** 31350 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 31351 */ 31352 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)31353 public void setTooltip(@Nullable CharSequence tooltipText) { 31354 setTooltipText(tooltipText); 31355 } 31356 31357 /** 31358 * Returns the view's tooltip text. 31359 * 31360 * <strong>Note:</strong> Do not override this method, as it will have no 31361 * effect on the text displayed in the tooltip. You must call 31362 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 31363 * 31364 * @return the tooltip text 31365 * @see #setTooltipText(CharSequence) 31366 * @attr ref android.R.styleable#View_tooltipText 31367 */ 31368 @InspectableProperty 31369 @Nullable getTooltipText()31370 public CharSequence getTooltipText() { 31371 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 31372 } 31373 31374 /** 31375 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 31376 */ 31377 @Nullable getTooltip()31378 public CharSequence getTooltip() { 31379 return getTooltipText(); 31380 } 31381 showTooltip(int x, int y, boolean fromLongClick)31382 private boolean showTooltip(int x, int y, boolean fromLongClick) { 31383 if (mAttachInfo == null || mTooltipInfo == null) { 31384 return false; 31385 } 31386 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 31387 return false; 31388 } 31389 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 31390 return false; 31391 } 31392 hideTooltip(); 31393 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 31394 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 31395 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 31396 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 31397 mAttachInfo.mTooltipHost = this; 31398 // The available accessibility actions have changed 31399 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 31400 return true; 31401 } 31402 31403 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hideTooltip()31404 void hideTooltip() { 31405 if (mTooltipInfo == null) { 31406 return; 31407 } 31408 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 31409 if (mTooltipInfo.mTooltipPopup == null) { 31410 return; 31411 } 31412 mTooltipInfo.mTooltipPopup.hide(); 31413 mTooltipInfo.mTooltipPopup = null; 31414 mTooltipInfo.mTooltipFromLongClick = false; 31415 mTooltipInfo.clearAnchorPos(); 31416 if (mAttachInfo != null) { 31417 mAttachInfo.mTooltipHost = null; 31418 } 31419 // The available accessibility actions have changed 31420 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 31421 } 31422 showLongClickTooltip(int x, int y)31423 private boolean showLongClickTooltip(int x, int y) { 31424 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 31425 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 31426 return showTooltip(x, y, true); 31427 } 31428 showHoverTooltip()31429 private boolean showHoverTooltip() { 31430 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 31431 } 31432 dispatchTooltipHoverEvent(MotionEvent event)31433 boolean dispatchTooltipHoverEvent(MotionEvent event) { 31434 if (mTooltipInfo == null) { 31435 return false; 31436 } 31437 switch(event.getAction()) { 31438 case MotionEvent.ACTION_HOVER_MOVE: 31439 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 31440 break; 31441 } 31442 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 31443 if (mTooltipInfo.mTooltipPopup == null) { 31444 // Schedule showing the tooltip after a timeout. 31445 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 31446 postDelayed(mTooltipInfo.mShowTooltipRunnable, 31447 ViewConfiguration.getHoverTooltipShowTimeout()); 31448 } 31449 31450 // Hide hover-triggered tooltip after a period of inactivity. 31451 // Match the timeout used by NativeInputManager to hide the mouse pointer 31452 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 31453 final int timeout; 31454 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 31455 == SYSTEM_UI_FLAG_LOW_PROFILE) { 31456 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 31457 } else { 31458 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 31459 } 31460 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 31461 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 31462 } 31463 return true; 31464 31465 case MotionEvent.ACTION_HOVER_EXIT: 31466 mTooltipInfo.clearAnchorPos(); 31467 if (!mTooltipInfo.mTooltipFromLongClick) { 31468 hideTooltip(); 31469 } 31470 break; 31471 } 31472 return false; 31473 } 31474 handleTooltipKey(KeyEvent event)31475 void handleTooltipKey(KeyEvent event) { 31476 switch (event.getAction()) { 31477 case KeyEvent.ACTION_DOWN: 31478 if (event.getRepeatCount() == 0) { 31479 hideTooltip(); 31480 } 31481 break; 31482 31483 case KeyEvent.ACTION_UP: 31484 handleTooltipUp(); 31485 break; 31486 } 31487 } 31488 handleTooltipUp()31489 private void handleTooltipUp() { 31490 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 31491 return; 31492 } 31493 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 31494 postDelayed(mTooltipInfo.mHideTooltipRunnable, 31495 ViewConfiguration.getLongPressTooltipHideTimeout()); 31496 } 31497 getFocusableAttribute(TypedArray attributes)31498 private int getFocusableAttribute(TypedArray attributes) { 31499 TypedValue val = new TypedValue(); 31500 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 31501 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 31502 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 31503 } else { 31504 return val.data; 31505 } 31506 } else { 31507 return FOCUSABLE_AUTO; 31508 } 31509 } 31510 31511 /** 31512 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 31513 * is not showing. 31514 * @hide 31515 */ 31516 @TestApi getTooltipView()31517 public View getTooltipView() { 31518 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 31519 return null; 31520 } 31521 return mTooltipInfo.mTooltipPopup.getContentView(); 31522 } 31523 31524 /** 31525 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 31526 * @hide 31527 */ 31528 @TestApi isDefaultFocusHighlightEnabled()31529 public static boolean isDefaultFocusHighlightEnabled() { 31530 return sUseDefaultFocusHighlight; 31531 } 31532 31533 /** 31534 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 31535 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 31536 * (visually on-top views first). 31537 * 31538 * @param evt the previously unhandled {@link KeyEvent}. 31539 * @return the {@link View} which consumed the event or {@code null} if not consumed. 31540 */ dispatchUnhandledKeyEvent(KeyEvent evt)31541 View dispatchUnhandledKeyEvent(KeyEvent evt) { 31542 if (onUnhandledKeyEvent(evt)) { 31543 return this; 31544 } 31545 return null; 31546 } 31547 31548 /** 31549 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 31550 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 31551 * this will dispatch into all the listeners registered via 31552 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 31553 * order (most recently added will receive events first). 31554 * 31555 * @param event An unhandled event. 31556 * @return {@code true} if the event was handled, {@code false} otherwise. 31557 * @see #addOnUnhandledKeyEventListener 31558 */ onUnhandledKeyEvent(@onNull KeyEvent event)31559 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 31560 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 31561 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 31562 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 31563 return true; 31564 } 31565 } 31566 } 31567 return false; 31568 } 31569 hasUnhandledKeyListener()31570 boolean hasUnhandledKeyListener() { 31571 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 31572 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 31573 } 31574 31575 /** 31576 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 31577 * UI thread. 31578 * 31579 * @param listener a receiver of unhandled {@link KeyEvent}s. 31580 * @see #removeOnUnhandledKeyEventListener 31581 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)31582 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 31583 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 31584 if (listeners == null) { 31585 listeners = new ArrayList<>(); 31586 getListenerInfo().mUnhandledKeyListeners = listeners; 31587 } 31588 listeners.add(listener); 31589 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 31590 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 31591 } 31592 } 31593 31594 /** 31595 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 31596 * UI thread. 31597 * 31598 * @param listener a receiver of unhandled {@link KeyEvent}s. 31599 * @see #addOnUnhandledKeyEventListener 31600 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)31601 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 31602 if (mListenerInfo != null) { 31603 if (mListenerInfo.mUnhandledKeyListeners != null 31604 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 31605 mListenerInfo.mUnhandledKeyListeners.remove(listener); 31606 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 31607 mListenerInfo.mUnhandledKeyListeners = null; 31608 if (mParent instanceof ViewGroup) { 31609 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 31610 } 31611 } 31612 } 31613 } 31614 } 31615 31616 /** 31617 * Set the view to be detached or not detached. 31618 * 31619 * @param detached Whether the view is detached. 31620 * 31621 * @hide 31622 */ setDetached(boolean detached)31623 protected void setDetached(boolean detached) { 31624 if (detached) { 31625 mPrivateFlags4 |= PFLAG4_DETACHED; 31626 } else { 31627 mPrivateFlags4 &= ~PFLAG4_DETACHED; 31628 } 31629 } 31630 31631 /** 31632 * Set whether this view enables automatic handwriting initiation. 31633 * 31634 * For a view with an active {@link InputConnection}, if auto handwriting is enabled then 31635 * stylus movement within its view boundary will automatically trigger the handwriting mode. 31636 * Check {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} for 31637 * more details about handwriting mode. 31638 * 31639 * If the View wants to initiate handwriting mode by itself, it can set this field to 31640 * {@code false} and call 31641 * {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} when there 31642 * is stylus movement detected. 31643 * 31644 * @see #onCreateInputConnection(EditorInfo) 31645 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 31646 * @param enabled whether auto handwriting initiation is enabled for this view. 31647 * @attr ref android.R.styleable#View_autoHandwritingEnabled 31648 */ setAutoHandwritingEnabled(boolean enabled)31649 public void setAutoHandwritingEnabled(boolean enabled) { 31650 if (enabled) { 31651 mPrivateFlags4 |= PFLAG4_AUTO_HANDWRITING_ENABLED; 31652 } else { 31653 mPrivateFlags4 &= ~PFLAG4_AUTO_HANDWRITING_ENABLED; 31654 } 31655 updatePositionUpdateListener(); 31656 postUpdate(this::updateHandwritingArea); 31657 } 31658 31659 /** 31660 * Return whether the View allows automatic handwriting initiation. Returns true if automatic 31661 * handwriting initiation is enabled, and verse visa. 31662 * @see #setAutoHandwritingEnabled(boolean) 31663 */ isAutoHandwritingEnabled()31664 public boolean isAutoHandwritingEnabled() { 31665 return (mPrivateFlags4 & PFLAG4_AUTO_HANDWRITING_ENABLED) 31666 == PFLAG4_AUTO_HANDWRITING_ENABLED; 31667 } 31668 setTraversalTracingEnabled(boolean enabled)31669 private void setTraversalTracingEnabled(boolean enabled) { 31670 if (enabled) { 31671 if (mTracingStrings == null) { 31672 mTracingStrings = new ViewTraversalTracingStrings(this); 31673 } 31674 mPrivateFlags4 |= PFLAG4_TRAVERSAL_TRACING_ENABLED; 31675 } else { 31676 mPrivateFlags4 &= ~PFLAG4_TRAVERSAL_TRACING_ENABLED; 31677 } 31678 } 31679 isTraversalTracingEnabled()31680 private boolean isTraversalTracingEnabled() { 31681 return (mPrivateFlags4 & PFLAG4_TRAVERSAL_TRACING_ENABLED) 31682 == PFLAG4_TRAVERSAL_TRACING_ENABLED; 31683 } 31684 setRelayoutTracingEnabled(boolean enabled)31685 private void setRelayoutTracingEnabled(boolean enabled) { 31686 if (enabled) { 31687 if (mTracingStrings == null) { 31688 mTracingStrings = new ViewTraversalTracingStrings(this); 31689 } 31690 mPrivateFlags4 |= PFLAG4_RELAYOUT_TRACING_ENABLED; 31691 } else { 31692 mPrivateFlags4 &= ~PFLAG4_RELAYOUT_TRACING_ENABLED; 31693 } 31694 } 31695 isRelayoutTracingEnabled()31696 private boolean isRelayoutTracingEnabled() { 31697 return (mPrivateFlags4 & PFLAG4_RELAYOUT_TRACING_ENABLED) 31698 == PFLAG4_RELAYOUT_TRACING_ENABLED; 31699 } 31700 31701 /** 31702 * Collects a {@link ViewTranslationRequest} which represents the content to be translated in 31703 * the view. 31704 * 31705 * <p>The default implementation does nothing.</p> 31706 * 31707 * @param supportedFormats the supported translation formats. For now, the only possible value 31708 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 31709 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be used to 31710 * collect the information to be translated in the view. The {@code requestsCollector} only 31711 * accepts one request; an IllegalStateException is thrown if more than one 31712 * {@link ViewTranslationRequest} is submitted to it. The {@link AutofillId} must be set on the 31713 * {@link ViewTranslationRequest}. 31714 */ onCreateViewTranslationRequest(@onNull @ataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)31715 public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, 31716 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 31717 } 31718 31719 /** 31720 * Collects {@link ViewTranslationRequest}s which represents the content to be translated 31721 * for the virtual views in the host view. This is called if this view returned a virtual 31722 * view structure from {@link #onProvideContentCaptureStructure} and the system determined that 31723 * those virtual views were relevant for translation. 31724 * 31725 * <p>The default implementation does nothing.</p> 31726 * 31727 * @param virtualIds the virtual view ids which represents the virtual views in the host 31728 * view. 31729 * @param supportedFormats the supported translation formats. For now, the only possible value 31730 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 31731 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called 31732 * multiple times to collect the information to be translated in the host view. One 31733 * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must 31734 * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this 31735 * Consumer after the method returns. 31736 */ 31737 @SuppressLint("NullableCollection") onCreateVirtualViewTranslationRequests(@onNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)31738 public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, 31739 @NonNull @DataFormat int[] supportedFormats, 31740 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 31741 // no-op 31742 } 31743 31744 /** 31745 * Returns a {@link ViewTranslationCallback} that is used to display the translated information 31746 * or {@code null} if this View doesn't support translation. 31747 * 31748 * @hide 31749 */ 31750 @Nullable getViewTranslationCallback()31751 public ViewTranslationCallback getViewTranslationCallback() { 31752 return mViewTranslationCallback; 31753 } 31754 31755 /** 31756 * Sets a {@link ViewTranslationCallback} that is used to display/hide the translated 31757 * information. Developers can provide the customized implementation for show/hide translated 31758 * information. 31759 * 31760 * @param callback a {@link ViewTranslationCallback} that is used to control how to display the 31761 * translated information 31762 */ setViewTranslationCallback(@onNull ViewTranslationCallback callback)31763 public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { 31764 mViewTranslationCallback = callback; 31765 } 31766 31767 /** 31768 * Clear the {@link ViewTranslationCallback} from this view. 31769 */ clearViewTranslationCallback()31770 public void clearViewTranslationCallback() { 31771 mViewTranslationCallback = null; 31772 } 31773 31774 /** 31775 * Returns the {@link ViewTranslationResponse} associated with this view. The response will be 31776 * set when the translation is done then {@link #onViewTranslationResponse} is called. The 31777 * {@link ViewTranslationCallback} can use to get {@link ViewTranslationResponse} to display the 31778 * translated information. 31779 * 31780 * @return a {@link ViewTranslationResponse} that contains the translated information associated 31781 * with this view or {@code null} if this View doesn't have the translation. 31782 */ 31783 @Nullable getViewTranslationResponse()31784 public ViewTranslationResponse getViewTranslationResponse() { 31785 return mViewTranslationResponse; 31786 } 31787 31788 /** 31789 * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated 31790 * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that 31791 * the {@link ViewTranslationResponse} can be used to display the translation when the system 31792 * calls {@link ViewTranslationCallback#onShowTranslation}. 31793 * 31794 * <p> The default implementation will set the ViewTranslationResponse that can be get from 31795 * {@link View#getViewTranslationResponse}. </p> 31796 * 31797 * @param response a {@link ViewTranslationResponse} that contains the translated information 31798 * which can be shown in the view. 31799 */ onViewTranslationResponse(@onNull ViewTranslationResponse response)31800 public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { 31801 mViewTranslationResponse = response; 31802 } 31803 31804 /** 31805 * Clears the ViewTranslationResponse stored by the default implementation of {@link 31806 * #onViewTranslationResponse}. 31807 * 31808 * @hide 31809 */ clearViewTranslationResponse()31810 public void clearViewTranslationResponse() { 31811 mViewTranslationResponse = null; 31812 } 31813 31814 /** 31815 * Called when the content from {@link View#onCreateVirtualViewTranslationRequests} had been 31816 * translated by the TranslationService. 31817 * 31818 * <p> The default implementation does nothing.</p> 31819 * 31820 * @param response a {@link ViewTranslationResponse} SparseArray for the request that send by 31821 * {@link View#onCreateVirtualViewTranslationRequests} that contains the translated information 31822 * which can be shown in the view. The key of SparseArray is the virtual child ids. 31823 */ onVirtualViewTranslationResponses( @onNull LongSparseArray<ViewTranslationResponse> response)31824 public void onVirtualViewTranslationResponses( 31825 @NonNull LongSparseArray<ViewTranslationResponse> response) { 31826 // no-op 31827 } 31828 31829 /** 31830 * Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing 31831 * the hierarchy when the app requests ui translation. Typically, this method should only be 31832 * overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other 31833 * classes should override {@link View#onCreateViewTranslationRequest} for normal view or 31834 * override {@link View#onVirtualViewTranslationResponses} for view contains virtual children. 31835 * When requested to start the ui translation, the system will call this method to traverse the 31836 * view hierarchy to collect {@link ViewTranslationRequest}s and create a 31837 * {@link android.view.translation.Translator} to translate the requests. All the 31838 * {@link ViewTranslationRequest}s must be added when the traversal is done. 31839 * 31840 * <p> The default implementation calls {@link View#onCreateViewTranslationRequest} for normal 31841 * view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual 31842 * children to build {@link ViewTranslationRequest} if the view should be translated. 31843 * The view is marked as having {@link #setHasTransientState(boolean) transient state} so that 31844 * recycling of views doesn't prevent the system from attaching the response to it. Therefore, 31845 * if overriding this method, you should set or reset the transient state. </p> 31846 * 31847 * @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or 31848 * {@code null} if the view doesn't have virtual child that should be translated. The virtual 31849 * child ids are the same virtual ids provided by ContentCapture. 31850 * @param supportedFormats the supported translation formats. For now, the only possible value 31851 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 31852 * @param capability a {@link TranslationCapability} that holds translation capability. 31853 * information, e.g. source spec, target spec. 31854 * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose. 31855 */ dispatchCreateViewTranslationRequest(@onNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests)31856 public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, 31857 @NonNull @DataFormat int[] supportedFormats, 31858 @NonNull TranslationCapability capability, 31859 @NonNull List<ViewTranslationRequest> requests) { 31860 AutofillId autofillId = getAutofillId(); 31861 if (viewIds.containsKey(autofillId)) { 31862 if (viewIds.get(autofillId) == null) { 31863 // TODO: avoiding the allocation per view 31864 onCreateViewTranslationRequest(supportedFormats, 31865 new ViewTranslationRequestConsumer(requests)); 31866 } else { 31867 onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, 31868 request -> { 31869 requests.add(request); 31870 }); 31871 } 31872 } 31873 } 31874 31875 private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { 31876 private final List<ViewTranslationRequest> mRequests; 31877 private boolean mCalled; 31878 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests)31879 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { 31880 mRequests = requests; 31881 } 31882 31883 @Override accept(ViewTranslationRequest request)31884 public void accept(ViewTranslationRequest request) { 31885 if (mCalled) { 31886 throw new IllegalStateException("The translation Consumer is not reusable."); 31887 } 31888 mCalled = true; 31889 if (request != null && request.getKeys().size() > 0) { 31890 mRequests.add(request); 31891 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 31892 Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " 31893 + getAutofillId()); 31894 } 31895 setHasTransientState(true); 31896 setHasTranslationTransientState(true); 31897 } 31898 } 31899 } 31900 31901 /** 31902 * Called to generate a {@link DisplayHash} for this view. 31903 * 31904 * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of 31905 * the values returned from 31906 * {@link DisplayHashManager#getSupportedHashAlgorithms()} 31907 * @param bounds The bounds for the content within the View to generate the hash for. If 31908 * bounds are null, the entire View's bounds will be used. If empty, it will 31909 * invoke the callback 31910 * {@link DisplayHashResultCallback#onDisplayHashError} with error 31911 * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} 31912 * @param executor The executor that the callback should be invoked on. 31913 * @param callback The callback to handle the results of generating the display hash 31914 */ generateDisplayHash(@onNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback)31915 public void generateDisplayHash(@NonNull String hashAlgorithm, 31916 @Nullable Rect bounds, @NonNull Executor executor, 31917 @NonNull DisplayHashResultCallback callback) { 31918 IWindowSession session = getWindowSession(); 31919 if (session == null) { 31920 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 31921 return; 31922 } 31923 IWindow window = getWindow(); 31924 if (window == null) { 31925 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 31926 return; 31927 } 31928 31929 Rect visibleBounds = new Rect(); 31930 getGlobalVisibleRect(visibleBounds); 31931 31932 if (bounds != null && bounds.isEmpty()) { 31933 callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); 31934 return; 31935 } 31936 31937 if (bounds != null) { 31938 bounds.offset(visibleBounds.left, visibleBounds.top); 31939 visibleBounds.intersectUnchecked(bounds); 31940 } 31941 31942 if (visibleBounds.isEmpty()) { 31943 callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); 31944 return; 31945 } 31946 31947 RemoteCallback remoteCallback = new RemoteCallback(result -> 31948 executor.execute(() -> { 31949 DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH); 31950 int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, 31951 DISPLAY_HASH_ERROR_UNKNOWN); 31952 if (displayHash != null) { 31953 callback.onDisplayHashResult(displayHash); 31954 } else { 31955 callback.onDisplayHashError(errorCode); 31956 } 31957 })); 31958 31959 try { 31960 session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); 31961 } catch (RemoteException e) { 31962 Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); 31963 callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); 31964 } 31965 } 31966 31967 /** 31968 * The AttachedSurfaceControl itself is not a View, it is just the interface to the 31969 * windowing-system object that contains the entire view hierarchy. 31970 * For the root View of a given hierarchy see {@link #getRootView}. 31971 31972 * @return The {@link android.view.AttachedSurfaceControl} interface for this View. 31973 * This will only return a non-null value when called between {@link #onAttachedToWindow} 31974 * and {@link #onDetachedFromWindow}. 31975 */ getRootSurfaceControl()31976 public @Nullable AttachedSurfaceControl getRootSurfaceControl() { 31977 if (mAttachInfo != null) { 31978 return mAttachInfo.getRootSurfaceControl(); 31979 } 31980 return null; 31981 } 31982 } 31983