1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import static android.content.res.Resources.ID_NULL; 20 import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; 21 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 22 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; 23 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 24 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; 25 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; 26 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; 27 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; 28 29 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 30 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 31 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 32 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 33 34 import static java.lang.Math.max; 35 36 import android.animation.AnimatorInflater; 37 import android.animation.StateListAnimator; 38 import android.annotation.AttrRes; 39 import android.annotation.CallSuper; 40 import android.annotation.ColorInt; 41 import android.annotation.DrawableRes; 42 import android.annotation.FloatRange; 43 import android.annotation.IdRes; 44 import android.annotation.IntDef; 45 import android.annotation.IntRange; 46 import android.annotation.LayoutRes; 47 import android.annotation.NonNull; 48 import android.annotation.Nullable; 49 import android.annotation.Size; 50 import android.annotation.StyleRes; 51 import android.annotation.SuppressLint; 52 import android.annotation.TestApi; 53 import android.annotation.UiContext; 54 import android.annotation.UiThread; 55 import android.compat.annotation.UnsupportedAppUsage; 56 import android.content.AutofillOptions; 57 import android.content.ClipData; 58 import android.content.ClipDescription; 59 import android.content.Context; 60 import android.content.ContextWrapper; 61 import android.content.Intent; 62 import android.content.res.ColorStateList; 63 import android.content.res.Configuration; 64 import android.content.res.Resources; 65 import android.content.res.TypedArray; 66 import android.graphics.Bitmap; 67 import android.graphics.BlendMode; 68 import android.graphics.Canvas; 69 import android.graphics.Color; 70 import android.graphics.Insets; 71 import android.graphics.Interpolator; 72 import android.graphics.LinearGradient; 73 import android.graphics.Matrix; 74 import android.graphics.Outline; 75 import android.graphics.Paint; 76 import android.graphics.PixelFormat; 77 import android.graphics.Point; 78 import android.graphics.PorterDuff; 79 import android.graphics.PorterDuffXfermode; 80 import android.graphics.RecordingCanvas; 81 import android.graphics.Rect; 82 import android.graphics.RectF; 83 import android.graphics.Region; 84 import android.graphics.RenderEffect; 85 import android.graphics.RenderNode; 86 import android.graphics.Shader; 87 import android.graphics.drawable.ColorDrawable; 88 import android.graphics.drawable.Drawable; 89 import android.graphics.drawable.GradientDrawable; 90 import android.hardware.display.DisplayManagerGlobal; 91 import android.net.Uri; 92 import android.os.Build; 93 import android.os.Bundle; 94 import android.os.Handler; 95 import android.os.IBinder; 96 import android.os.Message; 97 import android.os.Parcel; 98 import android.os.Parcelable; 99 import android.os.RemoteCallback; 100 import android.os.RemoteException; 101 import android.os.SystemClock; 102 import android.os.Trace; 103 import android.sysprop.DisplayProperties; 104 import android.text.InputType; 105 import android.text.TextUtils; 106 import android.util.AttributeSet; 107 import android.util.FloatProperty; 108 import android.util.LayoutDirection; 109 import android.util.Log; 110 import android.util.LongSparseArray; 111 import android.util.LongSparseLongArray; 112 import android.util.Pair; 113 import android.util.Pools.SynchronizedPool; 114 import android.util.Property; 115 import android.util.SparseArray; 116 import android.util.SparseIntArray; 117 import android.util.StateSet; 118 import android.util.SuperNotCalledException; 119 import android.util.TypedValue; 120 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 121 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 122 import android.view.AccessibilityIterators.TextSegmentIterator; 123 import android.view.AccessibilityIterators.WordTextSegmentIterator; 124 import android.view.ContextMenu.ContextMenuInfo; 125 import android.view.InputDevice.InputSourceClass; 126 import android.view.Window.OnContentApplyWindowInsetsListener; 127 import android.view.WindowInsets.Type; 128 import android.view.WindowInsetsAnimation.Bounds; 129 import android.view.WindowManager.LayoutParams; 130 import android.view.accessibility.AccessibilityEvent; 131 import android.view.accessibility.AccessibilityEventSource; 132 import android.view.accessibility.AccessibilityManager; 133 import android.view.accessibility.AccessibilityNodeIdManager; 134 import android.view.accessibility.AccessibilityNodeInfo; 135 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 136 import android.view.accessibility.AccessibilityNodeProvider; 137 import android.view.accessibility.AccessibilityWindowInfo; 138 import android.view.animation.Animation; 139 import android.view.animation.AnimationUtils; 140 import android.view.animation.Transformation; 141 import android.view.autofill.AutofillId; 142 import android.view.autofill.AutofillManager; 143 import android.view.autofill.AutofillValue; 144 import android.view.contentcapture.ContentCaptureContext; 145 import android.view.contentcapture.ContentCaptureManager; 146 import android.view.contentcapture.ContentCaptureSession; 147 import android.view.displayhash.DisplayHash; 148 import android.view.displayhash.DisplayHashManager; 149 import android.view.displayhash.DisplayHashResultCallback; 150 import android.view.inputmethod.EditorInfo; 151 import android.view.inputmethod.InputConnection; 152 import android.view.inspector.InspectableProperty; 153 import android.view.inspector.InspectableProperty.EnumEntry; 154 import android.view.inspector.InspectableProperty.FlagEntry; 155 import android.view.translation.TranslationCapability; 156 import android.view.translation.TranslationSpec.DataFormat; 157 import android.view.translation.ViewTranslationCallback; 158 import android.view.translation.ViewTranslationRequest; 159 import android.view.translation.ViewTranslationResponse; 160 import android.widget.Checkable; 161 import android.widget.FrameLayout; 162 import android.widget.ScrollBarDrawable; 163 164 import com.android.internal.R; 165 import com.android.internal.util.ArrayUtils; 166 import com.android.internal.util.FrameworkStatsLog; 167 import com.android.internal.util.Preconditions; 168 import com.android.internal.view.ScrollCaptureInternal; 169 import com.android.internal.view.TooltipPopup; 170 import com.android.internal.view.menu.MenuBuilder; 171 import com.android.internal.widget.ScrollBarUtils; 172 173 import com.google.android.collect.Lists; 174 import com.google.android.collect.Maps; 175 176 import java.io.PrintWriter; 177 import java.lang.annotation.Retention; 178 import java.lang.annotation.RetentionPolicy; 179 import java.lang.ref.WeakReference; 180 import java.lang.reflect.Field; 181 import java.lang.reflect.InvocationTargetException; 182 import java.lang.reflect.Method; 183 import java.lang.reflect.Modifier; 184 import java.util.ArrayList; 185 import java.util.Arrays; 186 import java.util.Calendar; 187 import java.util.Collection; 188 import java.util.Collections; 189 import java.util.HashMap; 190 import java.util.List; 191 import java.util.Locale; 192 import java.util.Map; 193 import java.util.concurrent.CopyOnWriteArrayList; 194 import java.util.concurrent.Executor; 195 import java.util.concurrent.atomic.AtomicInteger; 196 import java.util.function.Consumer; 197 import java.util.function.Predicate; 198 199 /** 200 * <p> 201 * This class represents the basic building block for user interface components. A View 202 * occupies a rectangular area on the screen and is responsible for drawing and 203 * event handling. View is the base class for <em>widgets</em>, which are 204 * used to create interactive UI components (buttons, text fields, etc.). The 205 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 206 * are invisible containers that hold other Views (or other ViewGroups) and define 207 * their layout properties. 208 * </p> 209 * 210 * <div class="special reference"> 211 * <h3>Developer Guides</h3> 212 * <p>For information about using this class to develop your application's user interface, 213 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 214 * </div> 215 * 216 * <a name="Using"></a> 217 * <h3>Using Views</h3> 218 * <p> 219 * All of the views in a window are arranged in a single tree. You can add views 220 * either from code or by specifying a tree of views in one or more XML layout 221 * files. There are many specialized subclasses of views that act as controls or 222 * are capable of displaying text, images, or other content. 223 * </p> 224 * <p> 225 * Once you have created a tree of views, there are typically a few types of 226 * common operations you may wish to perform: 227 * <ul> 228 * <li><strong>Set properties:</strong> for example setting the text of a 229 * {@link android.widget.TextView}. The available properties and the methods 230 * that set them will vary among the different subclasses of views. Note that 231 * properties that are known at build time can be set in the XML layout 232 * files.</li> 233 * <li><strong>Set focus:</strong> The framework will handle moving focus in 234 * response to user input. To force focus to a specific view, call 235 * {@link #requestFocus}.</li> 236 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 237 * that will be notified when something interesting happens to the view. For 238 * example, all views will let you set a listener to be notified when the view 239 * gains or loses focus. You can register such a listener using 240 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 241 * Other view subclasses offer more specialized listeners. For example, a Button 242 * exposes a listener to notify clients when the button is clicked.</li> 243 * <li><strong>Set visibility:</strong> You can hide or show views using 244 * {@link #setVisibility(int)}.</li> 245 * </ul> 246 * </p> 247 * <p><em> 248 * Note: The Android framework is responsible for measuring, laying out and 249 * drawing views. You should not call methods that perform these actions on 250 * views yourself unless you are actually implementing a 251 * {@link android.view.ViewGroup}. 252 * </em></p> 253 * 254 * <a name="Lifecycle"></a> 255 * <h3>Implementing a Custom View</h3> 256 * 257 * <p> 258 * To implement a custom view, you will usually begin by providing overrides for 259 * some of the standard methods that the framework calls on all views. You do 260 * not need to override all of these methods. In fact, you can start by just 261 * overriding {@link #onDraw(android.graphics.Canvas)}. 262 * <table border="2" width="85%" align="center" cellpadding="5"> 263 * <thead> 264 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 265 * </thead> 266 * 267 * <tbody> 268 * <tr> 269 * <td rowspan="2">Creation</td> 270 * <td>Constructors</td> 271 * <td>There is a form of the constructor that are called when the view 272 * is created from code and a form that is called when the view is 273 * inflated from a layout file. The second form should parse and apply 274 * any attributes defined in the layout file. 275 * </td> 276 * </tr> 277 * <tr> 278 * <td><code>{@link #onFinishInflate()}</code></td> 279 * <td>Called after a view and all of its children has been inflated 280 * from XML.</td> 281 * </tr> 282 * 283 * <tr> 284 * <td rowspan="3">Layout</td> 285 * <td><code>{@link #onMeasure(int, int)}</code></td> 286 * <td>Called to determine the size requirements for this view and all 287 * of its children. 288 * </td> 289 * </tr> 290 * <tr> 291 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 292 * <td>Called when this view should assign a size and position to all 293 * of its children. 294 * </td> 295 * </tr> 296 * <tr> 297 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 298 * <td>Called when the size of this view has changed. 299 * </td> 300 * </tr> 301 * 302 * <tr> 303 * <td>Drawing</td> 304 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 305 * <td>Called when the view should render its content. 306 * </td> 307 * </tr> 308 * 309 * <tr> 310 * <td rowspan="4">Event processing</td> 311 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 312 * <td>Called when a new hardware key event occurs. 313 * </td> 314 * </tr> 315 * <tr> 316 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 317 * <td>Called when a hardware key up event occurs. 318 * </td> 319 * </tr> 320 * <tr> 321 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 322 * <td>Called when a trackball motion event occurs. 323 * </td> 324 * </tr> 325 * <tr> 326 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 327 * <td>Called when a touch screen motion event occurs. 328 * </td> 329 * </tr> 330 * 331 * <tr> 332 * <td rowspan="2">Focus</td> 333 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 334 * <td>Called when the view gains or loses focus. 335 * </td> 336 * </tr> 337 * 338 * <tr> 339 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 340 * <td>Called when the window containing the view gains or loses focus. 341 * </td> 342 * </tr> 343 * 344 * <tr> 345 * <td rowspan="3">Attaching</td> 346 * <td><code>{@link #onAttachedToWindow()}</code></td> 347 * <td>Called when the view is attached to a window. 348 * </td> 349 * </tr> 350 * 351 * <tr> 352 * <td><code>{@link #onDetachedFromWindow}</code></td> 353 * <td>Called when the view is detached from its window. 354 * </td> 355 * </tr> 356 * 357 * <tr> 358 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 359 * <td>Called when the visibility of the window containing the view 360 * has changed. 361 * </td> 362 * </tr> 363 * </tbody> 364 * 365 * </table> 366 * </p> 367 * 368 * <a name="IDs"></a> 369 * <h3>IDs</h3> 370 * Views may have an integer id associated with them. These ids are typically 371 * assigned in the layout XML files, and are used to find specific views within 372 * the view tree. A common pattern is to: 373 * <ul> 374 * <li>Define a Button in the layout file and assign it a unique ID. 375 * <pre> 376 * <Button 377 * android:id="@+id/my_button" 378 * android:layout_width="wrap_content" 379 * android:layout_height="wrap_content" 380 * android:text="@string/my_button_text"/> 381 * </pre></li> 382 * <li>From the onCreate method of an Activity, find the Button 383 * <pre class="prettyprint"> 384 * Button myButton = findViewById(R.id.my_button); 385 * </pre></li> 386 * </ul> 387 * <p> 388 * View IDs need not be unique throughout the tree, but it is good practice to 389 * ensure that they are at least unique within the part of the tree you are 390 * searching. 391 * </p> 392 * 393 * <a name="Position"></a> 394 * <h3>Position</h3> 395 * <p> 396 * The geometry of a view is that of a rectangle. A view has a location, 397 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 398 * two dimensions, expressed as a width and a height. The unit for location 399 * and dimensions is the pixel. 400 * </p> 401 * 402 * <p> 403 * It is possible to retrieve the location of a view by invoking the methods 404 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 405 * coordinate of the rectangle representing the view. The latter returns the 406 * top, or Y, coordinate of the rectangle representing the view. These methods 407 * both return the location of the view relative to its parent. For instance, 408 * when getLeft() returns 20, that means the view is located 20 pixels to the 409 * right of the left edge of its direct parent. 410 * </p> 411 * 412 * <p> 413 * In addition, several convenience methods are offered to avoid unnecessary 414 * computations, namely {@link #getRight()} and {@link #getBottom()}. 415 * These methods return the coordinates of the right and bottom edges of the 416 * rectangle representing the view. For instance, calling {@link #getRight()} 417 * is similar to the following computation: <code>getLeft() + getWidth()</code> 418 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 419 * </p> 420 * 421 * <a name="SizePaddingMargins"></a> 422 * <h3>Size, padding and margins</h3> 423 * <p> 424 * The size of a view is expressed with a width and a height. A view actually 425 * possess two pairs of width and height values. 426 * </p> 427 * 428 * <p> 429 * The first pair is known as <em>measured width</em> and 430 * <em>measured height</em>. These dimensions define how big a view wants to be 431 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 432 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 433 * and {@link #getMeasuredHeight()}. 434 * </p> 435 * 436 * <p> 437 * The second pair is simply known as <em>width</em> and <em>height</em>, or 438 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 439 * dimensions define the actual size of the view on screen, at drawing time and 440 * after layout. These values may, but do not have to, be different from the 441 * measured width and height. The width and height can be obtained by calling 442 * {@link #getWidth()} and {@link #getHeight()}. 443 * </p> 444 * 445 * <p> 446 * To measure its dimensions, a view takes into account its padding. The padding 447 * is expressed in pixels for the left, top, right and bottom parts of the view. 448 * Padding can be used to offset the content of the view by a specific amount of 449 * pixels. For instance, a left padding of 2 will push the view's content by 450 * 2 pixels to the right of the left edge. Padding can be set using the 451 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 452 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 453 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 454 * {@link #getPaddingEnd()}. 455 * </p> 456 * 457 * <p> 458 * Even though a view can define a padding, it does not provide any support for 459 * margins. However, view groups provide such a support. Refer to 460 * {@link android.view.ViewGroup} and 461 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 462 * </p> 463 * 464 * <a name="Layout"></a> 465 * <h3>Layout</h3> 466 * <p> 467 * Layout is a two pass process: a measure pass and a layout pass. The measuring 468 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 469 * of the view tree. Each view pushes dimension specifications down the tree 470 * during the recursion. At the end of the measure pass, every view has stored 471 * its measurements. The second pass happens in 472 * {@link #layout(int,int,int,int)} and is also top-down. During 473 * this pass each parent is responsible for positioning all of its children 474 * using the sizes computed in the measure pass. 475 * </p> 476 * 477 * <p> 478 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 479 * {@link #getMeasuredHeight()} values must be set, along with those for all of 480 * that view's descendants. A view's measured width and measured height values 481 * must respect the constraints imposed by the view's parents. This guarantees 482 * that at the end of the measure pass, all parents accept all of their 483 * children's measurements. A parent view may call measure() more than once on 484 * its children. For example, the parent may measure each child once with 485 * unspecified dimensions to find out how big they want to be, then call 486 * measure() on them again with actual numbers if the sum of all the children's 487 * unconstrained sizes is too big or too small. 488 * </p> 489 * 490 * <p> 491 * The measure pass uses two classes to communicate dimensions. The 492 * {@link MeasureSpec} class is used by views to tell their parents how they 493 * want to be measured and positioned. The base LayoutParams class just 494 * describes how big the view wants to be for both width and height. For each 495 * dimension, it can specify one of: 496 * <ul> 497 * <li> an exact number 498 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 499 * (minus padding) 500 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 501 * enclose its content (plus padding). 502 * </ul> 503 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 504 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 505 * an X and Y value. 506 * </p> 507 * 508 * <p> 509 * MeasureSpecs are used to push requirements down the tree from parent to 510 * child. A MeasureSpec can be in one of three modes: 511 * <ul> 512 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 513 * of a child view. For example, a LinearLayout may call measure() on its child 514 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 515 * tall the child view wants to be given a width of 240 pixels. 516 * <li>EXACTLY: This is used by the parent to impose an exact size on the 517 * child. The child must use this size, and guarantee that all of its 518 * descendants will fit within this size. 519 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 520 * child. The child must guarantee that it and all of its descendants will fit 521 * within this size. 522 * </ul> 523 * </p> 524 * 525 * <p> 526 * To initiate a layout, call {@link #requestLayout}. This method is typically 527 * called by a view on itself when it believes that it can no longer fit within 528 * its current bounds. 529 * </p> 530 * 531 * <a name="Drawing"></a> 532 * <h3>Drawing</h3> 533 * <p> 534 * Drawing is handled by walking the tree and recording the drawing commands of 535 * any View that needs to update. After this, the drawing commands of the 536 * entire tree are issued to screen, clipped to the newly damaged area. 537 * </p> 538 * 539 * <p> 540 * The tree is largely recorded and drawn in order, with parents drawn before 541 * (i.e., behind) their children, with siblings drawn in the order they appear 542 * in the tree. If you set a background drawable for a View, then the View will 543 * draw it before calling back to its <code>onDraw()</code> method. The child 544 * drawing order can be overridden with 545 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 546 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 547 * </p> 548 * 549 * <p> 550 * To force a view to draw, call {@link #invalidate()}. 551 * </p> 552 * 553 * <a name="EventHandlingThreading"></a> 554 * <h3>Event Handling and Threading</h3> 555 * <p> 556 * The basic cycle of a view is as follows: 557 * <ol> 558 * <li>An event comes in and is dispatched to the appropriate view. The view 559 * handles the event and notifies any listeners.</li> 560 * <li>If in the course of processing the event, the view's bounds may need 561 * to be changed, the view will call {@link #requestLayout()}.</li> 562 * <li>Similarly, if in the course of processing the event the view's appearance 563 * may need to be changed, the view will call {@link #invalidate()}.</li> 564 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 565 * the framework will take care of measuring, laying out, and drawing the tree 566 * as appropriate.</li> 567 * </ol> 568 * </p> 569 * 570 * <p><em>Note: The entire view tree is single threaded. You must always be on 571 * the UI thread when calling any method on any view.</em> 572 * If you are doing work on other threads and want to update the state of a view 573 * from that thread, you should use a {@link Handler}. 574 * </p> 575 * 576 * <a name="FocusHandling"></a> 577 * <h3>Focus Handling</h3> 578 * <p> 579 * The framework will handle routine focus movement in response to user input. 580 * This includes changing the focus as views are removed or hidden, or as new 581 * views become available. Views indicate their willingness to take focus 582 * through the {@link #isFocusable} method. To change whether a view can take 583 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 584 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 585 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 586 * </p> 587 * <p> 588 * Focus movement is based on an algorithm which finds the nearest neighbor in a 589 * given direction. In rare cases, the default algorithm may not match the 590 * intended behavior of the developer. In these situations, you can provide 591 * explicit overrides by using these XML attributes in the layout file: 592 * <pre> 593 * nextFocusDown 594 * nextFocusLeft 595 * nextFocusRight 596 * nextFocusUp 597 * </pre> 598 * </p> 599 * 600 * 601 * <p> 602 * To get a particular view to take focus, call {@link #requestFocus()}. 603 * </p> 604 * 605 * <a name="TouchMode"></a> 606 * <h3>Touch Mode</h3> 607 * <p> 608 * When a user is navigating a user interface via directional keys such as a D-pad, it is 609 * necessary to give focus to actionable items such as buttons so the user can see 610 * what will take input. If the device has touch capabilities, however, and the user 611 * begins interacting with the interface by touching it, it is no longer necessary to 612 * always highlight, or give focus to, a particular view. This motivates a mode 613 * for interaction named 'touch mode'. 614 * </p> 615 * <p> 616 * For a touch capable device, once the user touches the screen, the device 617 * will enter touch mode. From this point onward, only views for which 618 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 619 * Other views that are touchable, like buttons, will not take focus when touched; they will 620 * only fire the on click listeners. 621 * </p> 622 * <p> 623 * Any time a user hits a directional key, such as a D-pad direction, the view device will 624 * exit touch mode, and find a view to take focus, so that the user may resume interacting 625 * with the user interface without touching the screen again. 626 * </p> 627 * <p> 628 * The touch mode state is maintained across {@link android.app.Activity}s. Call 629 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 630 * </p> 631 * 632 * <a name="Scrolling"></a> 633 * <h3>Scrolling</h3> 634 * <p> 635 * The framework provides basic support for views that wish to internally 636 * scroll their content. This includes keeping track of the X and Y scroll 637 * offset as well as mechanisms for drawing scrollbars. See 638 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 639 * {@link #awakenScrollBars()} for more details. 640 * </p> 641 * 642 * <a name="Tags"></a> 643 * <h3>Tags</h3> 644 * <p> 645 * Unlike IDs, tags are not used to identify views. Tags are essentially an 646 * extra piece of information that can be associated with a view. They are most 647 * often used as a convenience to store data related to views in the views 648 * themselves rather than by putting them in a separate structure. 649 * </p> 650 * <p> 651 * Tags may be specified with character sequence values in layout XML as either 652 * a single tag using the {@link android.R.styleable#View_tag android:tag} 653 * attribute or multiple tags using the {@code <tag>} child element: 654 * <pre> 655 * <View ... 656 * android:tag="@string/mytag_value" /> 657 * <View ...> 658 * <tag android:id="@+id/mytag" 659 * android:value="@string/mytag_value" /> 660 * </View> 661 * </pre> 662 * </p> 663 * <p> 664 * Tags may also be specified with arbitrary objects from code using 665 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 666 * </p> 667 * 668 * <a name="Themes"></a> 669 * <h3>Themes</h3> 670 * <p> 671 * By default, Views are created using the theme of the Context object supplied 672 * to their constructor; however, a different theme may be specified by using 673 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 674 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 675 * code. 676 * </p> 677 * <p> 678 * When the {@link android.R.styleable#View_theme android:theme} attribute is 679 * used in XML, the specified theme is applied on top of the inflation 680 * context's theme (see {@link LayoutInflater}) and used for the view itself as 681 * well as any child elements. 682 * </p> 683 * <p> 684 * In the following example, both views will be created using the Material dark 685 * color scheme; however, because an overlay theme is used which only defines a 686 * subset of attributes, the value of 687 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 688 * the inflation context's theme (e.g. the Activity theme) will be preserved. 689 * <pre> 690 * <LinearLayout 691 * ... 692 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 693 * <View ...> 694 * </LinearLayout> 695 * </pre> 696 * </p> 697 * 698 * <a name="Properties"></a> 699 * <h3>Properties</h3> 700 * <p> 701 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 702 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 703 * available both in the {@link Property} form as well as in similarly-named setter/getter 704 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 705 * be used to set persistent state associated with these rendering-related properties on the view. 706 * The properties and methods can also be used in conjunction with 707 * {@link android.animation.Animator Animator}-based animations, described more in the 708 * <a href="#Animation">Animation</a> section. 709 * </p> 710 * 711 * <a name="Animation"></a> 712 * <h3>Animation</h3> 713 * <p> 714 * Starting with Android 3.0, the preferred way of animating views is to use the 715 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 716 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 717 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 718 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 719 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 720 * makes animating these View properties particularly easy and efficient. 721 * </p> 722 * <p> 723 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 724 * You can attach an {@link Animation} object to a view using 725 * {@link #setAnimation(Animation)} or 726 * {@link #startAnimation(Animation)}. The animation can alter the scale, 727 * rotation, translation and alpha of a view over time. If the animation is 728 * attached to a view that has children, the animation will affect the entire 729 * subtree rooted by that node. When an animation is started, the framework will 730 * take care of redrawing the appropriate views until the animation completes. 731 * </p> 732 * 733 * <a name="Security"></a> 734 * <h3>Security</h3> 735 * <p> 736 * Sometimes it is essential that an application be able to verify that an action 737 * is being performed with the full knowledge and consent of the user, such as 738 * granting a permission request, making a purchase or clicking on an advertisement. 739 * Unfortunately, a malicious application could try to spoof the user into 740 * performing these actions, unaware, by concealing the intended purpose of the view. 741 * As a remedy, the framework offers a touch filtering mechanism that can be used to 742 * improve the security of views that provide access to sensitive functionality. 743 * </p><p> 744 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 745 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 746 * will discard touches that are received whenever the view's window is obscured by 747 * another visible window. As a result, the view will not receive touches whenever a 748 * toast, dialog or other window appears above the view's window. 749 * </p><p> 750 * For more fine-grained control over security, consider overriding the 751 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 752 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 753 * </p> 754 * 755 * @attr ref android.R.styleable#View_accessibilityHeading 756 * @attr ref android.R.styleable#View_allowClickWhenDisabled 757 * @attr ref android.R.styleable#View_alpha 758 * @attr ref android.R.styleable#View_background 759 * @attr ref android.R.styleable#View_clickable 760 * @attr ref android.R.styleable#View_clipToOutline 761 * @attr ref android.R.styleable#View_contentDescription 762 * @attr ref android.R.styleable#View_drawingCacheQuality 763 * @attr ref android.R.styleable#View_duplicateParentState 764 * @attr ref android.R.styleable#View_id 765 * @attr ref android.R.styleable#View_requiresFadingEdge 766 * @attr ref android.R.styleable#View_fadeScrollbars 767 * @attr ref android.R.styleable#View_fadingEdgeLength 768 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 769 * @attr ref android.R.styleable#View_fitsSystemWindows 770 * @attr ref android.R.styleable#View_isScrollContainer 771 * @attr ref android.R.styleable#View_focusable 772 * @attr ref android.R.styleable#View_focusableInTouchMode 773 * @attr ref android.R.styleable#View_focusedByDefault 774 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 775 * @attr ref android.R.styleable#View_keepScreenOn 776 * @attr ref android.R.styleable#View_keyboardNavigationCluster 777 * @attr ref android.R.styleable#View_layerType 778 * @attr ref android.R.styleable#View_layoutDirection 779 * @attr ref android.R.styleable#View_longClickable 780 * @attr ref android.R.styleable#View_minHeight 781 * @attr ref android.R.styleable#View_minWidth 782 * @attr ref android.R.styleable#View_nextClusterForward 783 * @attr ref android.R.styleable#View_nextFocusDown 784 * @attr ref android.R.styleable#View_nextFocusLeft 785 * @attr ref android.R.styleable#View_nextFocusRight 786 * @attr ref android.R.styleable#View_nextFocusUp 787 * @attr ref android.R.styleable#View_onClick 788 * @attr ref android.R.styleable#View_outlineSpotShadowColor 789 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 790 * @attr ref android.R.styleable#View_padding 791 * @attr ref android.R.styleable#View_paddingHorizontal 792 * @attr ref android.R.styleable#View_paddingVertical 793 * @attr ref android.R.styleable#View_paddingBottom 794 * @attr ref android.R.styleable#View_paddingLeft 795 * @attr ref android.R.styleable#View_paddingRight 796 * @attr ref android.R.styleable#View_paddingTop 797 * @attr ref android.R.styleable#View_paddingStart 798 * @attr ref android.R.styleable#View_paddingEnd 799 * @attr ref android.R.styleable#View_saveEnabled 800 * @attr ref android.R.styleable#View_rotation 801 * @attr ref android.R.styleable#View_rotationX 802 * @attr ref android.R.styleable#View_rotationY 803 * @attr ref android.R.styleable#View_scaleX 804 * @attr ref android.R.styleable#View_scaleY 805 * @attr ref android.R.styleable#View_scrollX 806 * @attr ref android.R.styleable#View_scrollY 807 * @attr ref android.R.styleable#View_scrollbarSize 808 * @attr ref android.R.styleable#View_scrollbarStyle 809 * @attr ref android.R.styleable#View_scrollbars 810 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 811 * @attr ref android.R.styleable#View_scrollbarFadeDuration 812 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 813 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 814 * @attr ref android.R.styleable#View_scrollbarThumbVertical 815 * @attr ref android.R.styleable#View_scrollbarTrackVertical 816 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 817 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 818 * @attr ref android.R.styleable#View_stateListAnimator 819 * @attr ref android.R.styleable#View_transitionName 820 * @attr ref android.R.styleable#View_soundEffectsEnabled 821 * @attr ref android.R.styleable#View_tag 822 * @attr ref android.R.styleable#View_textAlignment 823 * @attr ref android.R.styleable#View_textDirection 824 * @attr ref android.R.styleable#View_transformPivotX 825 * @attr ref android.R.styleable#View_transformPivotY 826 * @attr ref android.R.styleable#View_translationX 827 * @attr ref android.R.styleable#View_translationY 828 * @attr ref android.R.styleable#View_translationZ 829 * @attr ref android.R.styleable#View_visibility 830 * @attr ref android.R.styleable#View_theme 831 * 832 * @see android.view.ViewGroup 833 */ 834 @UiThread 835 public class View implements Drawable.Callback, KeyEvent.Callback, 836 AccessibilityEventSource { 837 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 838 private static final boolean DBG = false; 839 840 /** @hide */ 841 public static boolean DEBUG_DRAW = false; 842 843 /** 844 * The logging tag used by this class with android.util.Log. 845 */ 846 protected static final String VIEW_LOG_TAG = "View"; 847 848 /** 849 * The logging tag used by this class when logging verbose, autofill-related messages. 850 */ 851 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 852 // set if a session is not started. 853 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 854 855 /** 856 * The logging tag used by this class when logging content capture-related messages. 857 */ 858 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 859 860 private static final boolean DEBUG_CONTENT_CAPTURE = false; 861 862 /** 863 * When set to true, this view will save its attribute data. 864 * 865 * @hide 866 */ 867 public static boolean sDebugViewAttributes = false; 868 869 /** 870 * When set to this application package view will save its attribute data. 871 * 872 * @hide 873 */ 874 public static String sDebugViewAttributesApplicationPackage; 875 876 /** 877 * Used to mark a View that has no ID. 878 */ 879 public static final int NO_ID = -1; 880 881 /** 882 * Last ID that is given to Views that are no part of activities. 883 * 884 * {@hide} 885 */ 886 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 887 888 /** 889 * Attribute to find the autofilled highlight 890 * 891 * @see #getAutofilledDrawable() 892 */ 893 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 894 new int[]{android.R.attr.autofilledHighlight}; 895 896 /** 897 * Signals that compatibility booleans have been initialized according to 898 * target SDK versions. 899 */ 900 private static boolean sCompatibilityDone = false; 901 902 /** 903 * Use the old (broken) way of building MeasureSpecs. 904 */ 905 private static boolean sUseBrokenMakeMeasureSpec = false; 906 907 /** 908 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 909 */ 910 static boolean sUseZeroUnspecifiedMeasureSpec = false; 911 912 /** 913 * Ignore any optimizations using the measure cache. 914 */ 915 private static boolean sIgnoreMeasureCache = false; 916 917 /** 918 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 919 */ 920 private static boolean sAlwaysRemeasureExactly = false; 921 922 /** 923 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 924 * without throwing 925 */ 926 static boolean sTextureViewIgnoresDrawableSetters = false; 927 928 /** 929 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 930 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 931 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 932 * check is implemented for backwards compatibility. 933 * 934 * {@hide} 935 */ 936 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 937 938 /** 939 * Prior to N, when drag enters into child of a view that has already received an 940 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 941 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 942 * false from its event handler for these events. 943 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 944 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 945 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 946 */ 947 static boolean sCascadedDragDrop; 948 949 /** 950 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 951 * to determine things like whether or not to permit item click events. We can't break 952 * apps that do this just because more things (clickable things) are now auto-focusable 953 * and they would get different results, so give old behavior to old apps. 954 */ 955 static boolean sHasFocusableExcludeAutoFocusable; 956 957 /** 958 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 959 * made focusable by default. As a result, apps could (incorrectly) change the clickable 960 * setting of views off the UI thread. Now that clickable can effect the focusable state, 961 * changing the clickable attribute off the UI thread will cause an exception (since changing 962 * the focusable state checks). In order to prevent apps from crashing, we will handle this 963 * specific case and just not notify parents on new focusables resulting from marking views 964 * clickable from outside the UI thread. 965 */ 966 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 967 968 /** 969 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 970 * Float.NaN. If the app is targetting P or later then passing these values will result in an 971 * exception being thrown. If the app is targetting an earlier SDK version, then we will 972 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 973 * these bogus values. 974 */ 975 private static boolean sThrowOnInvalidFloatProperties; 976 977 /** 978 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 979 * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead. 980 */ 981 private static boolean sAcceptZeroSizeDragShadow; 982 983 /** 984 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 985 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 986 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 987 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 988 * thus, the hierarchical dispatching mechanism was hard to use for apps. 989 * <p> 990 * In order to make window inset dispatching work properly, we dispatch window insets 991 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 992 */ 993 static boolean sBrokenInsetsDispatch; 994 995 /** 996 * Prior to Q, calling 997 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 998 * did not call update the window format so the opacity of the background was not correctly 999 * applied to the window. Some applications rely on this misbehavior to work properly. 1000 * <p> 1001 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 1002 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 1003 * which updates the window format. 1004 * @hide 1005 */ 1006 protected static boolean sBrokenWindowBackground; 1007 1008 /** 1009 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 1010 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 1011 * calling {@link #requestLayout} when they need to relayout based on an insets change. 1012 */ 1013 static boolean sForceLayoutWhenInsetsChanged; 1014 1015 /** @hide */ 1016 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 1017 @Retention(RetentionPolicy.SOURCE) 1018 public @interface Focusable {} 1019 1020 /** 1021 * This view does not want keystrokes. 1022 * <p> 1023 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1024 * android:focusable}. 1025 */ 1026 public static final int NOT_FOCUSABLE = 0x00000000; 1027 1028 /** 1029 * This view wants keystrokes. 1030 * <p> 1031 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1032 * android:focusable}. 1033 */ 1034 public static final int FOCUSABLE = 0x00000001; 1035 1036 /** 1037 * This view determines focusability automatically. This is the default. 1038 * <p> 1039 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1040 * android:focusable}. 1041 */ 1042 public static final int FOCUSABLE_AUTO = 0x00000010; 1043 1044 /** 1045 * Mask for use with setFlags indicating bits used for focus. 1046 */ 1047 private static final int FOCUSABLE_MASK = 0x00000011; 1048 1049 /** 1050 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1051 */ 1052 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1053 1054 /** @hide */ 1055 @IntDef({VISIBLE, INVISIBLE, GONE}) 1056 @Retention(RetentionPolicy.SOURCE) 1057 public @interface Visibility {} 1058 1059 /** 1060 * This view is visible. 1061 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1062 * android:visibility}. 1063 */ 1064 public static final int VISIBLE = 0x00000000; 1065 1066 /** 1067 * This view is invisible, but it still takes up space for layout purposes. 1068 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1069 * android:visibility}. 1070 */ 1071 public static final int INVISIBLE = 0x00000004; 1072 1073 /** 1074 * This view is invisible, and it doesn't take any space for layout 1075 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1076 * android:visibility}. 1077 */ 1078 public static final int GONE = 0x00000008; 1079 1080 /** 1081 * Mask for use with setFlags indicating bits used for visibility. 1082 * {@hide} 1083 */ 1084 static final int VISIBILITY_MASK = 0x0000000C; 1085 1086 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1087 1088 /** 1089 * Hint indicating that this view can be autofilled with an email address. 1090 * 1091 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1092 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1093 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1094 * 1095 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1096 */ 1097 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1098 1099 /** 1100 * Hint indicating that this view can be autofilled with a user's real name. 1101 * 1102 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1103 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1104 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1105 * 1106 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1107 */ 1108 public static final String AUTOFILL_HINT_NAME = "name"; 1109 1110 /** 1111 * Hint indicating that this view can be autofilled with a username. 1112 * 1113 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1114 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1115 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1116 * 1117 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1118 */ 1119 public static final String AUTOFILL_HINT_USERNAME = "username"; 1120 1121 /** 1122 * Hint indicating that this view can be autofilled with a password. 1123 * 1124 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1125 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1126 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1127 * 1128 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1129 */ 1130 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1131 1132 /** 1133 * Hint indicating that this view can be autofilled with a phone number. 1134 * 1135 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1136 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1137 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1138 * 1139 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1140 */ 1141 public static final String AUTOFILL_HINT_PHONE = "phone"; 1142 1143 /** 1144 * Hint indicating that this view can be autofilled with a postal address. 1145 * 1146 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1147 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1148 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1149 * 1150 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1151 */ 1152 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1153 1154 /** 1155 * Hint indicating that this view can be autofilled with a postal code. 1156 * 1157 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1158 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1159 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1160 * 1161 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1162 */ 1163 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1164 1165 /** 1166 * Hint indicating that this view can be autofilled with a credit card number. 1167 * 1168 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1169 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1170 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1171 * 1172 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1173 */ 1174 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1175 1176 /** 1177 * Hint indicating that this view can be autofilled with a credit card security code. 1178 * 1179 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1180 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1181 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1182 * 1183 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1184 */ 1185 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1186 1187 /** 1188 * Hint indicating that this view can be autofilled with a credit card expiration date. 1189 * 1190 * <p>It should be used when the credit card expiration date is represented by just one view; 1191 * if it is represented by more than one (for example, one view for the month and another view 1192 * for the year), then each of these views should use the hint specific for the unit 1193 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1194 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1195 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1196 * 1197 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1198 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1199 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1200 * 1201 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1202 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1203 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1204 * the following options: 1205 * 1206 * <ul> 1207 * <li>{@code "04/2020"} 1208 * <li>{@code "4/2020"} 1209 * <li>{@code "2020/04"} 1210 * <li>{@code "2020/4"} 1211 * <li>{@code "April/2020"} 1212 * <li>{@code "Apr/2020"} 1213 * </ul> 1214 * 1215 * <p>You define a date autofill value for the view by overriding the following methods: 1216 * 1217 * <ol> 1218 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1219 * <li>{@link #getAutofillValue()} to return a 1220 * {@link AutofillValue#forDate(long) date autofillvalue}. 1221 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1222 * </ol> 1223 * 1224 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1225 */ 1226 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1227 "creditCardExpirationDate"; 1228 1229 /** 1230 * Hint indicating that this view can be autofilled with a credit card expiration month. 1231 * 1232 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1233 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1234 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1235 * 1236 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1237 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1238 * ambiguity when the autofill service provides a value for it. To understand why a 1239 * value can be ambiguous, consider "January", which could be represented as either of 1240 * 1241 * <ul> 1242 * <li>{@code "1"}: recommended way. 1243 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1244 * <li>{@code "January"}: full name, in English. 1245 * <li>{@code "jan"}: abbreviated name, in English. 1246 * <li>{@code "Janeiro"}: full name, in another language. 1247 * </ul> 1248 * 1249 * <p>Another recommended approach is to use a date autofill value - see 1250 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1251 * 1252 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1253 */ 1254 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1255 "creditCardExpirationMonth"; 1256 1257 /** 1258 * Hint indicating that this view can be autofilled with a credit card expiration year. 1259 * 1260 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1261 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1262 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1263 * 1264 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1265 */ 1266 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1267 "creditCardExpirationYear"; 1268 1269 /** 1270 * Hint indicating that this view can be autofilled with a credit card expiration day. 1271 * 1272 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1273 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1274 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1275 * 1276 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1277 */ 1278 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1279 1280 /** 1281 * Hints for the autofill services that describes the content of the view. 1282 */ 1283 private @Nullable String[] mAutofillHints; 1284 1285 /** 1286 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1287 */ 1288 private AutofillId mAutofillId; 1289 1290 /** @hide */ 1291 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1292 AUTOFILL_TYPE_NONE, 1293 AUTOFILL_TYPE_TEXT, 1294 AUTOFILL_TYPE_TOGGLE, 1295 AUTOFILL_TYPE_LIST, 1296 AUTOFILL_TYPE_DATE, 1297 }) 1298 @Retention(RetentionPolicy.SOURCE) 1299 public @interface AutofillType {} 1300 1301 /** 1302 * Autofill type for views that cannot be autofilled. 1303 * 1304 * <p>Typically used when the view is read-only; for example, a text label. 1305 * 1306 * @see #getAutofillType() 1307 */ 1308 public static final int AUTOFILL_TYPE_NONE = 0; 1309 1310 /** 1311 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1312 * 1313 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1314 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1315 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1316 * 1317 * @see #getAutofillType() 1318 */ 1319 public static final int AUTOFILL_TYPE_TEXT = 1; 1320 1321 /** 1322 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1323 * 1324 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1325 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1326 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1327 * 1328 * @see #getAutofillType() 1329 */ 1330 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1331 1332 /** 1333 * Autofill type for a selection list field, which is filled by an {@code int} 1334 * representing the element index inside the list (starting at {@code 0}). 1335 * 1336 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1337 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1338 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1339 * 1340 * <p>The available options in the selection list are typically provided by 1341 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1342 * 1343 * @see #getAutofillType() 1344 */ 1345 public static final int AUTOFILL_TYPE_LIST = 3; 1346 1347 /** 1348 * Autofill type for a field that contains a date, which is represented by a long representing 1349 * the number of milliseconds since the standard base time known as "the epoch", namely 1350 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1351 * 1352 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1353 * {@link AutofillValue#forDate(long)}, and the values passed to 1354 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1355 * 1356 * @see #getAutofillType() 1357 */ 1358 public static final int AUTOFILL_TYPE_DATE = 4; 1359 1360 1361 /** @hide */ 1362 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1363 IMPORTANT_FOR_AUTOFILL_AUTO, 1364 IMPORTANT_FOR_AUTOFILL_YES, 1365 IMPORTANT_FOR_AUTOFILL_NO, 1366 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1367 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1368 }) 1369 @Retention(RetentionPolicy.SOURCE) 1370 public @interface AutofillImportance {} 1371 1372 /** 1373 * Automatically determine whether a view is important for autofill. 1374 * 1375 * @see #isImportantForAutofill() 1376 * @see #setImportantForAutofill(int) 1377 */ 1378 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1379 1380 /** 1381 * The view is important for autofill, and its children (if any) will be traversed. 1382 * 1383 * @see #isImportantForAutofill() 1384 * @see #setImportantForAutofill(int) 1385 */ 1386 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1387 1388 /** 1389 * The view is not important for autofill, but its children (if any) will be traversed. 1390 * 1391 * @see #isImportantForAutofill() 1392 * @see #setImportantForAutofill(int) 1393 */ 1394 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1395 1396 /** 1397 * The view is important for autofill, but its children (if any) will not be traversed. 1398 * 1399 * @see #isImportantForAutofill() 1400 * @see #setImportantForAutofill(int) 1401 */ 1402 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1403 1404 /** 1405 * The view is not important for autofill, and its children (if any) will not be traversed. 1406 * 1407 * @see #isImportantForAutofill() 1408 * @see #setImportantForAutofill(int) 1409 */ 1410 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1411 1412 /** @hide */ 1413 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1414 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1415 }) 1416 @Retention(RetentionPolicy.SOURCE) 1417 public @interface AutofillFlags {} 1418 1419 /** 1420 * Flag requesting you to add views that are marked as not important for autofill 1421 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1422 */ 1423 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1424 1425 /** @hide */ 1426 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1427 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1428 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1429 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1430 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1431 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1432 }) 1433 @Retention(RetentionPolicy.SOURCE) 1434 public @interface ContentCaptureImportance {} 1435 1436 /** 1437 * Automatically determine whether a view is important for content capture. 1438 * 1439 * @see #isImportantForContentCapture() 1440 * @see #setImportantForContentCapture(int) 1441 */ 1442 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1443 1444 /** 1445 * The view is important for content capture, and its children (if any) will be traversed. 1446 * 1447 * @see #isImportantForContentCapture() 1448 * @see #setImportantForContentCapture(int) 1449 */ 1450 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1451 1452 /** 1453 * The view is not important for content capture, but its children (if any) will be traversed. 1454 * 1455 * @see #isImportantForContentCapture() 1456 * @see #setImportantForContentCapture(int) 1457 */ 1458 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1459 1460 /** 1461 * The view is important for content capture, but its children (if any) will not be traversed. 1462 * 1463 * @see #isImportantForContentCapture() 1464 * @see #setImportantForContentCapture(int) 1465 */ 1466 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1467 1468 /** 1469 * The view is not important for content capture, and its children (if any) will not be 1470 * traversed. 1471 * 1472 * @see #isImportantForContentCapture() 1473 * @see #setImportantForContentCapture(int) 1474 */ 1475 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1476 1477 /** {@hide} */ 1478 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1479 value = { 1480 SCROLL_CAPTURE_HINT_AUTO, 1481 SCROLL_CAPTURE_HINT_EXCLUDE, 1482 SCROLL_CAPTURE_HINT_INCLUDE, 1483 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1484 }) 1485 @Retention(RetentionPolicy.SOURCE) 1486 public @interface ScrollCaptureHint {} 1487 1488 /** 1489 * The content of this view will be considered for scroll capture if scrolling is possible. 1490 * 1491 * @see #getScrollCaptureHint() 1492 * @see #setScrollCaptureHint(int) 1493 */ 1494 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1495 1496 /** 1497 * Explicitly exclude this view as a potential scroll capture target. The system will not 1498 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1499 * takes precedence over. 1500 * 1501 * @see #getScrollCaptureHint() 1502 * @see #setScrollCaptureHint(int) 1503 */ 1504 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1505 1506 /** 1507 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1508 * capture target, this view will be prioritized before others without this flag. Mutually 1509 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1510 * 1511 * @see #getScrollCaptureHint() 1512 * @see #setScrollCaptureHint(int) 1513 */ 1514 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1515 1516 /** 1517 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1518 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1519 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1520 * 1521 * @see #getScrollCaptureHint() 1522 * @see #setScrollCaptureHint(int) 1523 */ 1524 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1525 1526 /** 1527 * This view is enabled. Interpretation varies by subclass. 1528 * Use with ENABLED_MASK when calling setFlags. 1529 * {@hide} 1530 */ 1531 static final int ENABLED = 0x00000000; 1532 1533 /** 1534 * This view is disabled. Interpretation varies by subclass. 1535 * Use with ENABLED_MASK when calling setFlags. 1536 * {@hide} 1537 */ 1538 static final int DISABLED = 0x00000020; 1539 1540 /** 1541 * Mask for use with setFlags indicating bits used for indicating whether 1542 * this view is enabled 1543 * {@hide} 1544 */ 1545 static final int ENABLED_MASK = 0x00000020; 1546 1547 /** 1548 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1549 * called and further optimizations will be performed. It is okay to have 1550 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1551 * {@hide} 1552 */ 1553 static final int WILL_NOT_DRAW = 0x00000080; 1554 1555 /** 1556 * Mask for use with setFlags indicating bits used for indicating whether 1557 * this view is will draw 1558 * {@hide} 1559 */ 1560 static final int DRAW_MASK = 0x00000080; 1561 1562 /** 1563 * <p>This view doesn't show scrollbars.</p> 1564 * {@hide} 1565 */ 1566 static final int SCROLLBARS_NONE = 0x00000000; 1567 1568 /** 1569 * <p>This view shows horizontal scrollbars.</p> 1570 * {@hide} 1571 */ 1572 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1573 1574 /** 1575 * <p>This view shows vertical scrollbars.</p> 1576 * {@hide} 1577 */ 1578 static final int SCROLLBARS_VERTICAL = 0x00000200; 1579 1580 /** 1581 * <p>Mask for use with setFlags indicating bits used for indicating which 1582 * scrollbars are enabled.</p> 1583 * {@hide} 1584 */ 1585 static final int SCROLLBARS_MASK = 0x00000300; 1586 1587 /** 1588 * Indicates that the view should filter touches when its window is obscured. 1589 * Refer to the class comments for more information about this security feature. 1590 * {@hide} 1591 */ 1592 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1593 1594 /** 1595 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1596 * that they are optional and should be skipped if the window has 1597 * requested system UI flags that ignore those insets for layout. 1598 * <p> 1599 * This is only used for support library as of Android R. The framework now uses 1600 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1601 * insets path that loses insets information. 1602 */ 1603 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1604 1605 /** 1606 * <p>This view doesn't show fading edges.</p> 1607 * {@hide} 1608 */ 1609 static final int FADING_EDGE_NONE = 0x00000000; 1610 1611 /** 1612 * <p>This view shows horizontal fading edges.</p> 1613 * {@hide} 1614 */ 1615 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1616 1617 /** 1618 * <p>This view shows vertical fading edges.</p> 1619 * {@hide} 1620 */ 1621 static final int FADING_EDGE_VERTICAL = 0x00002000; 1622 1623 /** 1624 * <p>Mask for use with setFlags indicating bits used for indicating which 1625 * fading edges are enabled.</p> 1626 * {@hide} 1627 */ 1628 static final int FADING_EDGE_MASK = 0x00003000; 1629 1630 /** 1631 * <p>Indicates this view can be clicked. When clickable, a View reacts 1632 * to clicks by notifying the OnClickListener.<p> 1633 * {@hide} 1634 */ 1635 static final int CLICKABLE = 0x00004000; 1636 1637 /** 1638 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1639 * {@hide} 1640 */ 1641 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1642 1643 /** 1644 * <p>Indicates that no icicle should be saved for this view.<p> 1645 * {@hide} 1646 */ 1647 static final int SAVE_DISABLED = 0x000010000; 1648 1649 /** 1650 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1651 * property.</p> 1652 * {@hide} 1653 */ 1654 static final int SAVE_DISABLED_MASK = 0x000010000; 1655 1656 /** 1657 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1658 * {@hide} 1659 */ 1660 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1661 1662 /** 1663 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1664 * {@hide} 1665 */ 1666 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1667 1668 /** @hide */ 1669 @Retention(RetentionPolicy.SOURCE) 1670 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1671 DRAWING_CACHE_QUALITY_LOW, 1672 DRAWING_CACHE_QUALITY_HIGH, 1673 DRAWING_CACHE_QUALITY_AUTO 1674 }) 1675 public @interface DrawingCacheQuality {} 1676 1677 /** 1678 * <p>Enables low quality mode for the drawing cache.</p> 1679 * 1680 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1681 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1682 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1683 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1684 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1685 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1686 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1687 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1688 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1689 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1690 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1691 * reports or unit testing the {@link PixelCopy} API is recommended. 1692 */ 1693 @Deprecated 1694 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1695 1696 /** 1697 * <p>Enables high quality mode for the drawing cache.</p> 1698 * 1699 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1700 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1701 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1702 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1703 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1704 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1705 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1706 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1707 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1708 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1709 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1710 * reports or unit testing the {@link PixelCopy} API is recommended. 1711 */ 1712 @Deprecated 1713 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1714 1715 /** 1716 * <p>Enables automatic quality mode for the drawing cache.</p> 1717 * 1718 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1719 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1720 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1721 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1722 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1723 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1724 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1725 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1726 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1727 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1728 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1729 * reports or unit testing the {@link PixelCopy} API is recommended. 1730 */ 1731 @Deprecated 1732 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1733 1734 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1735 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1736 }; 1737 1738 /** 1739 * <p>Mask for use with setFlags indicating bits used for the cache 1740 * quality property.</p> 1741 * {@hide} 1742 */ 1743 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1744 1745 /** 1746 * <p> 1747 * Indicates this view can be long clicked. When long clickable, a View 1748 * reacts to long clicks by notifying the OnLongClickListener or showing a 1749 * context menu. 1750 * </p> 1751 * {@hide} 1752 */ 1753 static final int LONG_CLICKABLE = 0x00200000; 1754 1755 /** 1756 * <p>Indicates that this view gets its drawable states from its direct parent 1757 * and ignores its original internal states.</p> 1758 * 1759 * @hide 1760 */ 1761 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1762 1763 /** 1764 * <p> 1765 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1766 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1767 * OnContextClickListener. 1768 * </p> 1769 * {@hide} 1770 */ 1771 static final int CONTEXT_CLICKABLE = 0x00800000; 1772 1773 /** @hide */ 1774 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1775 SCROLLBARS_INSIDE_OVERLAY, 1776 SCROLLBARS_INSIDE_INSET, 1777 SCROLLBARS_OUTSIDE_OVERLAY, 1778 SCROLLBARS_OUTSIDE_INSET 1779 }) 1780 @Retention(RetentionPolicy.SOURCE) 1781 public @interface ScrollBarStyle {} 1782 1783 /** 1784 * The scrollbar style to display the scrollbars inside the content area, 1785 * without increasing the padding. The scrollbars will be overlaid with 1786 * translucency on the view's content. 1787 */ 1788 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1789 1790 /** 1791 * The scrollbar style to display the scrollbars inside the padded area, 1792 * increasing the padding of the view. The scrollbars will not overlap the 1793 * content area of the view. 1794 */ 1795 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1796 1797 /** 1798 * The scrollbar style to display the scrollbars at the edge of the view, 1799 * without increasing the padding. The scrollbars will be overlaid with 1800 * translucency. 1801 */ 1802 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1803 1804 /** 1805 * The scrollbar style to display the scrollbars at the edge of the view, 1806 * increasing the padding of the view. The scrollbars will only overlap the 1807 * background, if any. 1808 */ 1809 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1810 1811 /** 1812 * Mask to check if the scrollbar style is overlay or inset. 1813 * {@hide} 1814 */ 1815 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1816 1817 /** 1818 * Mask to check if the scrollbar style is inside or outside. 1819 * {@hide} 1820 */ 1821 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1822 1823 /** 1824 * Mask for scrollbar style. 1825 * {@hide} 1826 */ 1827 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1828 1829 /** 1830 * View flag indicating that the screen should remain on while the 1831 * window containing this view is visible to the user. This effectively 1832 * takes care of automatically setting the WindowManager's 1833 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1834 */ 1835 public static final int KEEP_SCREEN_ON = 0x04000000; 1836 1837 /** 1838 * View flag indicating whether this view should have sound effects enabled 1839 * for events such as clicking and touching. 1840 */ 1841 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1842 1843 /** 1844 * View flag indicating whether this view should have haptic feedback 1845 * enabled for events such as long presses. 1846 */ 1847 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1848 1849 /** 1850 * <p>Indicates that the view hierarchy should stop saving state when 1851 * it reaches this view. If state saving is initiated immediately at 1852 * the view, it will be allowed. 1853 * {@hide} 1854 */ 1855 static final int PARENT_SAVE_DISABLED = 0x20000000; 1856 1857 /** 1858 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1859 * {@hide} 1860 */ 1861 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1862 1863 private static Paint sDebugPaint; 1864 1865 /** 1866 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1867 * {@hide} 1868 */ 1869 static final int TOOLTIP = 0x40000000; 1870 1871 /** @hide */ 1872 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1873 FOCUSABLES_ALL, 1874 FOCUSABLES_TOUCH_MODE 1875 }) 1876 @Retention(RetentionPolicy.SOURCE) 1877 public @interface FocusableMode {} 1878 1879 /** 1880 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1881 * should add all focusable Views regardless if they are focusable in touch mode. 1882 */ 1883 public static final int FOCUSABLES_ALL = 0x00000000; 1884 1885 /** 1886 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1887 * should add only Views focusable in touch mode. 1888 */ 1889 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1890 1891 /** @hide */ 1892 @IntDef(prefix = { "FOCUS_" }, value = { 1893 FOCUS_BACKWARD, 1894 FOCUS_FORWARD, 1895 FOCUS_LEFT, 1896 FOCUS_UP, 1897 FOCUS_RIGHT, 1898 FOCUS_DOWN 1899 }) 1900 @Retention(RetentionPolicy.SOURCE) 1901 public @interface FocusDirection {} 1902 1903 /** @hide */ 1904 @IntDef(prefix = { "FOCUS_" }, value = { 1905 FOCUS_LEFT, 1906 FOCUS_UP, 1907 FOCUS_RIGHT, 1908 FOCUS_DOWN 1909 }) 1910 @Retention(RetentionPolicy.SOURCE) 1911 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1912 1913 /** 1914 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1915 * item. 1916 */ 1917 public static final int FOCUS_BACKWARD = 0x00000001; 1918 1919 /** 1920 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1921 * item. 1922 */ 1923 public static final int FOCUS_FORWARD = 0x00000002; 1924 1925 /** 1926 * Use with {@link #focusSearch(int)}. Move focus to the left. 1927 */ 1928 public static final int FOCUS_LEFT = 0x00000011; 1929 1930 /** 1931 * Use with {@link #focusSearch(int)}. Move focus up. 1932 */ 1933 public static final int FOCUS_UP = 0x00000021; 1934 1935 /** 1936 * Use with {@link #focusSearch(int)}. Move focus to the right. 1937 */ 1938 public static final int FOCUS_RIGHT = 0x00000042; 1939 1940 /** 1941 * Use with {@link #focusSearch(int)}. Move focus down. 1942 */ 1943 public static final int FOCUS_DOWN = 0x00000082; 1944 1945 /** 1946 * Bits of {@link #getMeasuredWidthAndState()} and 1947 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1948 */ 1949 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1950 1951 /** 1952 * Bits of {@link #getMeasuredWidthAndState()} and 1953 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1954 */ 1955 public static final int MEASURED_STATE_MASK = 0xff000000; 1956 1957 /** 1958 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1959 * for functions that combine both width and height into a single int, 1960 * such as {@link #getMeasuredState()} and the childState argument of 1961 * {@link #resolveSizeAndState(int, int, int)}. 1962 */ 1963 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1964 1965 /** 1966 * Bit of {@link #getMeasuredWidthAndState()} and 1967 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1968 * is smaller that the space the view would like to have. 1969 */ 1970 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1971 1972 /** 1973 * Base View state sets 1974 */ 1975 // Singles 1976 /** 1977 * Indicates the view has no states set. States are used with 1978 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1979 * view depending on its state. 1980 * 1981 * @see android.graphics.drawable.Drawable 1982 * @see #getDrawableState() 1983 */ 1984 protected static final int[] EMPTY_STATE_SET; 1985 /** 1986 * Indicates the view is enabled. States are used with 1987 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1988 * view depending on its state. 1989 * 1990 * @see android.graphics.drawable.Drawable 1991 * @see #getDrawableState() 1992 */ 1993 protected static final int[] ENABLED_STATE_SET; 1994 /** 1995 * Indicates the view is focused. States are used with 1996 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1997 * view depending on its state. 1998 * 1999 * @see android.graphics.drawable.Drawable 2000 * @see #getDrawableState() 2001 */ 2002 protected static final int[] FOCUSED_STATE_SET; 2003 /** 2004 * Indicates the view is selected. States are used with 2005 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2006 * view depending on its state. 2007 * 2008 * @see android.graphics.drawable.Drawable 2009 * @see #getDrawableState() 2010 */ 2011 protected static final int[] SELECTED_STATE_SET; 2012 /** 2013 * Indicates the view is pressed. States are used with 2014 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2015 * view depending on its state. 2016 * 2017 * @see android.graphics.drawable.Drawable 2018 * @see #getDrawableState() 2019 */ 2020 protected static final int[] PRESSED_STATE_SET; 2021 /** 2022 * Indicates the view's window has focus. States are used with 2023 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2024 * view depending on its state. 2025 * 2026 * @see android.graphics.drawable.Drawable 2027 * @see #getDrawableState() 2028 */ 2029 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2030 // Doubles 2031 /** 2032 * Indicates the view is enabled and has the focus. 2033 * 2034 * @see #ENABLED_STATE_SET 2035 * @see #FOCUSED_STATE_SET 2036 */ 2037 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2038 /** 2039 * Indicates the view is enabled and selected. 2040 * 2041 * @see #ENABLED_STATE_SET 2042 * @see #SELECTED_STATE_SET 2043 */ 2044 protected static final int[] ENABLED_SELECTED_STATE_SET; 2045 /** 2046 * Indicates the view is enabled and that its window has focus. 2047 * 2048 * @see #ENABLED_STATE_SET 2049 * @see #WINDOW_FOCUSED_STATE_SET 2050 */ 2051 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2052 /** 2053 * Indicates the view is focused and selected. 2054 * 2055 * @see #FOCUSED_STATE_SET 2056 * @see #SELECTED_STATE_SET 2057 */ 2058 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2059 /** 2060 * Indicates the view has the focus and that its window has the focus. 2061 * 2062 * @see #FOCUSED_STATE_SET 2063 * @see #WINDOW_FOCUSED_STATE_SET 2064 */ 2065 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2066 /** 2067 * Indicates the view is selected and that its window has the focus. 2068 * 2069 * @see #SELECTED_STATE_SET 2070 * @see #WINDOW_FOCUSED_STATE_SET 2071 */ 2072 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2073 // Triples 2074 /** 2075 * Indicates the view is enabled, focused and selected. 2076 * 2077 * @see #ENABLED_STATE_SET 2078 * @see #FOCUSED_STATE_SET 2079 * @see #SELECTED_STATE_SET 2080 */ 2081 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2082 /** 2083 * Indicates the view is enabled, focused and its window has the focus. 2084 * 2085 * @see #ENABLED_STATE_SET 2086 * @see #FOCUSED_STATE_SET 2087 * @see #WINDOW_FOCUSED_STATE_SET 2088 */ 2089 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2090 /** 2091 * Indicates the view is enabled, selected and its window has the focus. 2092 * 2093 * @see #ENABLED_STATE_SET 2094 * @see #SELECTED_STATE_SET 2095 * @see #WINDOW_FOCUSED_STATE_SET 2096 */ 2097 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2098 /** 2099 * Indicates the view is focused, selected and its window has the focus. 2100 * 2101 * @see #FOCUSED_STATE_SET 2102 * @see #SELECTED_STATE_SET 2103 * @see #WINDOW_FOCUSED_STATE_SET 2104 */ 2105 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2106 /** 2107 * Indicates the view is enabled, focused, selected and its window 2108 * has the focus. 2109 * 2110 * @see #ENABLED_STATE_SET 2111 * @see #FOCUSED_STATE_SET 2112 * @see #SELECTED_STATE_SET 2113 * @see #WINDOW_FOCUSED_STATE_SET 2114 */ 2115 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2116 /** 2117 * Indicates the view is pressed and its window has the focus. 2118 * 2119 * @see #PRESSED_STATE_SET 2120 * @see #WINDOW_FOCUSED_STATE_SET 2121 */ 2122 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2123 /** 2124 * Indicates the view is pressed and selected. 2125 * 2126 * @see #PRESSED_STATE_SET 2127 * @see #SELECTED_STATE_SET 2128 */ 2129 protected static final int[] PRESSED_SELECTED_STATE_SET; 2130 /** 2131 * Indicates the view is pressed, selected and its window has the focus. 2132 * 2133 * @see #PRESSED_STATE_SET 2134 * @see #SELECTED_STATE_SET 2135 * @see #WINDOW_FOCUSED_STATE_SET 2136 */ 2137 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2138 /** 2139 * Indicates the view is pressed and focused. 2140 * 2141 * @see #PRESSED_STATE_SET 2142 * @see #FOCUSED_STATE_SET 2143 */ 2144 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2145 /** 2146 * Indicates the view is pressed, focused and its window has the focus. 2147 * 2148 * @see #PRESSED_STATE_SET 2149 * @see #FOCUSED_STATE_SET 2150 * @see #WINDOW_FOCUSED_STATE_SET 2151 */ 2152 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2153 /** 2154 * Indicates the view is pressed, focused and selected. 2155 * 2156 * @see #PRESSED_STATE_SET 2157 * @see #SELECTED_STATE_SET 2158 * @see #FOCUSED_STATE_SET 2159 */ 2160 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2161 /** 2162 * Indicates the view is pressed, focused, selected and its window has the focus. 2163 * 2164 * @see #PRESSED_STATE_SET 2165 * @see #FOCUSED_STATE_SET 2166 * @see #SELECTED_STATE_SET 2167 * @see #WINDOW_FOCUSED_STATE_SET 2168 */ 2169 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2170 /** 2171 * Indicates the view is pressed and enabled. 2172 * 2173 * @see #PRESSED_STATE_SET 2174 * @see #ENABLED_STATE_SET 2175 */ 2176 protected static final int[] PRESSED_ENABLED_STATE_SET; 2177 /** 2178 * Indicates the view is pressed, enabled and its window has the focus. 2179 * 2180 * @see #PRESSED_STATE_SET 2181 * @see #ENABLED_STATE_SET 2182 * @see #WINDOW_FOCUSED_STATE_SET 2183 */ 2184 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2185 /** 2186 * Indicates the view is pressed, enabled and selected. 2187 * 2188 * @see #PRESSED_STATE_SET 2189 * @see #ENABLED_STATE_SET 2190 * @see #SELECTED_STATE_SET 2191 */ 2192 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2193 /** 2194 * Indicates the view is pressed, enabled, selected and its window has the 2195 * focus. 2196 * 2197 * @see #PRESSED_STATE_SET 2198 * @see #ENABLED_STATE_SET 2199 * @see #SELECTED_STATE_SET 2200 * @see #WINDOW_FOCUSED_STATE_SET 2201 */ 2202 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2203 /** 2204 * Indicates the view is pressed, enabled and focused. 2205 * 2206 * @see #PRESSED_STATE_SET 2207 * @see #ENABLED_STATE_SET 2208 * @see #FOCUSED_STATE_SET 2209 */ 2210 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2211 /** 2212 * Indicates the view is pressed, enabled, focused and its window has the 2213 * focus. 2214 * 2215 * @see #PRESSED_STATE_SET 2216 * @see #ENABLED_STATE_SET 2217 * @see #FOCUSED_STATE_SET 2218 * @see #WINDOW_FOCUSED_STATE_SET 2219 */ 2220 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2221 /** 2222 * Indicates the view is pressed, enabled, focused and selected. 2223 * 2224 * @see #PRESSED_STATE_SET 2225 * @see #ENABLED_STATE_SET 2226 * @see #SELECTED_STATE_SET 2227 * @see #FOCUSED_STATE_SET 2228 */ 2229 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2230 /** 2231 * Indicates the view is pressed, enabled, focused, selected and its window 2232 * has the focus. 2233 * 2234 * @see #PRESSED_STATE_SET 2235 * @see #ENABLED_STATE_SET 2236 * @see #SELECTED_STATE_SET 2237 * @see #FOCUSED_STATE_SET 2238 * @see #WINDOW_FOCUSED_STATE_SET 2239 */ 2240 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2241 2242 static { 2243 EMPTY_STATE_SET = StateSet.get(0); 2244 2245 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2246 2247 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2248 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2249 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2250 2251 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2252 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2253 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2254 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2255 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2256 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2257 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2258 | StateSet.VIEW_STATE_FOCUSED); 2259 2260 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2261 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2262 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2263 ENABLED_SELECTED_STATE_SET = StateSet.get( 2264 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2265 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2266 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2267 | StateSet.VIEW_STATE_ENABLED); 2268 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2269 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2270 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2271 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2272 | StateSet.VIEW_STATE_ENABLED); 2273 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2274 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2275 | StateSet.VIEW_STATE_ENABLED); 2276 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2277 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2278 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2279 2280 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2281 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2282 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2283 PRESSED_SELECTED_STATE_SET = StateSet.get( 2284 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2285 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2286 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2287 | StateSet.VIEW_STATE_PRESSED); 2288 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2289 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2290 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2291 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2292 | StateSet.VIEW_STATE_PRESSED); 2293 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2294 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2295 | StateSet.VIEW_STATE_PRESSED); 2296 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2297 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2298 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2299 PRESSED_ENABLED_STATE_SET = StateSet.get( 2300 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2301 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2302 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2303 | StateSet.VIEW_STATE_PRESSED); 2304 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2305 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2306 | StateSet.VIEW_STATE_PRESSED); 2307 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2308 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2309 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2310 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2311 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2312 | StateSet.VIEW_STATE_PRESSED); 2313 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2314 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2315 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2316 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2317 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2318 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2319 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2320 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2321 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2322 | StateSet.VIEW_STATE_PRESSED); 2323 } 2324 2325 /** 2326 * Accessibility event types that are dispatched for text population. 2327 */ 2328 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2329 AccessibilityEvent.TYPE_VIEW_CLICKED 2330 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2331 | AccessibilityEvent.TYPE_VIEW_SELECTED 2332 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2333 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2334 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2335 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2336 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2337 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2338 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2339 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2340 2341 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2342 2343 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2344 2345 /** 2346 * Temporary Rect currently for use in setBackground(). This will probably 2347 * be extended in the future to hold our own class with more than just 2348 * a Rect. :) 2349 */ 2350 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2351 2352 /** 2353 * Map used to store views' tags. 2354 */ 2355 @UnsupportedAppUsage 2356 private SparseArray<Object> mKeyedTags; 2357 2358 /** 2359 * The next available accessibility id. 2360 */ 2361 private static int sNextAccessibilityViewId; 2362 2363 /** 2364 * The animation currently associated with this view. 2365 * @hide 2366 */ 2367 protected Animation mCurrentAnimation = null; 2368 2369 /** 2370 * Width as measured during measure pass. 2371 * {@hide} 2372 */ 2373 @ViewDebug.ExportedProperty(category = "measurement") 2374 @UnsupportedAppUsage 2375 int mMeasuredWidth; 2376 2377 /** 2378 * Height as measured during measure pass. 2379 * {@hide} 2380 */ 2381 @ViewDebug.ExportedProperty(category = "measurement") 2382 @UnsupportedAppUsage 2383 int mMeasuredHeight; 2384 2385 /** 2386 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2387 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2388 * its display list. This flag, used only when hw accelerated, allows us to clear the 2389 * flag while retaining this information until it's needed (at getDisplayList() time and 2390 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2391 * 2392 * {@hide} 2393 */ 2394 @UnsupportedAppUsage 2395 boolean mRecreateDisplayList = false; 2396 2397 /** 2398 * The view's identifier. 2399 * {@hide} 2400 * 2401 * @see #setId(int) 2402 * @see #getId() 2403 */ 2404 @IdRes 2405 @ViewDebug.ExportedProperty(resolveId = true) 2406 int mID = NO_ID; 2407 2408 /** The ID of this view for autofill purposes. 2409 * <ul> 2410 * <li>== {@link #NO_ID}: ID has not been assigned yet 2411 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2412 * unique in the process. This might change 2413 * over activity lifecycle events. 2414 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2415 * unique in the activity. This stays the same 2416 * over activity lifecycle events. 2417 */ 2418 private int mAutofillViewId = NO_ID; 2419 2420 // ID for accessibility purposes. This ID must be unique for every window 2421 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2422 private int mAccessibilityViewId = NO_ID; 2423 2424 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2425 2426 /** 2427 * The view's tag. 2428 * {@hide} 2429 * 2430 * @see #setTag(Object) 2431 * @see #getTag() 2432 */ 2433 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2434 protected Object mTag = null; 2435 2436 /* 2437 * Masks for mPrivateFlags, as generated by dumpFlags(): 2438 * 2439 * |-------|-------|-------|-------| 2440 * 1 PFLAG_WANTS_FOCUS 2441 * 1 PFLAG_FOCUSED 2442 * 1 PFLAG_SELECTED 2443 * 1 PFLAG_IS_ROOT_NAMESPACE 2444 * 1 PFLAG_HAS_BOUNDS 2445 * 1 PFLAG_DRAWN 2446 * 1 PFLAG_DRAW_ANIMATION 2447 * 1 PFLAG_SKIP_DRAW 2448 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2449 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2450 * 1 PFLAG_MEASURED_DIMENSION_SET 2451 * 1 PFLAG_FORCE_LAYOUT 2452 * 1 PFLAG_LAYOUT_REQUIRED 2453 * 1 PFLAG_PRESSED 2454 * 1 PFLAG_DRAWING_CACHE_VALID 2455 * 1 PFLAG_ANIMATION_STARTED 2456 * 1 PFLAG_SAVE_STATE_CALLED 2457 * 1 PFLAG_ALPHA_SET 2458 * 1 PFLAG_SCROLL_CONTAINER 2459 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2460 * 1 PFLAG_DIRTY 2461 * 1 PFLAG_DIRTY_MASK 2462 * 1 PFLAG_OPAQUE_BACKGROUND 2463 * 1 PFLAG_OPAQUE_SCROLLBARS 2464 * 11 PFLAG_OPAQUE_MASK 2465 * 1 PFLAG_PREPRESSED 2466 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2467 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2468 * 1 PFLAG_HOVERED 2469 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2470 * 1 PFLAG_ACTIVATED 2471 * 1 PFLAG_INVALIDATED 2472 * |-------|-------|-------|-------| 2473 */ 2474 /** {@hide} */ 2475 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2476 /** {@hide} */ 2477 static final int PFLAG_FOCUSED = 0x00000002; 2478 /** {@hide} */ 2479 static final int PFLAG_SELECTED = 0x00000004; 2480 /** {@hide} */ 2481 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2482 /** {@hide} */ 2483 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2484 /** {@hide} */ 2485 static final int PFLAG_DRAWN = 0x00000020; 2486 /** 2487 * When this flag is set, this view is running an animation on behalf of its 2488 * children and should therefore not cancel invalidate requests, even if they 2489 * lie outside of this view's bounds. 2490 * 2491 * {@hide} 2492 */ 2493 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2494 /** {@hide} */ 2495 static final int PFLAG_SKIP_DRAW = 0x00000080; 2496 /** {@hide} */ 2497 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2498 /** {@hide} */ 2499 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2500 /** {@hide} */ 2501 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2502 /** {@hide} */ 2503 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2504 /** {@hide} */ 2505 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2506 2507 private static final int PFLAG_PRESSED = 0x00004000; 2508 2509 /** {@hide} */ 2510 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2511 /** 2512 * Flag used to indicate that this view should be drawn once more (and only once 2513 * more) after its animation has completed. 2514 * {@hide} 2515 */ 2516 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2517 2518 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2519 2520 /** 2521 * Indicates that the View returned true when onSetAlpha() was called and that 2522 * the alpha must be restored. 2523 * {@hide} 2524 */ 2525 static final int PFLAG_ALPHA_SET = 0x00040000; 2526 2527 /** 2528 * Set by {@link #setScrollContainer(boolean)}. 2529 */ 2530 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2531 2532 /** 2533 * Set by {@link #setScrollContainer(boolean)}. 2534 */ 2535 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2536 2537 /** 2538 * View flag indicating whether this view was invalidated (fully or partially.) 2539 * 2540 * @hide 2541 */ 2542 static final int PFLAG_DIRTY = 0x00200000; 2543 2544 /** 2545 * Mask for {@link #PFLAG_DIRTY}. 2546 * 2547 * @hide 2548 */ 2549 static final int PFLAG_DIRTY_MASK = 0x00200000; 2550 2551 /** 2552 * Indicates whether the background is opaque. 2553 * 2554 * @hide 2555 */ 2556 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2557 2558 /** 2559 * Indicates whether the scrollbars are opaque. 2560 * 2561 * @hide 2562 */ 2563 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2564 2565 /** 2566 * Indicates whether the view is opaque. 2567 * 2568 * @hide 2569 */ 2570 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2571 2572 /** 2573 * Indicates a prepressed state; 2574 * the short time between ACTION_DOWN and recognizing 2575 * a 'real' press. Prepressed is used to recognize quick taps 2576 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2577 * 2578 * @hide 2579 */ 2580 private static final int PFLAG_PREPRESSED = 0x02000000; 2581 2582 /** 2583 * Indicates whether the view is temporarily detached. 2584 * 2585 * @hide 2586 */ 2587 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2588 2589 /** 2590 * Indicates that we should awaken scroll bars once attached 2591 * 2592 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2593 * during window attachment and it is no longer needed. Feel free to repurpose it. 2594 * 2595 * @hide 2596 */ 2597 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2598 2599 /** 2600 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2601 * @hide 2602 */ 2603 private static final int PFLAG_HOVERED = 0x10000000; 2604 2605 /** 2606 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2607 */ 2608 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2609 2610 /** {@hide} */ 2611 static final int PFLAG_ACTIVATED = 0x40000000; 2612 2613 /** 2614 * Indicates that this view was specifically invalidated, not just dirtied because some 2615 * child view was invalidated. The flag is used to determine when we need to recreate 2616 * a view's display list (as opposed to just returning a reference to its existing 2617 * display list). 2618 * 2619 * @hide 2620 */ 2621 static final int PFLAG_INVALIDATED = 0x80000000; 2622 2623 /* End of masks for mPrivateFlags */ 2624 2625 /* 2626 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2627 * 2628 * |-------|-------|-------|-------| 2629 * 1 PFLAG2_DRAG_CAN_ACCEPT 2630 * 1 PFLAG2_DRAG_HOVERED 2631 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2632 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2633 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2634 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2635 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2636 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2637 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2638 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2639 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2640 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2641 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2642 * 111 PFLAG2_TEXT_DIRECTION_MASK 2643 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2644 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2645 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2646 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2647 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2648 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2649 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2650 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2651 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2652 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2653 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2654 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2655 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2656 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2657 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2658 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2659 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2660 * 1 PFLAG2_VIEW_QUICK_REJECTED 2661 * 1 PFLAG2_PADDING_RESOLVED 2662 * 1 PFLAG2_DRAWABLE_RESOLVED 2663 * 1 PFLAG2_HAS_TRANSIENT_STATE 2664 * |-------|-------|-------|-------| 2665 */ 2666 2667 /** 2668 * Indicates that this view has reported that it can accept the current drag's content. 2669 * Cleared when the drag operation concludes. 2670 * @hide 2671 */ 2672 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2673 2674 /** 2675 * Indicates that this view is currently directly under the drag location in a 2676 * drag-and-drop operation involving content that it can accept. Cleared when 2677 * the drag exits the view, or when the drag operation concludes. 2678 * @hide 2679 */ 2680 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2681 2682 /** @hide */ 2683 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2684 LAYOUT_DIRECTION_LTR, 2685 LAYOUT_DIRECTION_RTL, 2686 LAYOUT_DIRECTION_INHERIT, 2687 LAYOUT_DIRECTION_LOCALE 2688 }) 2689 @Retention(RetentionPolicy.SOURCE) 2690 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2691 public @interface LayoutDir {} 2692 2693 /** @hide */ 2694 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2695 LAYOUT_DIRECTION_LTR, 2696 LAYOUT_DIRECTION_RTL 2697 }) 2698 @Retention(RetentionPolicy.SOURCE) 2699 public @interface ResolvedLayoutDir {} 2700 2701 /** 2702 * A flag to indicate that the layout direction of this view has not been defined yet. 2703 * @hide 2704 */ 2705 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2706 2707 /** 2708 * Horizontal layout direction of this view is from Left to Right. 2709 * Use with {@link #setLayoutDirection}. 2710 */ 2711 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2712 2713 /** 2714 * Horizontal layout direction of this view is from Right to Left. 2715 * Use with {@link #setLayoutDirection}. 2716 */ 2717 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2718 2719 /** 2720 * Horizontal layout direction of this view is inherited from its parent. 2721 * Use with {@link #setLayoutDirection}. 2722 */ 2723 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2724 2725 /** 2726 * Horizontal layout direction of this view is from deduced from the default language 2727 * script for the locale. Use with {@link #setLayoutDirection}. 2728 */ 2729 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2730 2731 /** 2732 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2733 * @hide 2734 */ 2735 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2736 2737 /** 2738 * Mask for use with private flags indicating bits used for horizontal layout direction. 2739 * @hide 2740 */ 2741 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2742 2743 /** 2744 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2745 * right-to-left direction. 2746 * @hide 2747 */ 2748 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2749 2750 /** 2751 * Indicates whether the view horizontal layout direction has been resolved. 2752 * @hide 2753 */ 2754 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2755 2756 /** 2757 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2758 * @hide 2759 */ 2760 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2761 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2762 2763 /* 2764 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2765 * flag value. 2766 * @hide 2767 */ 2768 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2769 LAYOUT_DIRECTION_LTR, 2770 LAYOUT_DIRECTION_RTL, 2771 LAYOUT_DIRECTION_INHERIT, 2772 LAYOUT_DIRECTION_LOCALE 2773 }; 2774 2775 /** 2776 * Default horizontal layout direction. 2777 */ 2778 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2779 2780 /** 2781 * Default horizontal layout direction. 2782 * @hide 2783 */ 2784 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2785 2786 /** 2787 * Text direction is inherited through {@link ViewGroup} 2788 */ 2789 public static final int TEXT_DIRECTION_INHERIT = 0; 2790 2791 /** 2792 * Text direction is using "first strong algorithm". The first strong directional character 2793 * determines the paragraph direction. If there is no strong directional character, the 2794 * paragraph direction is the view's resolved layout direction. 2795 */ 2796 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2797 2798 /** 2799 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2800 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2801 * If there are neither, the paragraph direction is the view's resolved layout direction. 2802 */ 2803 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2804 2805 /** 2806 * Text direction is forced to LTR. 2807 */ 2808 public static final int TEXT_DIRECTION_LTR = 3; 2809 2810 /** 2811 * Text direction is forced to RTL. 2812 */ 2813 public static final int TEXT_DIRECTION_RTL = 4; 2814 2815 /** 2816 * Text direction is coming from the system Locale. 2817 */ 2818 public static final int TEXT_DIRECTION_LOCALE = 5; 2819 2820 /** 2821 * Text direction is using "first strong algorithm". The first strong directional character 2822 * determines the paragraph direction. If there is no strong directional character, the 2823 * paragraph direction is LTR. 2824 */ 2825 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2826 2827 /** 2828 * Text direction is using "first strong algorithm". The first strong directional character 2829 * determines the paragraph direction. If there is no strong directional character, the 2830 * paragraph direction is RTL. 2831 */ 2832 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2833 2834 /** 2835 * Default text direction is inherited 2836 */ 2837 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2838 2839 /** 2840 * Default resolved text direction 2841 * @hide 2842 */ 2843 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2844 2845 /** 2846 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2847 * @hide 2848 */ 2849 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2850 2851 /** 2852 * Mask for use with private flags indicating bits used for text direction. 2853 * @hide 2854 */ 2855 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2856 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2857 2858 /** 2859 * Array of text direction flags for mapping attribute "textDirection" to correct 2860 * flag value. 2861 * @hide 2862 */ 2863 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2864 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2865 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2866 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2867 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2868 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2869 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2870 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2871 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2872 }; 2873 2874 /** 2875 * Indicates whether the view text direction has been resolved. 2876 * @hide 2877 */ 2878 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2879 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2880 2881 /** 2882 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2883 * @hide 2884 */ 2885 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2886 2887 /** 2888 * Mask for use with private flags indicating bits used for resolved text direction. 2889 * @hide 2890 */ 2891 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2892 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2893 2894 /** 2895 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2896 * @hide 2897 */ 2898 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2899 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2900 2901 /** @hide */ 2902 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2903 TEXT_ALIGNMENT_INHERIT, 2904 TEXT_ALIGNMENT_GRAVITY, 2905 TEXT_ALIGNMENT_CENTER, 2906 TEXT_ALIGNMENT_TEXT_START, 2907 TEXT_ALIGNMENT_TEXT_END, 2908 TEXT_ALIGNMENT_VIEW_START, 2909 TEXT_ALIGNMENT_VIEW_END 2910 }) 2911 @Retention(RetentionPolicy.SOURCE) 2912 public @interface TextAlignment {} 2913 2914 /** 2915 * Default text alignment. The text alignment of this View is inherited from its parent. 2916 * Use with {@link #setTextAlignment(int)} 2917 */ 2918 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2919 2920 /** 2921 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2922 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 2923 * 2924 * Use with {@link #setTextAlignment(int)} 2925 */ 2926 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2927 2928 /** 2929 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2930 * 2931 * Use with {@link #setTextAlignment(int)} 2932 */ 2933 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2934 2935 /** 2936 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2937 * 2938 * Use with {@link #setTextAlignment(int)} 2939 */ 2940 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2941 2942 /** 2943 * Center the paragraph, e.g. ALIGN_CENTER. 2944 * 2945 * Use with {@link #setTextAlignment(int)} 2946 */ 2947 public static final int TEXT_ALIGNMENT_CENTER = 4; 2948 2949 /** 2950 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 2951 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2952 * 2953 * Use with {@link #setTextAlignment(int)} 2954 */ 2955 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2956 2957 /** 2958 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 2959 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2960 * 2961 * Use with {@link #setTextAlignment(int)} 2962 */ 2963 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2964 2965 /** 2966 * Default text alignment is inherited 2967 */ 2968 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2969 2970 /** 2971 * Default resolved text alignment 2972 * @hide 2973 */ 2974 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2975 2976 /** 2977 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2978 * @hide 2979 */ 2980 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2981 2982 /** 2983 * Mask for use with private flags indicating bits used for text alignment. 2984 * @hide 2985 */ 2986 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2987 2988 /** 2989 * Array of text direction flags for mapping attribute "textAlignment" to correct 2990 * flag value. 2991 * @hide 2992 */ 2993 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2994 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2995 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2996 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2997 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2998 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2999 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3000 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 3001 }; 3002 3003 /** 3004 * Indicates whether the view text alignment has been resolved. 3005 * @hide 3006 */ 3007 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3008 3009 /** 3010 * Bit shift to get the resolved text alignment. 3011 * @hide 3012 */ 3013 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 3014 3015 /** 3016 * Mask for use with private flags indicating bits used for text alignment. 3017 * @hide 3018 */ 3019 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 3020 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3021 3022 /** 3023 * Indicates whether if the view text alignment has been resolved to gravity 3024 */ 3025 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3026 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3027 3028 // Accessiblity constants for mPrivateFlags2 3029 3030 /** 3031 * Shift for the bits in {@link #mPrivateFlags2} related to the 3032 * "importantForAccessibility" attribute. 3033 */ 3034 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3035 3036 /** 3037 * Automatically determine whether a view is important for accessibility. 3038 */ 3039 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3040 3041 /** 3042 * The view is important for accessibility. 3043 */ 3044 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3045 3046 /** 3047 * The view is not important for accessibility. 3048 */ 3049 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3050 3051 /** 3052 * The view is not important for accessibility, nor are any of its 3053 * descendant views. 3054 */ 3055 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3056 3057 /** 3058 * The default whether the view is important for accessibility. 3059 */ 3060 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3061 3062 /** 3063 * Mask for obtaining the bits which specify how to determine 3064 * whether a view is important for accessibility. 3065 */ 3066 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3067 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3068 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3069 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3070 3071 /** 3072 * Shift for the bits in {@link #mPrivateFlags2} related to the 3073 * "accessibilityLiveRegion" attribute. 3074 */ 3075 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3076 3077 /** 3078 * Live region mode specifying that accessibility services should not 3079 * automatically announce changes to this view. This is the default live 3080 * region mode for most views. 3081 * <p> 3082 * Use with {@link #setAccessibilityLiveRegion(int)}. 3083 */ 3084 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3085 3086 /** 3087 * Live region mode specifying that accessibility services should announce 3088 * changes to this view. 3089 * <p> 3090 * Use with {@link #setAccessibilityLiveRegion(int)}. 3091 */ 3092 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3093 3094 /** 3095 * Live region mode specifying that accessibility services should interrupt 3096 * ongoing speech to immediately announce changes to this view. 3097 * <p> 3098 * Use with {@link #setAccessibilityLiveRegion(int)}. 3099 */ 3100 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3101 3102 /** 3103 * The default whether the view is important for accessibility. 3104 */ 3105 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3106 3107 /** 3108 * Mask for obtaining the bits which specify a view's accessibility live 3109 * region mode. 3110 */ 3111 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3112 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3113 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3114 3115 /** 3116 * Flag indicating whether a view has accessibility focus. 3117 */ 3118 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3119 3120 /** 3121 * Flag whether the accessibility state of the subtree rooted at this view changed. 3122 */ 3123 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3124 3125 /** 3126 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3127 * is used to check whether later changes to the view's transform should invalidate the 3128 * view to force the quickReject test to run again. 3129 */ 3130 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3131 3132 /** 3133 * Flag indicating that start/end padding has been resolved into left/right padding 3134 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3135 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3136 * during measurement. In some special cases this is required such as when an adapter-based 3137 * view measures prospective children without attaching them to a window. 3138 */ 3139 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3140 3141 /** 3142 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3143 */ 3144 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3145 3146 /** 3147 * Indicates that the view is tracking some sort of transient state 3148 * that the app should not need to be aware of, but that the framework 3149 * should take special care to preserve. 3150 */ 3151 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3152 3153 /** 3154 * Group of bits indicating that RTL properties resolution is done. 3155 */ 3156 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3157 PFLAG2_TEXT_DIRECTION_RESOLVED | 3158 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3159 PFLAG2_PADDING_RESOLVED | 3160 PFLAG2_DRAWABLE_RESOLVED; 3161 3162 // There are a couple of flags left in mPrivateFlags2 3163 3164 /* End of masks for mPrivateFlags2 */ 3165 3166 /* 3167 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3168 * 3169 * |-------|-------|-------|-------| 3170 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3171 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3172 * 1 PFLAG3_IS_LAID_OUT 3173 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3174 * 1 PFLAG3_CALLED_SUPER 3175 * 1 PFLAG3_APPLYING_INSETS 3176 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3177 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3178 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3179 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3180 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3181 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3182 * 1 PFLAG3_SCROLL_INDICATOR_START 3183 * 1 PFLAG3_SCROLL_INDICATOR_END 3184 * 1 PFLAG3_ASSIST_BLOCKED 3185 * 1 PFLAG3_CLUSTER 3186 * 1 PFLAG3_IS_AUTOFILLED 3187 * 1 PFLAG3_FINGER_DOWN 3188 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3189 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3190 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3191 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3192 * 1 PFLAG3_TEMPORARY_DETACH 3193 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3194 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3195 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3196 * 1 PFLAG3_AGGREGATED_VISIBLE 3197 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3198 * 1 PFLAG3_ACCESSIBILITY_HEADING 3199 * |-------|-------|-------|-------| 3200 */ 3201 3202 /** 3203 * Flag indicating that view has a transform animation set on it. This is used to track whether 3204 * an animation is cleared between successive frames, in order to tell the associated 3205 * DisplayList to clear its animation matrix. 3206 */ 3207 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3208 3209 /** 3210 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3211 * animation is cleared between successive frames, in order to tell the associated 3212 * DisplayList to restore its alpha value. 3213 */ 3214 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3215 3216 /** 3217 * Flag indicating that the view has been through at least one layout since it 3218 * was last attached to a window. 3219 */ 3220 static final int PFLAG3_IS_LAID_OUT = 0x4; 3221 3222 /** 3223 * Flag indicating that a call to measure() was skipped and should be done 3224 * instead when layout() is invoked. 3225 */ 3226 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3227 3228 /** 3229 * Flag indicating that an overridden method correctly called down to 3230 * the superclass implementation as required by the API spec. 3231 */ 3232 static final int PFLAG3_CALLED_SUPER = 0x10; 3233 3234 /** 3235 * Flag indicating that we're in the process of applying window insets. 3236 */ 3237 static final int PFLAG3_APPLYING_INSETS = 0x20; 3238 3239 /** 3240 * Flag indicating that we're in the process of fitting system windows using the old method. 3241 */ 3242 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3243 3244 /** 3245 * Flag indicating that nested scrolling is enabled for this view. 3246 * The view will optionally cooperate with views up its parent chain to allow for 3247 * integrated nested scrolling along the same axis. 3248 */ 3249 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3250 3251 /** 3252 * Flag indicating that the bottom scroll indicator should be displayed 3253 * when this view can scroll up. 3254 */ 3255 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3256 3257 /** 3258 * Flag indicating that the bottom scroll indicator should be displayed 3259 * when this view can scroll down. 3260 */ 3261 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3262 3263 /** 3264 * Flag indicating that the left scroll indicator should be displayed 3265 * when this view can scroll left. 3266 */ 3267 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3268 3269 /** 3270 * Flag indicating that the right scroll indicator should be displayed 3271 * when this view can scroll right. 3272 */ 3273 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3274 3275 /** 3276 * Flag indicating that the start scroll indicator should be displayed 3277 * when this view can scroll in the start direction. 3278 */ 3279 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3280 3281 /** 3282 * Flag indicating that the end scroll indicator should be displayed 3283 * when this view can scroll in the end direction. 3284 */ 3285 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3286 3287 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3288 3289 static final int SCROLL_INDICATORS_NONE = 0x0000; 3290 3291 /** 3292 * Mask for use with setFlags indicating bits used for indicating which 3293 * scroll indicators are enabled. 3294 */ 3295 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3296 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3297 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3298 | PFLAG3_SCROLL_INDICATOR_END; 3299 3300 /** 3301 * Left-shift required to translate between public scroll indicator flags 3302 * and internal PFLAGS3 flags. When used as a right-shift, translates 3303 * PFLAGS3 flags to public flags. 3304 */ 3305 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3306 3307 /** @hide */ 3308 @Retention(RetentionPolicy.SOURCE) 3309 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3310 SCROLL_INDICATOR_TOP, 3311 SCROLL_INDICATOR_BOTTOM, 3312 SCROLL_INDICATOR_LEFT, 3313 SCROLL_INDICATOR_RIGHT, 3314 SCROLL_INDICATOR_START, 3315 SCROLL_INDICATOR_END, 3316 }) 3317 public @interface ScrollIndicators {} 3318 3319 /** 3320 * Scroll indicator direction for the top edge of the view. 3321 * 3322 * @see #setScrollIndicators(int) 3323 * @see #setScrollIndicators(int, int) 3324 * @see #getScrollIndicators() 3325 */ 3326 public static final int SCROLL_INDICATOR_TOP = 3327 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3328 3329 /** 3330 * Scroll indicator direction for the bottom edge of the view. 3331 * 3332 * @see #setScrollIndicators(int) 3333 * @see #setScrollIndicators(int, int) 3334 * @see #getScrollIndicators() 3335 */ 3336 public static final int SCROLL_INDICATOR_BOTTOM = 3337 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3338 3339 /** 3340 * Scroll indicator direction for the left edge of the view. 3341 * 3342 * @see #setScrollIndicators(int) 3343 * @see #setScrollIndicators(int, int) 3344 * @see #getScrollIndicators() 3345 */ 3346 public static final int SCROLL_INDICATOR_LEFT = 3347 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3348 3349 /** 3350 * Scroll indicator direction for the right edge of the view. 3351 * 3352 * @see #setScrollIndicators(int) 3353 * @see #setScrollIndicators(int, int) 3354 * @see #getScrollIndicators() 3355 */ 3356 public static final int SCROLL_INDICATOR_RIGHT = 3357 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3358 3359 /** 3360 * Scroll indicator direction for the starting edge of the view. 3361 * <p> 3362 * Resolved according to the view's layout direction, see 3363 * {@link #getLayoutDirection()} for more information. 3364 * 3365 * @see #setScrollIndicators(int) 3366 * @see #setScrollIndicators(int, int) 3367 * @see #getScrollIndicators() 3368 */ 3369 public static final int SCROLL_INDICATOR_START = 3370 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3371 3372 /** 3373 * Scroll indicator direction for the ending edge of the view. 3374 * <p> 3375 * Resolved according to the view's layout direction, see 3376 * {@link #getLayoutDirection()} for more information. 3377 * 3378 * @see #setScrollIndicators(int) 3379 * @see #setScrollIndicators(int, int) 3380 * @see #getScrollIndicators() 3381 */ 3382 public static final int SCROLL_INDICATOR_END = 3383 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3384 3385 /** 3386 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3387 * into this view.<p> 3388 */ 3389 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3390 3391 /** 3392 * Flag indicating that the view is a root of a keyboard navigation cluster. 3393 * 3394 * @see #isKeyboardNavigationCluster() 3395 * @see #setKeyboardNavigationCluster(boolean) 3396 */ 3397 private static final int PFLAG3_CLUSTER = 0x8000; 3398 3399 /** 3400 * Flag indicating that the view is autofilled 3401 * 3402 * @see #isAutofilled() 3403 * @see #setAutofilled(boolean, boolean) 3404 */ 3405 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3406 3407 /** 3408 * Indicates that the user is currently touching the screen. 3409 * Currently used for the tooltip positioning only. 3410 */ 3411 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3412 3413 /** 3414 * Flag indicating that this view is the default-focus view. 3415 * 3416 * @see #isFocusedByDefault() 3417 * @see #setFocusedByDefault(boolean) 3418 */ 3419 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3420 3421 /** 3422 * Shift for the bits in {@link #mPrivateFlags3} related to the 3423 * "importantForAutofill" attribute. 3424 */ 3425 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3426 3427 /** 3428 * Mask for obtaining the bits which specify how to determine 3429 * whether a view is important for autofill. 3430 */ 3431 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3432 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3433 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3434 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3435 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3436 3437 /** 3438 * Whether this view has rendered elements that overlap (see {@link 3439 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3440 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3441 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3442 * determined by whatever {@link #hasOverlappingRendering()} returns. 3443 */ 3444 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3445 3446 /** 3447 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3448 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3449 */ 3450 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3451 3452 /** 3453 * Flag indicating that the view is temporarily detached from the parent view. 3454 * 3455 * @see #onStartTemporaryDetach() 3456 * @see #onFinishTemporaryDetach() 3457 */ 3458 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3459 3460 /** 3461 * Flag indicating that the view does not wish to be revealed within its parent 3462 * hierarchy when it gains focus. Expressed in the negative since the historical 3463 * default behavior is to reveal on focus; this flag suppresses that behavior. 3464 * 3465 * @see #setRevealOnFocusHint(boolean) 3466 * @see #getRevealOnFocusHint() 3467 */ 3468 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3469 3470 /** 3471 * Flag indicating that when layout is completed we should notify 3472 * that the view was entered for autofill purposes. To minimize 3473 * showing autofill for views not visible to the user we evaluate 3474 * user visibility which cannot be done until the view is laid out. 3475 */ 3476 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3477 3478 /** 3479 * Works like focusable for screen readers, but without the side effects on input focus. 3480 * @see #setScreenReaderFocusable(boolean) 3481 */ 3482 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3483 3484 /** 3485 * The last aggregated visibility. Used to detect when it truly changes. 3486 */ 3487 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3488 3489 /** 3490 * Used to indicate that {@link #mAutofillId} was explicitly set through 3491 * {@link #setAutofillId(AutofillId)}. 3492 */ 3493 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3494 3495 /** 3496 * Indicates if the View is a heading for accessibility purposes 3497 */ 3498 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3499 3500 /* End of masks for mPrivateFlags3 */ 3501 3502 /* 3503 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3504 * 3505 * |-------|-------|-------|-------| 3506 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3507 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3508 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3509 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3510 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3511 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3512 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3513 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3514 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3515 * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED 3516 * 1 PFLAG4_DETACHED 3517 * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE 3518 * |-------|-------|-------|-------| 3519 */ 3520 3521 /** 3522 * Mask for obtaining the bits which specify how to determine 3523 * whether a view is important for autofill. 3524 * 3525 * <p>NOTE: the important for content capture values were the first flags added and are set in 3526 * the rightmost position, so we don't need to shift them 3527 */ 3528 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3529 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3530 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3531 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3532 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3533 3534 /* 3535 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3536 * should be called. 3537 * 3538 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3539 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3540 */ 3541 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3542 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3543 3544 /* 3545 * Flags used to cache the value returned by isImportantForContentCapture while the view 3546 * hierarchy is being traversed. 3547 */ 3548 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3549 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3550 3551 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3552 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3553 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3554 3555 /** 3556 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3557 */ 3558 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3559 3560 /** 3561 * Flag indicating the field should not have yellow highlight when autofilled. 3562 */ 3563 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3564 3565 /** 3566 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3567 */ 3568 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3569 3570 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3571 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3572 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3573 3574 /** 3575 * Indicates if the view can receive click events when disabled. 3576 */ 3577 private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; 3578 3579 /** 3580 * Indicates if the view is just detached. 3581 */ 3582 private static final int PFLAG4_DETACHED = 0x000002000; 3583 3584 /** 3585 * Indicates that the view has transient state because the system is translating it. 3586 */ 3587 private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; 3588 3589 /* End of masks for mPrivateFlags4 */ 3590 3591 /** @hide */ 3592 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3593 /** @hide */ 3594 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3595 /** @hide */ 3596 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3597 3598 /** @hide */ 3599 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3600 VIEW_STRUCTURE_FOR_ASSIST, 3601 VIEW_STRUCTURE_FOR_AUTOFILL, 3602 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3603 }) 3604 @Retention(RetentionPolicy.SOURCE) 3605 public @interface ViewStructureType {} 3606 3607 /** 3608 * Always allow a user to over-scroll this view, provided it is a 3609 * view that can scroll. 3610 * 3611 * @see #getOverScrollMode() 3612 * @see #setOverScrollMode(int) 3613 */ 3614 public static final int OVER_SCROLL_ALWAYS = 0; 3615 3616 /** 3617 * Allow a user to over-scroll this view only if the content is large 3618 * enough to meaningfully scroll, provided it is a view that can scroll. 3619 * 3620 * @see #getOverScrollMode() 3621 * @see #setOverScrollMode(int) 3622 */ 3623 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3624 3625 /** 3626 * Never allow a user to over-scroll this view. 3627 * 3628 * @see #getOverScrollMode() 3629 * @see #setOverScrollMode(int) 3630 */ 3631 public static final int OVER_SCROLL_NEVER = 2; 3632 3633 /** 3634 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3635 * requested the system UI (status bar) to be visible (the default). 3636 * 3637 * @see #setSystemUiVisibility(int) 3638 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 3639 * instead. 3640 */ 3641 @Deprecated 3642 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3643 3644 /** 3645 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3646 * system UI to enter an unobtrusive "low profile" mode. 3647 * 3648 * <p>This is for use in games, book readers, video players, or any other 3649 * "immersive" application where the usual system chrome is deemed too distracting. 3650 * 3651 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3652 * 3653 * @see #setSystemUiVisibility(int) 3654 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 3655 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 3656 * {@link Type#systemBars()}. 3657 */ 3658 @Deprecated 3659 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3660 3661 /** 3662 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3663 * system navigation be temporarily hidden. 3664 * 3665 * <p>This is an even less obtrusive state than that called for by 3666 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3667 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3668 * those to disappear. This is useful (in conjunction with the 3669 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3670 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3671 * window flags) for displaying content using every last pixel on the display. 3672 * 3673 * <p>There is a limitation: because navigation controls are so important, the least user 3674 * interaction will cause them to reappear immediately. When this happens, both 3675 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3676 * so that both elements reappear at the same time. 3677 * 3678 * @see #setSystemUiVisibility(int) 3679 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 3680 * instead. 3681 */ 3682 @Deprecated 3683 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3684 3685 /** 3686 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3687 * into the normal fullscreen mode so that its content can take over the screen 3688 * while still allowing the user to interact with the application. 3689 * 3690 * <p>This has the same visual effect as 3691 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3692 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3693 * meaning that non-critical screen decorations (such as the status bar) will be 3694 * hidden while the user is in the View's window, focusing the experience on 3695 * that content. Unlike the window flag, if you are using ActionBar in 3696 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3697 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3698 * hide the action bar. 3699 * 3700 * <p>This approach to going fullscreen is best used over the window flag when 3701 * it is a transient state -- that is, the application does this at certain 3702 * points in its user interaction where it wants to allow the user to focus 3703 * on content, but not as a continuous state. For situations where the application 3704 * would like to simply stay full screen the entire time (such as a game that 3705 * wants to take over the screen), the 3706 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3707 * is usually a better approach. The state set here will be removed by the system 3708 * in various situations (such as the user moving to another application) like 3709 * the other system UI states. 3710 * 3711 * <p>When using this flag, the application should provide some easy facility 3712 * for the user to go out of it. A common example would be in an e-book 3713 * reader, where tapping on the screen brings back whatever screen and UI 3714 * decorations that had been hidden while the user was immersed in reading 3715 * the book. 3716 * 3717 * @see #setSystemUiVisibility(int) 3718 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 3719 * instead. 3720 */ 3721 @Deprecated 3722 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3723 3724 /** 3725 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3726 * flags, we would like a stable view of the content insets given to 3727 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3728 * will always represent the worst case that the application can expect 3729 * as a continuous state. In the stock Android UI this is the space for 3730 * the system bar, nav bar, and status bar, but not more transient elements 3731 * such as an input method. 3732 * 3733 * The stable layout your UI sees is based on the system UI modes you can 3734 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3735 * then you will get a stable layout for changes of the 3736 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3737 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3738 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3739 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3740 * with a stable layout. (Note that you should avoid using 3741 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3742 * 3743 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3744 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3745 * then a hidden status bar will be considered a "stable" state for purposes 3746 * here. This allows your UI to continually hide the status bar, while still 3747 * using the system UI flags to hide the action bar while still retaining 3748 * a stable layout. Note that changing the window fullscreen flag will never 3749 * provide a stable layout for a clean transition. 3750 * 3751 * <p>If you are using ActionBar in 3752 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3753 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3754 * insets it adds to those given to the application. 3755 * 3756 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 3757 * insets that don't change when system bars change visibility state. 3758 */ 3759 @Deprecated 3760 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3761 3762 /** 3763 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3764 * to be laid out as if it has requested 3765 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3766 * allows it to avoid artifacts when switching in and out of that mode, at 3767 * the expense that some of its user interface may be covered by screen 3768 * decorations when they are shown. You can perform layout of your inner 3769 * UI elements to account for the navigation system UI through the 3770 * {@link #fitSystemWindows(Rect)} method. 3771 * 3772 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3773 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 3774 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3775 */ 3776 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3777 3778 /** 3779 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3780 * to be laid out as if it has requested 3781 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3782 * allows it to avoid artifacts when switching in and out of that mode, at 3783 * the expense that some of its user interface may be covered by screen 3784 * decorations when they are shown. You can perform layout of your inner 3785 * UI elements to account for non-fullscreen system UI through the 3786 * {@link #fitSystemWindows(Rect)} method. 3787 * 3788 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3789 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3790 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3791 * layoutInDisplayCutoutMode} is 3792 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3793 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3794 * 3795 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3796 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3797 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3798 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3799 * 3800 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3801 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 3802 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3803 */ 3804 @Deprecated 3805 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3806 3807 /** 3808 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3809 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3810 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3811 * user interaction. 3812 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3813 * has an effect when used in combination with that flag.</p> 3814 * 3815 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead. 3816 */ 3817 @Deprecated 3818 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3819 3820 /** 3821 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3822 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3823 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3824 * experience while also hiding the system bars. If this flag is not set, 3825 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3826 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3827 * if the user swipes from the top of the screen. 3828 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3829 * system gestures, such as swiping from the top of the screen. These transient system bars 3830 * will overlay app's content, may have some degree of transparency, and will automatically 3831 * hide after a short timeout. 3832 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3833 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3834 * with one or both of those flags.</p> 3835 * 3836 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 3837 */ 3838 @Deprecated 3839 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3840 3841 /** 3842 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3843 * is compatible with light status bar backgrounds. 3844 * 3845 * <p>For this to take effect, the window must request 3846 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3847 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3848 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3849 * FLAG_TRANSLUCENT_STATUS}. 3850 * 3851 * @see android.R.attr#windowLightStatusBar 3852 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 3853 */ 3854 @Deprecated 3855 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3856 3857 /** 3858 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3859 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3860 */ 3861 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3862 3863 /** 3864 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3865 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3866 */ 3867 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3868 3869 /** 3870 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3871 * that is compatible with light navigation bar backgrounds. 3872 * 3873 * <p>For this to take effect, the window must request 3874 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3875 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3876 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3877 * FLAG_TRANSLUCENT_NAVIGATION}. 3878 * 3879 * @see android.R.attr#windowLightNavigationBar 3880 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 3881 */ 3882 @Deprecated 3883 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3884 3885 /** 3886 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3887 */ 3888 @Deprecated 3889 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3890 3891 /** 3892 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3893 */ 3894 @Deprecated 3895 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3896 3897 /** 3898 * @hide 3899 * 3900 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3901 * out of the public fields to keep the undefined bits out of the developer's way. 3902 * 3903 * Flag to make the status bar not expandable. Unless you also 3904 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3905 */ 3906 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3907 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3908 3909 /** 3910 * @hide 3911 * 3912 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3913 * out of the public fields to keep the undefined bits out of the developer's way. 3914 * 3915 * Flag to hide notification icons and scrolling ticker text. 3916 */ 3917 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3918 3919 /** 3920 * @hide 3921 * 3922 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3923 * out of the public fields to keep the undefined bits out of the developer's way. 3924 * 3925 * Flag to disable incoming notification alerts. This will not block 3926 * icons, but it will block sound, vibrating and other visual or aural notifications. 3927 */ 3928 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3929 3930 /** 3931 * @hide 3932 * 3933 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3934 * out of the public fields to keep the undefined bits out of the developer's way. 3935 * 3936 * Flag to hide only the scrolling ticker. Note that 3937 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3938 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3939 */ 3940 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3941 3942 /** 3943 * @hide 3944 * 3945 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3946 * out of the public fields to keep the undefined bits out of the developer's way. 3947 * 3948 * Flag to hide the center system info area. 3949 */ 3950 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3951 3952 /** 3953 * @hide 3954 * 3955 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3956 * out of the public fields to keep the undefined bits out of the developer's way. 3957 * 3958 * Flag to hide only the home button. Don't use this 3959 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3960 */ 3961 @UnsupportedAppUsage 3962 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3963 3964 /** 3965 * @hide 3966 * 3967 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3968 * out of the public fields to keep the undefined bits out of the developer's way. 3969 * 3970 * Flag to hide only the back button. Don't use this 3971 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3972 */ 3973 @UnsupportedAppUsage 3974 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3975 3976 /** 3977 * @hide 3978 * 3979 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3980 * out of the public fields to keep the undefined bits out of the developer's way. 3981 * 3982 * Flag to hide only the clock. You might use this if your activity has 3983 * its own clock making the status bar's clock redundant. 3984 */ 3985 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3986 3987 /** 3988 * @hide 3989 * 3990 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3991 * out of the public fields to keep the undefined bits out of the developer's way. 3992 * 3993 * Flag to hide only the recent apps button. Don't use this 3994 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3995 */ 3996 @UnsupportedAppUsage 3997 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3998 3999 /** 4000 * @hide 4001 * 4002 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4003 * out of the public fields to keep the undefined bits out of the developer's way. 4004 * 4005 * Flag to disable the global search gesture. Don't use this 4006 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4007 */ 4008 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 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 disable the ongoing call chip. 4017 */ 4018 public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; 4019 4020 /** 4021 * @hide 4022 */ 4023 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4024 4025 /** 4026 * These are the system UI flags that can be cleared by events outside 4027 * of an application. Currently this is just the ability to tap on the 4028 * screen while hiding the navigation bar to have it return. 4029 * @hide 4030 */ 4031 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4032 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4033 | SYSTEM_UI_FLAG_FULLSCREEN; 4034 4035 /** 4036 * Flags that can impact the layout in relation to system UI. 4037 * 4038 * @deprecated System UI layout flags are deprecated. 4039 */ 4040 @Deprecated 4041 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4042 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4043 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4044 4045 /** @hide */ 4046 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4047 FIND_VIEWS_WITH_TEXT, 4048 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4049 }) 4050 @Retention(RetentionPolicy.SOURCE) 4051 public @interface FindViewFlags {} 4052 4053 /** 4054 * Find views that render the specified text. 4055 * 4056 * @see #findViewsWithText(ArrayList, CharSequence, int) 4057 */ 4058 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4059 4060 /** 4061 * Find find views that contain the specified content description. 4062 * 4063 * @see #findViewsWithText(ArrayList, CharSequence, int) 4064 */ 4065 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4066 4067 /** 4068 * Find views that contain {@link AccessibilityNodeProvider}. Such 4069 * a View is a root of virtual view hierarchy and may contain the searched 4070 * text. If this flag is set Views with providers are automatically 4071 * added and it is a responsibility of the client to call the APIs of 4072 * the provider to determine whether the virtual tree rooted at this View 4073 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4074 * representing the virtual views with this text. 4075 * 4076 * @see #findViewsWithText(ArrayList, CharSequence, int) 4077 * 4078 * @hide 4079 */ 4080 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4081 4082 /** 4083 * The undefined cursor position. 4084 * 4085 * @hide 4086 */ 4087 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4088 4089 /** 4090 * Indicates that the screen has changed state and is now off. 4091 * 4092 * @see #onScreenStateChanged(int) 4093 */ 4094 public static final int SCREEN_STATE_OFF = 0x0; 4095 4096 /** 4097 * Indicates that the screen has changed state and is now on. 4098 * 4099 * @see #onScreenStateChanged(int) 4100 */ 4101 public static final int SCREEN_STATE_ON = 0x1; 4102 4103 /** 4104 * Indicates no axis of view scrolling. 4105 */ 4106 public static final int SCROLL_AXIS_NONE = 0; 4107 4108 /** 4109 * Indicates scrolling along the horizontal axis. 4110 */ 4111 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4112 4113 /** 4114 * Indicates scrolling along the vertical axis. 4115 */ 4116 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4117 4118 /** 4119 * Controls the over-scroll mode for this view. 4120 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4121 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4122 * and {@link #OVER_SCROLL_NEVER}. 4123 */ 4124 private int mOverScrollMode; 4125 4126 /** 4127 * The parent this view is attached to. 4128 * {@hide} 4129 * 4130 * @see #getParent() 4131 */ 4132 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4133 protected ViewParent mParent; 4134 4135 /** 4136 * {@hide} 4137 * 4138 * Not available for general use. If you need help, hang up and then dial one of the following 4139 * public APIs: 4140 * 4141 * @see #isAttachedToWindow() for current attach state 4142 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4143 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4144 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4145 * @see #getHandler() for posting messages to this view's UI thread/looper 4146 * @see #getParent() for interacting with the parent chain 4147 * @see #getWindowToken() for the current window token 4148 * @see #getRootView() for the view at the root of the attached hierarchy 4149 * @see #getDisplay() for the Display this view is presented on 4150 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4151 * @see #hasWindowFocus() for whether the attached window is currently focused 4152 * @see #getWindowVisibility() for checking the visibility of the attached window 4153 */ 4154 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4155 AttachInfo mAttachInfo; 4156 4157 /** 4158 * {@hide} 4159 */ 4160 @ViewDebug.ExportedProperty(flagMapping = { 4161 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4162 name = "FORCE_LAYOUT"), 4163 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4164 name = "LAYOUT_REQUIRED"), 4165 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4166 name = "DRAWING_CACHE_INVALID", outputIf = false), 4167 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4168 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4169 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4170 }, formatToHexString = true) 4171 4172 /* @hide */ 4173 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4174 public int mPrivateFlags; 4175 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4176 int mPrivateFlags2; 4177 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4178 int mPrivateFlags3; 4179 4180 private int mPrivateFlags4; 4181 4182 /** 4183 * This view's request for the visibility of the status bar. 4184 * @hide 4185 */ 4186 @ViewDebug.ExportedProperty(flagMapping = { 4187 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4188 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4189 name = "LOW_PROFILE"), 4190 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4191 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4192 name = "HIDE_NAVIGATION"), 4193 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4194 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4195 name = "FULLSCREEN"), 4196 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4197 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4198 name = "LAYOUT_STABLE"), 4199 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4200 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4201 name = "LAYOUT_HIDE_NAVIGATION"), 4202 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4203 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4204 name = "LAYOUT_FULLSCREEN"), 4205 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4206 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4207 name = "IMMERSIVE"), 4208 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4209 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4210 name = "IMMERSIVE_STICKY"), 4211 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4212 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4213 name = "LIGHT_STATUS_BAR"), 4214 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4215 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4216 name = "LIGHT_NAVIGATION_BAR"), 4217 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4218 equals = STATUS_BAR_DISABLE_EXPAND, 4219 name = "STATUS_BAR_DISABLE_EXPAND"), 4220 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4221 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4222 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4223 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4224 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4225 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4226 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4227 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4228 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4229 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4230 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4231 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4232 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4233 equals = STATUS_BAR_DISABLE_HOME, 4234 name = "STATUS_BAR_DISABLE_HOME"), 4235 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4236 equals = STATUS_BAR_DISABLE_BACK, 4237 name = "STATUS_BAR_DISABLE_BACK"), 4238 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4239 equals = STATUS_BAR_DISABLE_CLOCK, 4240 name = "STATUS_BAR_DISABLE_CLOCK"), 4241 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4242 equals = STATUS_BAR_DISABLE_RECENT, 4243 name = "STATUS_BAR_DISABLE_RECENT"), 4244 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4245 equals = STATUS_BAR_DISABLE_SEARCH, 4246 name = "STATUS_BAR_DISABLE_SEARCH"), 4247 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4248 equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4249 name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") 4250 }, formatToHexString = true) 4251 @SystemUiVisibility 4252 int mSystemUiVisibility; 4253 4254 /** 4255 * @hide 4256 */ 4257 @IntDef(flag = true, prefix = "", value = { 4258 SYSTEM_UI_FLAG_LOW_PROFILE, 4259 SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4260 SYSTEM_UI_FLAG_FULLSCREEN, 4261 SYSTEM_UI_FLAG_LAYOUT_STABLE, 4262 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4263 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4264 SYSTEM_UI_FLAG_IMMERSIVE, 4265 SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4266 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4267 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4268 STATUS_BAR_DISABLE_EXPAND, 4269 STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4270 STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4271 STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4272 STATUS_BAR_DISABLE_SYSTEM_INFO, 4273 STATUS_BAR_DISABLE_HOME, 4274 STATUS_BAR_DISABLE_BACK, 4275 STATUS_BAR_DISABLE_CLOCK, 4276 STATUS_BAR_DISABLE_RECENT, 4277 STATUS_BAR_DISABLE_SEARCH, 4278 STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4279 }) 4280 @Retention(RetentionPolicy.SOURCE) 4281 public @interface SystemUiVisibility {} 4282 4283 /** 4284 * Reference count for transient state. 4285 * @see #setHasTransientState(boolean) 4286 */ 4287 int mTransientStateCount = 0; 4288 4289 /** 4290 * Count of how many windows this view has been attached to. 4291 */ 4292 int mWindowAttachCount; 4293 4294 /** 4295 * The layout parameters associated with this view and used by the parent 4296 * {@link android.view.ViewGroup} to determine how this view should be 4297 * laid out. 4298 * 4299 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4300 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4301 * state correctness of the class. 4302 * {@hide} 4303 */ 4304 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4305 protected ViewGroup.LayoutParams mLayoutParams; 4306 4307 /** 4308 * The view flags hold various views states. 4309 * 4310 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4311 * triggering updates. 4312 * {@hide} 4313 */ 4314 @ViewDebug.ExportedProperty(formatToHexString = true) 4315 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4316 int mViewFlags; 4317 4318 static class TransformationInfo { 4319 /** 4320 * The transform matrix for the View. This transform is calculated internally 4321 * based on the translation, rotation, and scale properties. 4322 * 4323 * Do *not* use this variable directly; instead call getMatrix(), which will 4324 * load the value from the View's RenderNode. 4325 */ 4326 private final Matrix mMatrix = new Matrix(); 4327 4328 /** 4329 * The inverse transform matrix for the View. This transform is calculated 4330 * internally based on the translation, rotation, and scale properties. 4331 * 4332 * Do *not* use this variable directly; instead call getInverseMatrix(), 4333 * which will load the value from the View's RenderNode. 4334 */ 4335 private Matrix mInverseMatrix; 4336 4337 /** 4338 * The opacity of the View. This is a value from 0 to 1, where 0 means 4339 * completely transparent and 1 means completely opaque. 4340 */ 4341 @ViewDebug.ExportedProperty 4342 private float mAlpha = 1f; 4343 4344 /** 4345 * The opacity of the view as manipulated by the Fade transition. This is a 4346 * property only used by transitions, which is composited with the other alpha 4347 * values to calculate the final visual alpha value. 4348 */ 4349 float mTransitionAlpha = 1f; 4350 } 4351 4352 /** @hide */ 4353 @UnsupportedAppUsage 4354 public TransformationInfo mTransformationInfo; 4355 4356 /** 4357 * Current clip bounds. to which all drawing of this view are constrained. 4358 */ 4359 @ViewDebug.ExportedProperty(category = "drawing") 4360 Rect mClipBounds = null; 4361 4362 private boolean mLastIsOpaque; 4363 4364 /** 4365 * The distance in pixels from the left edge of this view's parent 4366 * to the left edge of this view. 4367 * {@hide} 4368 */ 4369 @ViewDebug.ExportedProperty(category = "layout") 4370 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4371 protected int mLeft; 4372 /** 4373 * The distance in pixels from the left edge of this view's parent 4374 * to the right edge of this view. 4375 * {@hide} 4376 */ 4377 @ViewDebug.ExportedProperty(category = "layout") 4378 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4379 protected int mRight; 4380 /** 4381 * The distance in pixels from the top edge of this view's parent 4382 * to the top edge of this view. 4383 * {@hide} 4384 */ 4385 @ViewDebug.ExportedProperty(category = "layout") 4386 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4387 protected int mTop; 4388 /** 4389 * The distance in pixels from the top edge of this view's parent 4390 * to the bottom edge of this view. 4391 * {@hide} 4392 */ 4393 @ViewDebug.ExportedProperty(category = "layout") 4394 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4395 protected int mBottom; 4396 4397 /** 4398 * The offset, in pixels, by which the content of this view is scrolled 4399 * horizontally. 4400 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4401 * accessing these directly. 4402 * {@hide} 4403 */ 4404 @ViewDebug.ExportedProperty(category = "scrolling") 4405 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4406 protected int mScrollX; 4407 /** 4408 * The offset, in pixels, by which the content of this view is scrolled 4409 * vertically. 4410 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4411 * accessing these directly. 4412 * {@hide} 4413 */ 4414 @ViewDebug.ExportedProperty(category = "scrolling") 4415 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4416 protected int mScrollY; 4417 4418 /** 4419 * The final computed left padding in pixels that is used for drawing. This is the distance in 4420 * pixels between the left edge of this view and the left edge of its content. 4421 * {@hide} 4422 */ 4423 @ViewDebug.ExportedProperty(category = "padding") 4424 @UnsupportedAppUsage 4425 protected int mPaddingLeft = 0; 4426 /** 4427 * The final computed right padding in pixels that is used for drawing. This is the distance in 4428 * pixels between the right edge of this view and the right edge of its content. 4429 * {@hide} 4430 */ 4431 @ViewDebug.ExportedProperty(category = "padding") 4432 @UnsupportedAppUsage 4433 protected int mPaddingRight = 0; 4434 /** 4435 * The final computed top padding in pixels that is used for drawing. This is the distance in 4436 * pixels between the top edge of this view and the top edge of its content. 4437 * {@hide} 4438 */ 4439 @ViewDebug.ExportedProperty(category = "padding") 4440 @UnsupportedAppUsage 4441 protected int mPaddingTop; 4442 /** 4443 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4444 * pixels between the bottom edge of this view and the bottom edge of its content. 4445 * {@hide} 4446 */ 4447 @ViewDebug.ExportedProperty(category = "padding") 4448 @UnsupportedAppUsage 4449 protected int mPaddingBottom; 4450 4451 /** 4452 * The layout insets in pixels, that is the distance in pixels between the 4453 * visible edges of this view its bounds. 4454 */ 4455 private Insets mLayoutInsets; 4456 4457 /** 4458 * Briefly describes the state of the view and is primarily used for accessibility support. 4459 */ 4460 private CharSequence mStateDescription; 4461 4462 /** 4463 * Briefly describes the view and is primarily used for accessibility support. 4464 */ 4465 private CharSequence mContentDescription; 4466 4467 /** 4468 * If this view represents a distinct part of the window, it can have a title that labels the 4469 * area. 4470 */ 4471 private CharSequence mAccessibilityPaneTitle; 4472 4473 /** 4474 * Specifies the id of a view for which this view serves as a label for 4475 * accessibility purposes. 4476 */ 4477 private int mLabelForId = View.NO_ID; 4478 4479 /** 4480 * Predicate for matching labeled view id with its label for 4481 * accessibility purposes. 4482 */ 4483 private MatchLabelForPredicate mMatchLabelForPredicate; 4484 4485 /** 4486 * Specifies a view before which this one is visited in accessibility traversal. 4487 */ 4488 private int mAccessibilityTraversalBeforeId = NO_ID; 4489 4490 /** 4491 * Specifies a view after which this one is visited in accessibility traversal. 4492 */ 4493 private int mAccessibilityTraversalAfterId = NO_ID; 4494 4495 /** 4496 * Predicate for matching a view by its id. 4497 */ 4498 private MatchIdPredicate mMatchIdPredicate; 4499 4500 /** 4501 * The right padding after RTL resolution, but before taking account of scroll bars. 4502 * 4503 * @hide 4504 */ 4505 @ViewDebug.ExportedProperty(category = "padding") 4506 protected int mUserPaddingRight; 4507 4508 /** 4509 * The resolved bottom padding before taking account of scroll bars. 4510 * 4511 * @hide 4512 */ 4513 @ViewDebug.ExportedProperty(category = "padding") 4514 protected int mUserPaddingBottom; 4515 4516 /** 4517 * The left padding after RTL resolution, but before taking account of scroll bars. 4518 * 4519 * @hide 4520 */ 4521 @ViewDebug.ExportedProperty(category = "padding") 4522 protected int mUserPaddingLeft; 4523 4524 /** 4525 * Cache the paddingStart set by the user to append to the scrollbar's size. 4526 * 4527 */ 4528 @ViewDebug.ExportedProperty(category = "padding") 4529 int mUserPaddingStart; 4530 4531 /** 4532 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4533 * 4534 */ 4535 @ViewDebug.ExportedProperty(category = "padding") 4536 int mUserPaddingEnd; 4537 4538 /** 4539 * The left padding as set by a setter method, a background's padding, or via XML property 4540 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4541 * 4542 * @hide 4543 */ 4544 int mUserPaddingLeftInitial; 4545 4546 /** 4547 * The right padding as set by a setter method, a background's padding, or via XML property 4548 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4549 * 4550 * @hide 4551 */ 4552 int mUserPaddingRightInitial; 4553 4554 /** 4555 * Default undefined padding 4556 */ 4557 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4558 4559 /** 4560 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4561 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4562 */ 4563 private boolean mLeftPaddingDefined = false; 4564 4565 /** 4566 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4567 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4568 */ 4569 private boolean mRightPaddingDefined = false; 4570 4571 /** 4572 * @hide 4573 */ 4574 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4575 /** 4576 * @hide 4577 */ 4578 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4579 4580 private LongSparseLongArray mMeasureCache; 4581 4582 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4583 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4584 private Drawable mBackground; 4585 private TintInfo mBackgroundTint; 4586 4587 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4588 private ForegroundInfo mForegroundInfo; 4589 4590 private Drawable mScrollIndicatorDrawable; 4591 4592 /** 4593 * RenderNode used for backgrounds. 4594 * <p> 4595 * When non-null and valid, this is expected to contain an up-to-date copy 4596 * of the background drawable. It is cleared on temporary detach, and reset 4597 * on cleanup. 4598 * @hide 4599 */ 4600 RenderNode mBackgroundRenderNode; 4601 4602 @UnsupportedAppUsage 4603 private int mBackgroundResource; 4604 private boolean mBackgroundSizeChanged; 4605 4606 /** The default focus highlight. 4607 * @see #mDefaultFocusHighlightEnabled 4608 * @see Drawable#hasFocusStateSpecified() 4609 */ 4610 private Drawable mDefaultFocusHighlight; 4611 private Drawable mDefaultFocusHighlightCache; 4612 private boolean mDefaultFocusHighlightSizeChanged; 4613 /** 4614 * True if the default focus highlight is needed on the target device. 4615 */ 4616 private static boolean sUseDefaultFocusHighlight; 4617 4618 /** 4619 * True if zero-sized views can be focused. 4620 */ 4621 private static boolean sCanFocusZeroSized; 4622 4623 /** 4624 * Always assign focus if a focusable View is available. 4625 */ 4626 private static boolean sAlwaysAssignFocus; 4627 4628 private String mTransitionName; 4629 4630 static class TintInfo { 4631 ColorStateList mTintList; 4632 BlendMode mBlendMode; 4633 boolean mHasTintMode; 4634 boolean mHasTintList; 4635 } 4636 4637 private static class ForegroundInfo { 4638 private Drawable mDrawable; 4639 private TintInfo mTintInfo; 4640 private int mGravity = Gravity.FILL; 4641 private boolean mInsidePadding = true; 4642 private boolean mBoundsChanged = true; 4643 private final Rect mSelfBounds = new Rect(); 4644 private final Rect mOverlayBounds = new Rect(); 4645 } 4646 4647 static class ListenerInfo { 4648 4649 @UnsupportedAppUsage ListenerInfo()4650 ListenerInfo() { 4651 } 4652 4653 /** 4654 * Listener used to dispatch focus change events. 4655 * This field should be made private, so it is hidden from the SDK. 4656 * {@hide} 4657 */ 4658 @UnsupportedAppUsage 4659 protected OnFocusChangeListener mOnFocusChangeListener; 4660 4661 /** 4662 * Listeners for layout change events. 4663 */ 4664 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4665 4666 protected OnScrollChangeListener mOnScrollChangeListener; 4667 4668 /** 4669 * Listeners for attach events. 4670 */ 4671 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4672 4673 /** 4674 * Listener used to dispatch click events. 4675 * This field should be made private, so it is hidden from the SDK. 4676 * {@hide} 4677 */ 4678 @UnsupportedAppUsage 4679 public OnClickListener mOnClickListener; 4680 4681 /** 4682 * Listener used to dispatch long click events. 4683 * This field should be made private, so it is hidden from the SDK. 4684 * {@hide} 4685 */ 4686 @UnsupportedAppUsage 4687 protected OnLongClickListener mOnLongClickListener; 4688 4689 /** 4690 * Listener used to dispatch context click events. This field should be made private, so it 4691 * is hidden from the SDK. 4692 * {@hide} 4693 */ 4694 protected OnContextClickListener mOnContextClickListener; 4695 4696 /** 4697 * Listener used to build the context menu. 4698 * This field should be made private, so it is hidden from the SDK. 4699 * {@hide} 4700 */ 4701 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4702 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4703 4704 @UnsupportedAppUsage 4705 private OnKeyListener mOnKeyListener; 4706 4707 @UnsupportedAppUsage 4708 private OnTouchListener mOnTouchListener; 4709 4710 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4711 private OnHoverListener mOnHoverListener; 4712 4713 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4714 private OnGenericMotionListener mOnGenericMotionListener; 4715 4716 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4717 private OnDragListener mOnDragListener; 4718 4719 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4720 4721 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4722 4723 OnCapturedPointerListener mOnCapturedPointerListener; 4724 4725 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4726 4727 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 4728 4729 /** 4730 * This lives here since it's only valid for interactive views. This list is null until the 4731 * first use. 4732 */ 4733 private List<Rect> mSystemGestureExclusionRects = null; 4734 4735 /** 4736 * Used to track {@link #mSystemGestureExclusionRects} 4737 */ 4738 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4739 4740 /** 4741 * Allows the application to implement custom scroll capture support. 4742 */ 4743 ScrollCaptureCallback mScrollCaptureCallback; 4744 4745 @Nullable 4746 private OnReceiveContentListener mOnReceiveContentListener; 4747 } 4748 4749 @UnsupportedAppUsage 4750 ListenerInfo mListenerInfo; 4751 4752 private static class TooltipInfo { 4753 /** 4754 * Text to be displayed in a tooltip popup. 4755 */ 4756 @Nullable 4757 CharSequence mTooltipText; 4758 4759 /** 4760 * View-relative position of the tooltip anchor point. 4761 */ 4762 int mAnchorX; 4763 int mAnchorY; 4764 4765 /** 4766 * The tooltip popup. 4767 */ 4768 @Nullable 4769 TooltipPopup mTooltipPopup; 4770 4771 /** 4772 * Set to true if the tooltip was shown as a result of a long click. 4773 */ 4774 boolean mTooltipFromLongClick; 4775 4776 /** 4777 * Keep these Runnables so that they can be used to reschedule. 4778 */ 4779 Runnable mShowTooltipRunnable; 4780 Runnable mHideTooltipRunnable; 4781 4782 /** 4783 * Hover move is ignored if it is within this distance in pixels from the previous one. 4784 */ 4785 int mHoverSlop; 4786 4787 /** 4788 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4789 * different from the previously stored position. Ignoring insignificant changes 4790 * filters out the jitter which is typical for such input sources as stylus. 4791 * 4792 * @return True if the position has been updated. 4793 */ updateAnchorPos(MotionEvent event)4794 private boolean updateAnchorPos(MotionEvent event) { 4795 final int newAnchorX = (int) event.getX(); 4796 final int newAnchorY = (int) event.getY(); 4797 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4798 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4799 return false; 4800 } 4801 mAnchorX = newAnchorX; 4802 mAnchorY = newAnchorY; 4803 return true; 4804 } 4805 4806 /** 4807 * Clear the anchor position to ensure that the next change is considered significant. 4808 */ clearAnchorPos()4809 private void clearAnchorPos() { 4810 mAnchorX = Integer.MAX_VALUE; 4811 mAnchorY = Integer.MAX_VALUE; 4812 } 4813 } 4814 4815 TooltipInfo mTooltipInfo; 4816 4817 // Temporary values used to hold (x,y) coordinates when delegating from the 4818 // two-arg performLongClick() method to the legacy no-arg version. 4819 private float mLongClickX = Float.NaN; 4820 private float mLongClickY = Float.NaN; 4821 4822 /** 4823 * The application environment this view lives in. 4824 * This field should be made private, so it is hidden from the SDK. 4825 * {@hide} 4826 */ 4827 @ViewDebug.ExportedProperty(deepExport = true) 4828 @UnsupportedAppUsage 4829 @UiContext 4830 protected Context mContext; 4831 4832 @UnsupportedAppUsage 4833 private final Resources mResources; 4834 4835 @UnsupportedAppUsage 4836 private ScrollabilityCache mScrollCache; 4837 4838 private int[] mDrawableState = null; 4839 4840 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4841 4842 /** 4843 * Animator that automatically runs based on state changes. 4844 */ 4845 private StateListAnimator mStateListAnimator; 4846 4847 /** 4848 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4849 * the user may specify which view to go to next. 4850 */ 4851 private int mNextFocusLeftId = View.NO_ID; 4852 4853 /** 4854 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4855 * the user may specify which view to go to next. 4856 */ 4857 private int mNextFocusRightId = View.NO_ID; 4858 4859 /** 4860 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4861 * the user may specify which view to go to next. 4862 */ 4863 private int mNextFocusUpId = View.NO_ID; 4864 4865 /** 4866 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4867 * the user may specify which view to go to next. 4868 */ 4869 private int mNextFocusDownId = View.NO_ID; 4870 4871 /** 4872 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4873 * the user may specify which view to go to next. 4874 */ 4875 int mNextFocusForwardId = View.NO_ID; 4876 4877 /** 4878 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4879 * 4880 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4881 */ 4882 int mNextClusterForwardId = View.NO_ID; 4883 4884 /** 4885 * Whether this View should use a default focus highlight when it gets focused but doesn't 4886 * have {@link android.R.attr#state_focused} defined in its background. 4887 */ 4888 boolean mDefaultFocusHighlightEnabled = true; 4889 4890 private CheckForLongPress mPendingCheckForLongPress; 4891 @UnsupportedAppUsage 4892 private CheckForTap mPendingCheckForTap = null; 4893 private PerformClick mPerformClick; 4894 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4895 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 4896 private UnsetPressedState mUnsetPressedState; 4897 4898 /** 4899 * Whether the long press's action has been invoked. The tap's action is invoked on the 4900 * up event while a long press is invoked as soon as the long press duration is reached, so 4901 * a long press could be performed before the tap is checked, in which case the tap's action 4902 * should not be invoked. 4903 */ 4904 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4905 private boolean mHasPerformedLongPress; 4906 4907 /** 4908 * Whether a context click button is currently pressed down. This is true when the stylus is 4909 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4910 * pressed. This is false once the button is released or if the stylus has been lifted. 4911 */ 4912 private boolean mInContextButtonPress; 4913 4914 /** 4915 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4916 * true after a stylus button press has occured, when the next up event should not be recognized 4917 * as a tap. 4918 */ 4919 private boolean mIgnoreNextUpEvent; 4920 4921 /** 4922 * The minimum height of the view. We'll try our best to have the height 4923 * of this view to at least this amount. 4924 */ 4925 @ViewDebug.ExportedProperty(category = "measurement") 4926 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4927 private int mMinHeight; 4928 4929 /** 4930 * The minimum width of the view. We'll try our best to have the width 4931 * of this view to at least this amount. 4932 */ 4933 @ViewDebug.ExportedProperty(category = "measurement") 4934 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4935 private int mMinWidth; 4936 4937 /** 4938 * The delegate to handle touch events that are physically in this view 4939 * but should be handled by another view. 4940 */ 4941 private TouchDelegate mTouchDelegate = null; 4942 4943 /** 4944 * While touch exploration is in use, set to true when hovering across boundaries and 4945 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 4946 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 4947 * {@link MotionEvent#ACTION_HOVER_EXIT}. 4948 * Note that children of view group are excluded in the touch area. 4949 * @see #dispatchTouchExplorationHoverEvent 4950 */ 4951 private boolean mHoveringTouchDelegate = false; 4952 4953 /** 4954 * Solid color to use as a background when creating the drawing cache. Enables 4955 * the cache to use 16 bit bitmaps instead of 32 bit. 4956 */ 4957 private int mDrawingCacheBackgroundColor = 0; 4958 4959 /** 4960 * Special tree observer used when mAttachInfo is null. 4961 */ 4962 private ViewTreeObserver mFloatingTreeObserver; 4963 4964 /** 4965 * Cache the touch slop from the context that created the view. 4966 */ 4967 private int mTouchSlop; 4968 4969 /** 4970 * Cache the ambiguous gesture multiplier from the context that created the view. 4971 */ 4972 private float mAmbiguousGestureMultiplier; 4973 4974 /** 4975 * Object that handles automatic animation of view properties. 4976 */ 4977 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4978 private ViewPropertyAnimator mAnimator = null; 4979 4980 /** 4981 * List of registered FrameMetricsObservers. 4982 */ 4983 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4984 4985 /** 4986 * Flag indicating that a drag can cross window boundaries. When 4987 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4988 * with this flag set, all visible applications with targetSdkVersion >= 4989 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4990 * in the drag operation and receive the dragged content. 4991 * 4992 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4993 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4994 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4995 */ 4996 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4997 4998 /** 4999 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5000 * request read access to the content URI(s) contained in the {@link ClipData} object. 5001 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5002 */ 5003 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5004 5005 /** 5006 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5007 * request write access to the content URI(s) contained in the {@link ClipData} object. 5008 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5009 */ 5010 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5011 5012 /** 5013 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5014 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5015 * reboots until explicitly revoked with 5016 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5017 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5018 */ 5019 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5020 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5021 5022 /** 5023 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5024 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5025 * match against the original granted URI. 5026 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5027 */ 5028 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5029 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5030 5031 /** 5032 * Flag indicating that the drag shadow will be opaque. When 5033 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5034 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5035 */ 5036 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5037 5038 /** 5039 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5040 */ 5041 private float mVerticalScrollFactor; 5042 5043 /** 5044 * Position of the vertical scroll bar. 5045 */ 5046 @UnsupportedAppUsage 5047 private int mVerticalScrollbarPosition; 5048 5049 /** 5050 * Position the scroll bar at the default position as determined by the system. 5051 */ 5052 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5053 5054 /** 5055 * Position the scroll bar along the left edge. 5056 */ 5057 public static final int SCROLLBAR_POSITION_LEFT = 1; 5058 5059 /** 5060 * Position the scroll bar along the right edge. 5061 */ 5062 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5063 5064 /** 5065 * Indicates that the view does not have a layer. 5066 * 5067 * @see #getLayerType() 5068 * @see #setLayerType(int, android.graphics.Paint) 5069 * @see #LAYER_TYPE_SOFTWARE 5070 * @see #LAYER_TYPE_HARDWARE 5071 */ 5072 public static final int LAYER_TYPE_NONE = 0; 5073 5074 /** 5075 * <p>Indicates that the view has a software layer. A software layer is backed 5076 * by a bitmap and causes the view to be rendered using Android's software 5077 * rendering pipeline, even if hardware acceleration is enabled.</p> 5078 * 5079 * <p>Software layers have various usages:</p> 5080 * <p>When the application is not using hardware acceleration, a software layer 5081 * is useful to apply a specific color filter and/or blending mode and/or 5082 * translucency to a view and all its children.</p> 5083 * <p>When the application is using hardware acceleration, a software layer 5084 * is useful to render drawing primitives not supported by the hardware 5085 * accelerated pipeline. It can also be used to cache a complex view tree 5086 * into a texture and reduce the complexity of drawing operations. For instance, 5087 * when animating a complex view tree with a translation, a software layer can 5088 * be used to render the view tree only once.</p> 5089 * <p>Software layers should be avoided when the affected view tree updates 5090 * often. Every update will require to re-render the software layer, which can 5091 * potentially be slow (particularly when hardware acceleration is turned on 5092 * since the layer will have to be uploaded into a hardware texture after every 5093 * update.)</p> 5094 * 5095 * @see #getLayerType() 5096 * @see #setLayerType(int, android.graphics.Paint) 5097 * @see #LAYER_TYPE_NONE 5098 * @see #LAYER_TYPE_HARDWARE 5099 */ 5100 public static final int LAYER_TYPE_SOFTWARE = 1; 5101 5102 /** 5103 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5104 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5105 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5106 * rendering pipeline, but only if hardware acceleration is turned on for the 5107 * view hierarchy. When hardware acceleration is turned off, hardware layers 5108 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5109 * 5110 * <p>A hardware layer is useful to apply a specific color filter and/or 5111 * blending mode and/or translucency to a view and all its children.</p> 5112 * <p>A hardware layer can be used to cache a complex view tree into a 5113 * texture and reduce the complexity of drawing operations. For instance, 5114 * when animating a complex view tree with a translation, a hardware layer can 5115 * be used to render the view tree only once.</p> 5116 * <p>A hardware layer can also be used to increase the rendering quality when 5117 * rotation transformations are applied on a view. It can also be used to 5118 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5119 * 5120 * @see #getLayerType() 5121 * @see #setLayerType(int, android.graphics.Paint) 5122 * @see #LAYER_TYPE_NONE 5123 * @see #LAYER_TYPE_SOFTWARE 5124 */ 5125 public static final int LAYER_TYPE_HARDWARE = 2; 5126 5127 /** @hide */ 5128 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5129 LAYER_TYPE_NONE, 5130 LAYER_TYPE_SOFTWARE, 5131 LAYER_TYPE_HARDWARE 5132 }) 5133 @Retention(RetentionPolicy.SOURCE) 5134 public @interface LayerType {} 5135 5136 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 5137 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 5138 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 5139 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 5140 }) 5141 int mLayerType = LAYER_TYPE_NONE; 5142 Paint mLayerPaint; 5143 5144 /** 5145 * Set to true when drawing cache is enabled and cannot be created. 5146 * 5147 * @hide 5148 */ 5149 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5150 public boolean mCachingFailed; 5151 @UnsupportedAppUsage 5152 private Bitmap mDrawingCache; 5153 @UnsupportedAppUsage 5154 private Bitmap mUnscaledDrawingCache; 5155 5156 /** 5157 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5158 * <p> 5159 * When non-null and valid, this is expected to contain an up-to-date copy 5160 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5161 * cleanup. 5162 */ 5163 @UnsupportedAppUsage 5164 final RenderNode mRenderNode; 5165 5166 /** 5167 * Set to true when the view is sending hover accessibility events because it 5168 * is the innermost hovered view. 5169 */ 5170 private boolean mSendingHoverAccessibilityEvents; 5171 5172 /** 5173 * Delegate for injecting accessibility functionality. 5174 */ 5175 @UnsupportedAppUsage 5176 AccessibilityDelegate mAccessibilityDelegate; 5177 5178 /** 5179 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5180 * and add/remove objects to/from the overlay directly through the Overlay methods. 5181 */ 5182 ViewOverlay mOverlay; 5183 5184 /** 5185 * The currently active parent view for receiving delegated nested scrolling events. 5186 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5187 * by {@link #stopNestedScroll()} at the same point where we clear 5188 * requestDisallowInterceptTouchEvent. 5189 */ 5190 private ViewParent mNestedScrollingParent; 5191 5192 /** 5193 * Consistency verifier for debugging purposes. 5194 * @hide 5195 */ 5196 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5197 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5198 new InputEventConsistencyVerifier(this, 0) : null; 5199 5200 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5201 5202 private int[] mTempNestedScrollConsumed; 5203 5204 /** 5205 * An overlay is going to draw this View instead of being drawn as part of this 5206 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5207 * when this view is invalidated. 5208 */ 5209 GhostView mGhostView; 5210 5211 /** 5212 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5213 * @hide 5214 */ 5215 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5216 public String[] mAttributes; 5217 5218 /** 5219 * Maps a Resource id to its name. 5220 */ 5221 private static SparseArray<String> mAttributeMap; 5222 5223 /** 5224 * Queue of pending runnables. Used to postpone calls to post() until this 5225 * view is attached and has a handler. 5226 */ 5227 private HandlerActionQueue mRunQueue; 5228 5229 /** 5230 * The pointer icon when the mouse hovers on this view. The default is null. 5231 */ 5232 private PointerIcon mPointerIcon; 5233 5234 /** 5235 * @hide 5236 */ 5237 @UnsupportedAppUsage 5238 String mStartActivityRequestWho; 5239 5240 @Nullable 5241 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5242 5243 /** Used to delay visibility updates sent to the autofill manager */ 5244 private Handler mVisibilityChangeForAutofillHandler; 5245 5246 /** 5247 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5248 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5249 */ 5250 @Nullable 5251 private ContentCaptureSession mContentCaptureSession; 5252 5253 /** 5254 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5255 */ 5256 private boolean mContentCaptureSessionCached; 5257 5258 @LayoutRes 5259 private int mSourceLayoutId = ID_NULL; 5260 5261 @Nullable 5262 private SparseIntArray mAttributeSourceResId; 5263 5264 @Nullable 5265 private SparseArray<int[]> mAttributeResolutionStacks; 5266 5267 @StyleRes 5268 private int mExplicitStyle; 5269 5270 /** 5271 * Specifies which input source classes should provide unbuffered input events to this view 5272 * 5273 * @see View#requestUnbufferedDispatch(int) 5274 */ 5275 @InputSourceClass 5276 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5277 5278 @Nullable 5279 private String[] mReceiveContentMimeTypes; 5280 5281 @Nullable 5282 private ViewTranslationCallback mViewTranslationCallback; 5283 5284 @Nullable 5285 5286 private ViewTranslationResponse mViewTranslationResponse; 5287 5288 /** 5289 * Simple constructor to use when creating a view from code. 5290 * 5291 * @param context The Context the view is running in, through which it can 5292 * access the current theme, resources, etc. 5293 */ View(Context context)5294 public View(Context context) { 5295 mContext = context; 5296 mResources = context != null ? context.getResources() : null; 5297 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5298 // Set some flags defaults 5299 mPrivateFlags2 = 5300 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5301 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5302 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5303 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5304 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5305 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5306 5307 final ViewConfiguration configuration = ViewConfiguration.get(context); 5308 mTouchSlop = configuration.getScaledTouchSlop(); 5309 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5310 5311 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5312 mUserPaddingStart = UNDEFINED_PADDING; 5313 mUserPaddingEnd = UNDEFINED_PADDING; 5314 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5315 5316 if (!sCompatibilityDone && context != null) { 5317 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5318 5319 // Older apps may need this compatibility hack for measurement. 5320 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5321 5322 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5323 // of whether a layout was requested on that View. 5324 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 5325 5326 // In M and newer, our widgets can pass a "hint" value in the size 5327 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 5328 // know what the expected parent size is going to be, so e.g. list items can size 5329 // themselves at 1/3 the size of their container. It breaks older apps though, 5330 // specifically apps that use some popular open source libraries. 5331 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 5332 5333 // Old versions of the platform would give different results from 5334 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5335 // modes, so we always need to run an additional EXACTLY pass. 5336 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5337 5338 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5339 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5340 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5341 5342 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5343 // in apps so we target check it to avoid breaking existing apps. 5344 sPreserveMarginParamsInLayoutParamConversion = 5345 targetSdkVersion >= Build.VERSION_CODES.N; 5346 5347 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5348 5349 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5350 5351 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5352 5353 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5354 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5355 5356 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5357 5358 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5359 5360 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5361 5362 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5363 5364 sBrokenInsetsDispatch = targetSdkVersion < Build.VERSION_CODES.R; 5365 5366 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5367 5368 GradientDrawable.sWrapNegativeAngleMeasurements = 5369 targetSdkVersion >= Build.VERSION_CODES.Q; 5370 5371 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5372 5373 sCompatibilityDone = true; 5374 } 5375 } 5376 5377 /** 5378 * Constructor that is called when inflating a view from XML. This is called 5379 * when a view is being constructed from an XML file, supplying attributes 5380 * that were specified in the XML file. This version uses a default style of 5381 * 0, so the only attribute values applied are those in the Context's Theme 5382 * and the given AttributeSet. 5383 * 5384 * <p> 5385 * The method onFinishInflate() will be called after all children have been 5386 * added. 5387 * 5388 * @param context The Context the view is running in, through which it can 5389 * access the current theme, resources, etc. 5390 * @param attrs The attributes of the XML tag that is inflating the view. 5391 * @see #View(Context, AttributeSet, int) 5392 */ 5393 public View(Context context, @Nullable AttributeSet attrs) { 5394 this(context, attrs, 0); 5395 } 5396 5397 /** 5398 * Perform inflation from XML and apply a class-specific base style from a 5399 * theme attribute. This constructor of View allows subclasses to use their 5400 * own base style when they are inflating. For example, a Button class's 5401 * constructor would call this version of the super class constructor and 5402 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5403 * allows the theme's button style to modify all of the base view attributes 5404 * (in particular its background) as well as the Button class's attributes. 5405 * 5406 * @param context The Context the view is running in, through which it can 5407 * access the current theme, resources, etc. 5408 * @param attrs The attributes of the XML tag that is inflating the view. 5409 * @param defStyleAttr An attribute in the current theme that contains a 5410 * reference to a style resource that supplies default values for 5411 * the view. Can be 0 to not look for defaults. 5412 * @see #View(Context, AttributeSet) 5413 */ 5414 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5415 this(context, attrs, defStyleAttr, 0); 5416 } 5417 5418 /** 5419 * Perform inflation from XML and apply a class-specific base style from a 5420 * theme attribute or style resource. This constructor of View allows 5421 * subclasses to use their own base style when they are inflating. 5422 * <p> 5423 * When determining the final value of a particular attribute, there are 5424 * four inputs that come into play: 5425 * <ol> 5426 * <li>Any attribute values in the given AttributeSet. 5427 * <li>The style resource specified in the AttributeSet (named "style"). 5428 * <li>The default style specified by <var>defStyleAttr</var>. 5429 * <li>The default style specified by <var>defStyleRes</var>. 5430 * <li>The base values in this theme. 5431 * </ol> 5432 * <p> 5433 * Each of these inputs is considered in-order, with the first listed taking 5434 * precedence over the following ones. In other words, if in the 5435 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5436 * , then the button's text will <em>always</em> be black, regardless of 5437 * what is specified in any of the styles. 5438 * 5439 * @param context The Context the view is running in, through which it can 5440 * access the current theme, resources, etc. 5441 * @param attrs The attributes of the XML tag that is inflating the view. 5442 * @param defStyleAttr An attribute in the current theme that contains a 5443 * reference to a style resource that supplies default values for 5444 * the view. Can be 0 to not look for defaults. 5445 * @param defStyleRes A resource identifier of a style resource that 5446 * supplies default values for the view, used only if 5447 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5448 * to not look for defaults. 5449 * @see #View(Context, AttributeSet, int) 5450 */ 5451 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5452 this(context); 5453 5454 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5455 5456 final TypedArray a = context.obtainStyledAttributes( 5457 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5458 5459 retrieveExplicitStyle(context.getTheme(), attrs); 5460 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5461 defStyleAttr, defStyleRes); 5462 5463 if (sDebugViewAttributes) { 5464 saveAttributeData(attrs, a); 5465 } 5466 5467 Drawable background = null; 5468 5469 int leftPadding = -1; 5470 int topPadding = -1; 5471 int rightPadding = -1; 5472 int bottomPadding = -1; 5473 int startPadding = UNDEFINED_PADDING; 5474 int endPadding = UNDEFINED_PADDING; 5475 5476 int padding = -1; 5477 int paddingHorizontal = -1; 5478 int paddingVertical = -1; 5479 5480 int viewFlagValues = 0; 5481 int viewFlagMasks = 0; 5482 5483 boolean setScrollContainer = false; 5484 5485 int x = 0; 5486 int y = 0; 5487 5488 float tx = 0; 5489 float ty = 0; 5490 float tz = 0; 5491 float elevation = 0; 5492 float rotation = 0; 5493 float rotationX = 0; 5494 float rotationY = 0; 5495 float sx = 1f; 5496 float sy = 1f; 5497 boolean transformSet = false; 5498 5499 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5500 int overScrollMode = mOverScrollMode; 5501 boolean initializeScrollbars = false; 5502 boolean initializeScrollIndicators = false; 5503 5504 boolean startPaddingDefined = false; 5505 boolean endPaddingDefined = false; 5506 boolean leftPaddingDefined = false; 5507 boolean rightPaddingDefined = false; 5508 5509 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5510 5511 // Set default values. 5512 viewFlagValues |= FOCUSABLE_AUTO; 5513 viewFlagMasks |= FOCUSABLE_AUTO; 5514 5515 final int N = a.getIndexCount(); 5516 for (int i = 0; i < N; i++) { 5517 int attr = a.getIndex(i); 5518 switch (attr) { 5519 case com.android.internal.R.styleable.View_background: 5520 background = a.getDrawable(attr); 5521 break; 5522 case com.android.internal.R.styleable.View_padding: 5523 padding = a.getDimensionPixelSize(attr, -1); 5524 mUserPaddingLeftInitial = padding; 5525 mUserPaddingRightInitial = padding; 5526 leftPaddingDefined = true; 5527 rightPaddingDefined = true; 5528 break; 5529 case com.android.internal.R.styleable.View_paddingHorizontal: 5530 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5531 mUserPaddingLeftInitial = paddingHorizontal; 5532 mUserPaddingRightInitial = paddingHorizontal; 5533 leftPaddingDefined = true; 5534 rightPaddingDefined = true; 5535 break; 5536 case com.android.internal.R.styleable.View_paddingVertical: 5537 paddingVertical = a.getDimensionPixelSize(attr, -1); 5538 break; 5539 case com.android.internal.R.styleable.View_paddingLeft: 5540 leftPadding = a.getDimensionPixelSize(attr, -1); 5541 mUserPaddingLeftInitial = leftPadding; 5542 leftPaddingDefined = true; 5543 break; 5544 case com.android.internal.R.styleable.View_paddingTop: 5545 topPadding = a.getDimensionPixelSize(attr, -1); 5546 break; 5547 case com.android.internal.R.styleable.View_paddingRight: 5548 rightPadding = a.getDimensionPixelSize(attr, -1); 5549 mUserPaddingRightInitial = rightPadding; 5550 rightPaddingDefined = true; 5551 break; 5552 case com.android.internal.R.styleable.View_paddingBottom: 5553 bottomPadding = a.getDimensionPixelSize(attr, -1); 5554 break; 5555 case com.android.internal.R.styleable.View_paddingStart: 5556 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5557 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5558 break; 5559 case com.android.internal.R.styleable.View_paddingEnd: 5560 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5561 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5562 break; 5563 case com.android.internal.R.styleable.View_scrollX: 5564 x = a.getDimensionPixelOffset(attr, 0); 5565 break; 5566 case com.android.internal.R.styleable.View_scrollY: 5567 y = a.getDimensionPixelOffset(attr, 0); 5568 break; 5569 case com.android.internal.R.styleable.View_alpha: 5570 setAlpha(a.getFloat(attr, 1f)); 5571 break; 5572 case com.android.internal.R.styleable.View_transformPivotX: 5573 setPivotX(a.getDimension(attr, 0)); 5574 break; 5575 case com.android.internal.R.styleable.View_transformPivotY: 5576 setPivotY(a.getDimension(attr, 0)); 5577 break; 5578 case com.android.internal.R.styleable.View_translationX: 5579 tx = a.getDimension(attr, 0); 5580 transformSet = true; 5581 break; 5582 case com.android.internal.R.styleable.View_translationY: 5583 ty = a.getDimension(attr, 0); 5584 transformSet = true; 5585 break; 5586 case com.android.internal.R.styleable.View_translationZ: 5587 tz = a.getDimension(attr, 0); 5588 transformSet = true; 5589 break; 5590 case com.android.internal.R.styleable.View_elevation: 5591 elevation = a.getDimension(attr, 0); 5592 transformSet = true; 5593 break; 5594 case com.android.internal.R.styleable.View_rotation: 5595 rotation = a.getFloat(attr, 0); 5596 transformSet = true; 5597 break; 5598 case com.android.internal.R.styleable.View_rotationX: 5599 rotationX = a.getFloat(attr, 0); 5600 transformSet = true; 5601 break; 5602 case com.android.internal.R.styleable.View_rotationY: 5603 rotationY = a.getFloat(attr, 0); 5604 transformSet = true; 5605 break; 5606 case com.android.internal.R.styleable.View_scaleX: 5607 sx = a.getFloat(attr, 1f); 5608 transformSet = true; 5609 break; 5610 case com.android.internal.R.styleable.View_scaleY: 5611 sy = a.getFloat(attr, 1f); 5612 transformSet = true; 5613 break; 5614 case com.android.internal.R.styleable.View_id: 5615 mID = a.getResourceId(attr, NO_ID); 5616 break; 5617 case com.android.internal.R.styleable.View_tag: 5618 mTag = a.getText(attr); 5619 break; 5620 case com.android.internal.R.styleable.View_fitsSystemWindows: 5621 if (a.getBoolean(attr, false)) { 5622 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5623 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5624 } 5625 break; 5626 case com.android.internal.R.styleable.View_focusable: 5627 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5628 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5629 viewFlagMasks |= FOCUSABLE_MASK; 5630 } 5631 break; 5632 case com.android.internal.R.styleable.View_focusableInTouchMode: 5633 if (a.getBoolean(attr, false)) { 5634 // unset auto focus since focusableInTouchMode implies explicit focusable 5635 viewFlagValues &= ~FOCUSABLE_AUTO; 5636 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5637 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5638 } 5639 break; 5640 case com.android.internal.R.styleable.View_clickable: 5641 if (a.getBoolean(attr, false)) { 5642 viewFlagValues |= CLICKABLE; 5643 viewFlagMasks |= CLICKABLE; 5644 } 5645 break; 5646 case com.android.internal.R.styleable.View_allowClickWhenDisabled: 5647 setAllowClickWhenDisabled(a.getBoolean(attr, false)); 5648 break; 5649 case com.android.internal.R.styleable.View_longClickable: 5650 if (a.getBoolean(attr, false)) { 5651 viewFlagValues |= LONG_CLICKABLE; 5652 viewFlagMasks |= LONG_CLICKABLE; 5653 } 5654 break; 5655 case com.android.internal.R.styleable.View_contextClickable: 5656 if (a.getBoolean(attr, false)) { 5657 viewFlagValues |= CONTEXT_CLICKABLE; 5658 viewFlagMasks |= CONTEXT_CLICKABLE; 5659 } 5660 break; 5661 case com.android.internal.R.styleable.View_saveEnabled: 5662 if (!a.getBoolean(attr, true)) { 5663 viewFlagValues |= SAVE_DISABLED; 5664 viewFlagMasks |= SAVE_DISABLED_MASK; 5665 } 5666 break; 5667 case com.android.internal.R.styleable.View_duplicateParentState: 5668 if (a.getBoolean(attr, false)) { 5669 viewFlagValues |= DUPLICATE_PARENT_STATE; 5670 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5671 } 5672 break; 5673 case com.android.internal.R.styleable.View_visibility: 5674 final int visibility = a.getInt(attr, 0); 5675 if (visibility != 0) { 5676 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5677 viewFlagMasks |= VISIBILITY_MASK; 5678 } 5679 break; 5680 case com.android.internal.R.styleable.View_layoutDirection: 5681 // Clear any layout direction flags (included resolved bits) already set 5682 mPrivateFlags2 &= 5683 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5684 // Set the layout direction flags depending on the value of the attribute 5685 final int layoutDirection = a.getInt(attr, -1); 5686 final int value = (layoutDirection != -1) ? 5687 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5688 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5689 break; 5690 case com.android.internal.R.styleable.View_drawingCacheQuality: 5691 final int cacheQuality = a.getInt(attr, 0); 5692 if (cacheQuality != 0) { 5693 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5694 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5695 } 5696 break; 5697 case com.android.internal.R.styleable.View_contentDescription: 5698 setContentDescription(a.getString(attr)); 5699 break; 5700 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5701 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5702 break; 5703 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5704 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5705 break; 5706 case com.android.internal.R.styleable.View_labelFor: 5707 setLabelFor(a.getResourceId(attr, NO_ID)); 5708 break; 5709 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5710 if (!a.getBoolean(attr, true)) { 5711 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5712 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5713 } 5714 break; 5715 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5716 if (!a.getBoolean(attr, true)) { 5717 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5718 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5719 } 5720 break; 5721 case R.styleable.View_scrollbars: 5722 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5723 if (scrollbars != SCROLLBARS_NONE) { 5724 viewFlagValues |= scrollbars; 5725 viewFlagMasks |= SCROLLBARS_MASK; 5726 initializeScrollbars = true; 5727 } 5728 break; 5729 //noinspection deprecation 5730 case R.styleable.View_fadingEdge: 5731 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5732 // Ignore the attribute starting with ICS 5733 break; 5734 } 5735 // With builds < ICS, fall through and apply fading edges 5736 case R.styleable.View_requiresFadingEdge: 5737 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5738 if (fadingEdge != FADING_EDGE_NONE) { 5739 viewFlagValues |= fadingEdge; 5740 viewFlagMasks |= FADING_EDGE_MASK; 5741 initializeFadingEdgeInternal(a); 5742 } 5743 break; 5744 case R.styleable.View_scrollbarStyle: 5745 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5746 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5747 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5748 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5749 } 5750 break; 5751 case R.styleable.View_isScrollContainer: 5752 setScrollContainer = true; 5753 if (a.getBoolean(attr, false)) { 5754 setScrollContainer(true); 5755 } 5756 break; 5757 case com.android.internal.R.styleable.View_keepScreenOn: 5758 if (a.getBoolean(attr, false)) { 5759 viewFlagValues |= KEEP_SCREEN_ON; 5760 viewFlagMasks |= KEEP_SCREEN_ON; 5761 } 5762 break; 5763 case R.styleable.View_filterTouchesWhenObscured: 5764 if (a.getBoolean(attr, false)) { 5765 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5766 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5767 } 5768 break; 5769 case R.styleable.View_nextFocusLeft: 5770 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5771 break; 5772 case R.styleable.View_nextFocusRight: 5773 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5774 break; 5775 case R.styleable.View_nextFocusUp: 5776 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5777 break; 5778 case R.styleable.View_nextFocusDown: 5779 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5780 break; 5781 case R.styleable.View_nextFocusForward: 5782 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5783 break; 5784 case R.styleable.View_nextClusterForward: 5785 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5786 break; 5787 case R.styleable.View_minWidth: 5788 mMinWidth = a.getDimensionPixelSize(attr, 0); 5789 break; 5790 case R.styleable.View_minHeight: 5791 mMinHeight = a.getDimensionPixelSize(attr, 0); 5792 break; 5793 case R.styleable.View_onClick: 5794 if (context.isRestricted()) { 5795 throw new IllegalStateException("The android:onClick attribute cannot " 5796 + "be used within a restricted context"); 5797 } 5798 5799 final String handlerName = a.getString(attr); 5800 if (handlerName != null) { 5801 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5802 } 5803 break; 5804 case R.styleable.View_overScrollMode: 5805 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5806 break; 5807 case R.styleable.View_verticalScrollbarPosition: 5808 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5809 break; 5810 case R.styleable.View_layerType: 5811 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5812 break; 5813 case R.styleable.View_textDirection: 5814 // Clear any text direction flag already set 5815 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5816 // Set the text direction flags depending on the value of the attribute 5817 final int textDirection = a.getInt(attr, -1); 5818 if (textDirection != -1) { 5819 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5820 } 5821 break; 5822 case R.styleable.View_textAlignment: 5823 // Clear any text alignment flag already set 5824 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5825 // Set the text alignment flag depending on the value of the attribute 5826 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5827 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5828 break; 5829 case R.styleable.View_importantForAccessibility: 5830 setImportantForAccessibility(a.getInt(attr, 5831 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5832 break; 5833 case R.styleable.View_accessibilityLiveRegion: 5834 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5835 break; 5836 case R.styleable.View_transitionName: 5837 setTransitionName(a.getString(attr)); 5838 break; 5839 case R.styleable.View_nestedScrollingEnabled: 5840 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5841 break; 5842 case R.styleable.View_stateListAnimator: 5843 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5844 a.getResourceId(attr, 0))); 5845 break; 5846 case R.styleable.View_backgroundTint: 5847 // This will get applied later during setBackground(). 5848 if (mBackgroundTint == null) { 5849 mBackgroundTint = new TintInfo(); 5850 } 5851 mBackgroundTint.mTintList = a.getColorStateList( 5852 R.styleable.View_backgroundTint); 5853 mBackgroundTint.mHasTintList = true; 5854 break; 5855 case R.styleable.View_backgroundTintMode: 5856 // This will get applied later during setBackground(). 5857 if (mBackgroundTint == null) { 5858 mBackgroundTint = new TintInfo(); 5859 } 5860 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 5861 R.styleable.View_backgroundTintMode, -1), null); 5862 mBackgroundTint.mHasTintMode = true; 5863 break; 5864 case R.styleable.View_outlineProvider: 5865 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5866 PROVIDER_BACKGROUND)); 5867 break; 5868 case R.styleable.View_foreground: 5869 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5870 setForeground(a.getDrawable(attr)); 5871 } 5872 break; 5873 case R.styleable.View_foregroundGravity: 5874 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5875 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5876 } 5877 break; 5878 case R.styleable.View_foregroundTintMode: 5879 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5880 setForegroundTintBlendMode( 5881 Drawable.parseBlendMode(a.getInt(attr, -1), 5882 null)); 5883 } 5884 break; 5885 case R.styleable.View_foregroundTint: 5886 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5887 setForegroundTintList(a.getColorStateList(attr)); 5888 } 5889 break; 5890 case R.styleable.View_foregroundInsidePadding: 5891 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5892 if (mForegroundInfo == null) { 5893 mForegroundInfo = new ForegroundInfo(); 5894 } 5895 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5896 mForegroundInfo.mInsidePadding); 5897 } 5898 break; 5899 case R.styleable.View_scrollIndicators: 5900 final int scrollIndicators = 5901 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5902 & SCROLL_INDICATORS_PFLAG3_MASK; 5903 if (scrollIndicators != 0) { 5904 mPrivateFlags3 |= scrollIndicators; 5905 initializeScrollIndicators = true; 5906 } 5907 break; 5908 case R.styleable.View_pointerIcon: 5909 final int resourceId = a.getResourceId(attr, 0); 5910 if (resourceId != 0) { 5911 setPointerIcon(PointerIcon.load( 5912 context.getResources(), resourceId)); 5913 } else { 5914 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5915 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5916 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5917 } 5918 } 5919 break; 5920 case R.styleable.View_forceHasOverlappingRendering: 5921 if (a.peekValue(attr) != null) { 5922 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5923 } 5924 break; 5925 case R.styleable.View_tooltipText: 5926 setTooltipText(a.getText(attr)); 5927 break; 5928 case R.styleable.View_keyboardNavigationCluster: 5929 if (a.peekValue(attr) != null) { 5930 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5931 } 5932 break; 5933 case R.styleable.View_focusedByDefault: 5934 if (a.peekValue(attr) != null) { 5935 setFocusedByDefault(a.getBoolean(attr, true)); 5936 } 5937 break; 5938 case R.styleable.View_autofillHints: 5939 if (a.peekValue(attr) != null) { 5940 CharSequence[] rawHints = null; 5941 String rawString = null; 5942 5943 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5944 int resId = a.getResourceId(attr, 0); 5945 5946 try { 5947 rawHints = a.getTextArray(attr); 5948 } catch (Resources.NotFoundException e) { 5949 rawString = getResources().getString(resId); 5950 } 5951 } else { 5952 rawString = a.getString(attr); 5953 } 5954 5955 if (rawHints == null) { 5956 if (rawString == null) { 5957 throw new IllegalArgumentException( 5958 "Could not resolve autofillHints"); 5959 } else { 5960 rawHints = rawString.split(","); 5961 } 5962 } 5963 5964 String[] hints = new String[rawHints.length]; 5965 5966 int numHints = rawHints.length; 5967 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5968 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5969 } 5970 setAutofillHints(hints); 5971 } 5972 break; 5973 case R.styleable.View_importantForAutofill: 5974 if (a.peekValue(attr) != null) { 5975 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5976 } 5977 break; 5978 case R.styleable.View_importantForContentCapture: 5979 if (a.peekValue(attr) != null) { 5980 setImportantForContentCapture(a.getInt(attr, 5981 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 5982 } 5983 case R.styleable.View_defaultFocusHighlightEnabled: 5984 if (a.peekValue(attr) != null) { 5985 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5986 } 5987 break; 5988 case R.styleable.View_screenReaderFocusable: 5989 if (a.peekValue(attr) != null) { 5990 setScreenReaderFocusable(a.getBoolean(attr, false)); 5991 } 5992 break; 5993 case R.styleable.View_accessibilityPaneTitle: 5994 if (a.peekValue(attr) != null) { 5995 setAccessibilityPaneTitle(a.getString(attr)); 5996 } 5997 break; 5998 case R.styleable.View_outlineSpotShadowColor: 5999 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6000 break; 6001 case R.styleable.View_outlineAmbientShadowColor: 6002 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6003 break; 6004 case com.android.internal.R.styleable.View_accessibilityHeading: 6005 setAccessibilityHeading(a.getBoolean(attr, false)); 6006 break; 6007 case R.styleable.View_forceDarkAllowed: 6008 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6009 break; 6010 case R.styleable.View_scrollCaptureHint: 6011 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6012 break; 6013 case R.styleable.View_clipToOutline: 6014 setClipToOutline(a.getBoolean(attr, false)); 6015 break; 6016 } 6017 } 6018 6019 setOverScrollMode(overScrollMode); 6020 6021 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6022 // the resolved layout direction). Those cached values will be used later during padding 6023 // resolution. 6024 mUserPaddingStart = startPadding; 6025 mUserPaddingEnd = endPadding; 6026 6027 if (background != null) { 6028 setBackground(background); 6029 } 6030 6031 // setBackground above will record that padding is currently provided by the background. 6032 // If we have padding specified via xml, record that here instead and use it. 6033 mLeftPaddingDefined = leftPaddingDefined; 6034 mRightPaddingDefined = rightPaddingDefined; 6035 6036 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6037 // bottomPadding, and padding set by background. Valid padding beats everything. 6038 if (padding >= 0) { 6039 leftPadding = padding; 6040 topPadding = padding; 6041 rightPadding = padding; 6042 bottomPadding = padding; 6043 mUserPaddingLeftInitial = padding; 6044 mUserPaddingRightInitial = padding; 6045 } else { 6046 if (paddingHorizontal >= 0) { 6047 leftPadding = paddingHorizontal; 6048 rightPadding = paddingHorizontal; 6049 mUserPaddingLeftInitial = paddingHorizontal; 6050 mUserPaddingRightInitial = paddingHorizontal; 6051 } 6052 if (paddingVertical >= 0) { 6053 topPadding = paddingVertical; 6054 bottomPadding = paddingVertical; 6055 } 6056 } 6057 6058 if (isRtlCompatibilityMode()) { 6059 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6060 // left / right padding are used if defined (meaning here nothing to do). If they are not 6061 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6062 // start / end and resolve them as left / right (layout direction is not taken into account). 6063 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6064 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6065 // defined. 6066 if (!mLeftPaddingDefined && startPaddingDefined) { 6067 leftPadding = startPadding; 6068 } 6069 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6070 if (!mRightPaddingDefined && endPaddingDefined) { 6071 rightPadding = endPadding; 6072 } 6073 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6074 } else { 6075 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6076 // values defined. Otherwise, left /right values are used. 6077 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6078 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6079 // defined. 6080 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6081 6082 if (mLeftPaddingDefined && !hasRelativePadding) { 6083 mUserPaddingLeftInitial = leftPadding; 6084 } 6085 if (mRightPaddingDefined && !hasRelativePadding) { 6086 mUserPaddingRightInitial = rightPadding; 6087 } 6088 } 6089 6090 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6091 // them on if topPadding or bottomPadding are not valid. 6092 internalSetPadding( 6093 mUserPaddingLeftInitial, 6094 topPadding >= 0 ? topPadding : mPaddingTop, 6095 mUserPaddingRightInitial, 6096 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6097 6098 if (viewFlagMasks != 0) { 6099 setFlags(viewFlagValues, viewFlagMasks); 6100 } 6101 6102 if (initializeScrollbars) { 6103 initializeScrollbarsInternal(a); 6104 } 6105 6106 if (initializeScrollIndicators) { 6107 initializeScrollIndicatorsInternal(); 6108 } 6109 6110 a.recycle(); 6111 6112 // Needs to be called after mViewFlags is set 6113 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6114 recomputePadding(); 6115 } 6116 6117 if (x != 0 || y != 0) { 6118 scrollTo(x, y); 6119 } 6120 6121 if (transformSet) { 6122 setTranslationX(tx); 6123 setTranslationY(ty); 6124 setTranslationZ(tz); 6125 setElevation(elevation); 6126 setRotation(rotation); 6127 setRotationX(rotationX); 6128 setRotationY(rotationY); 6129 setScaleX(sx); 6130 setScaleY(sy); 6131 } 6132 6133 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6134 setScrollContainer(true); 6135 } 6136 6137 computeOpaqueFlags(); 6138 } 6139 6140 /** 6141 * Returns the ordered list of resource ID that are considered when resolving attribute values 6142 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6143 * XML. It will also include a set of explicit styles if specified in XML using 6144 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6145 * 6146 * <p> 6147 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6148 * is enabled in Android developer options. 6149 * 6150 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6151 * @return ordered list of resource ID that are considered when resolving attribute values for 6152 * this {@link View}. 6153 */ 6154 @NonNull 6155 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6156 if (!sDebugViewAttributes 6157 || mAttributeResolutionStacks == null 6158 || mAttributeResolutionStacks.get(attribute) == null) { 6159 return new int[0]; 6160 } 6161 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6162 int stackSize = attributeResolutionStack.length; 6163 if (mSourceLayoutId != ID_NULL) { 6164 stackSize++; 6165 } 6166 6167 int currentIndex = 0; 6168 int[] stack = new int[stackSize]; 6169 6170 if (mSourceLayoutId != ID_NULL) { 6171 stack[currentIndex] = mSourceLayoutId; 6172 currentIndex++; 6173 } 6174 for (int i = 0; i < attributeResolutionStack.length; i++) { 6175 stack[currentIndex] = attributeResolutionStack[i]; 6176 currentIndex++; 6177 } 6178 return stack; 6179 } 6180 6181 /** 6182 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6183 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6184 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6185 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6186 * 6187 * <p> 6188 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6189 * is enabled in Android developer options. 6190 * 6191 * @return mapping of attribute resource ID to source resource ID where the attribute value 6192 * was set. 6193 */ 6194 @NonNull 6195 @SuppressWarnings("AndroidFrameworkEfficientCollections") 6196 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6197 HashMap<Integer, Integer> map = new HashMap<>(); 6198 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6199 return map; 6200 } 6201 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6202 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6203 } 6204 return map; 6205 } 6206 6207 /** 6208 * Returns the resource ID for the style specified using {@code style="..."} in the 6209 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6210 * specified or otherwise not applicable. 6211 * <p> 6212 * Each {@link View} can have an explicit style specified in the layout file. 6213 * This style is used first during the {@link View} attribute resolution, then if an attribute 6214 * is not defined there the resource system looks at default style and theme as fallbacks. 6215 * 6216 * <p> 6217 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6218 * is enabled in Android developer options. 6219 * 6220 * @return The resource ID for the style specified using {@code style="..."} in the 6221 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6222 * if not specified or otherwise not applicable. 6223 */ 6224 @StyleRes 6225 public int getExplicitStyle() { 6226 if (!sDebugViewAttributes) { 6227 return ID_NULL; 6228 } 6229 return mExplicitStyle; 6230 } 6231 6232 /** 6233 * An implementation of OnClickListener that attempts to lazily load a 6234 * named click handling method from a parent or ancestor context. 6235 */ 6236 private static class DeclaredOnClickListener implements OnClickListener { 6237 private final View mHostView; 6238 private final String mMethodName; 6239 6240 private Method mResolvedMethod; 6241 private Context mResolvedContext; 6242 6243 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6244 mHostView = hostView; 6245 mMethodName = methodName; 6246 } 6247 6248 @Override 6249 public void onClick(@NonNull View v) { 6250 if (mResolvedMethod == null) { 6251 resolveMethod(mHostView.getContext(), mMethodName); 6252 } 6253 6254 try { 6255 mResolvedMethod.invoke(mResolvedContext, v); 6256 } catch (IllegalAccessException e) { 6257 throw new IllegalStateException( 6258 "Could not execute non-public method for android:onClick", e); 6259 } catch (InvocationTargetException e) { 6260 throw new IllegalStateException( 6261 "Could not execute method for android:onClick", e); 6262 } 6263 } 6264 6265 @NonNull 6266 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6267 while (context != null) { 6268 try { 6269 if (!context.isRestricted()) { 6270 final Method method = context.getClass().getMethod(mMethodName, View.class); 6271 if (method != null) { 6272 mResolvedMethod = method; 6273 mResolvedContext = context; 6274 return; 6275 } 6276 } 6277 } catch (NoSuchMethodException e) { 6278 // Failed to find method, keep searching up the hierarchy. 6279 } 6280 6281 if (context instanceof ContextWrapper) { 6282 context = ((ContextWrapper) context).getBaseContext(); 6283 } else { 6284 // Can't search up the hierarchy, null out and fail. 6285 context = null; 6286 } 6287 } 6288 6289 final int id = mHostView.getId(); 6290 final String idText = id == NO_ID ? "" : " with id '" 6291 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6292 throw new IllegalStateException("Could not find method " + mMethodName 6293 + "(View) in a parent or ancestor Context for android:onClick " 6294 + "attribute defined on view " + mHostView.getClass() + idText); 6295 } 6296 } 6297 6298 /** 6299 * Non-public constructor for use in testing 6300 */ 6301 @UnsupportedAppUsage 6302 View() { 6303 mResources = null; 6304 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6305 } 6306 6307 /** 6308 * Returns {@code true} when the View is attached and the system developer setting to show 6309 * the layout bounds is enabled or {@code false} otherwise. 6310 */ 6311 public final boolean isShowingLayoutBounds() { 6312 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6313 } 6314 6315 /** 6316 * Used to test isShowingLayoutBounds(). This sets the local value used 6317 * by that function. This method does nothing if the layout isn't attached. 6318 * 6319 * @hide 6320 */ 6321 @TestApi 6322 public final void setShowingLayoutBounds(boolean debugLayout) { 6323 if (mAttachInfo != null) { 6324 mAttachInfo.mDebugLayout = debugLayout; 6325 } 6326 } 6327 6328 private static SparseArray<String> getAttributeMap() { 6329 if (mAttributeMap == null) { 6330 mAttributeMap = new SparseArray<>(); 6331 } 6332 return mAttributeMap; 6333 } 6334 6335 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6336 @Nullable AttributeSet attrs) { 6337 if (!sDebugViewAttributes) { 6338 return; 6339 } 6340 mExplicitStyle = theme.getExplicitStyle(attrs); 6341 } 6342 6343 /** 6344 * Stores debugging information about attributes. This should be called in a constructor by 6345 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6346 * then the custom attributes used by this view will not be visible in layout inspection tools. 6347 * 6348 * @param context Context under which this view is created. 6349 * @param styleable A reference to styleable array R.styleable.Foo 6350 * @param attrs AttributeSet used to construct this view. 6351 * @param t Resolved {@link TypedArray} returned by a call to 6352 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6353 * @param defStyleAttr Default style attribute passed into the view constructor. 6354 * @param defStyleRes Default style resource passed into the view constructor. 6355 */ 6356 public final void saveAttributeDataForStyleable(@NonNull Context context, 6357 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6358 int defStyleAttr, int defStyleRes) { 6359 if (!sDebugViewAttributes) { 6360 return; 6361 } 6362 6363 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6364 defStyleAttr, defStyleRes, mExplicitStyle); 6365 6366 if (mAttributeResolutionStacks == null) { 6367 mAttributeResolutionStacks = new SparseArray<>(); 6368 } 6369 6370 if (mAttributeSourceResId == null) { 6371 mAttributeSourceResId = new SparseIntArray(); 6372 } 6373 6374 final int indexCount = t.getIndexCount(); 6375 for (int j = 0; j < indexCount; ++j) { 6376 final int index = t.getIndex(j); 6377 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6378 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6379 } 6380 } 6381 6382 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6383 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6384 final int indexCount = t.getIndexCount(); 6385 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6386 6387 int i = 0; 6388 6389 // Store raw XML attributes. 6390 for (int j = 0; j < attrsCount; ++j) { 6391 attributes[i] = attrs.getAttributeName(j); 6392 attributes[i + 1] = attrs.getAttributeValue(j); 6393 i += 2; 6394 } 6395 6396 // Store resolved styleable attributes. 6397 final Resources res = t.getResources(); 6398 final SparseArray<String> attributeMap = getAttributeMap(); 6399 for (int j = 0; j < indexCount; ++j) { 6400 final int index = t.getIndex(j); 6401 if (!t.hasValueOrEmpty(index)) { 6402 // Value is undefined. Skip it. 6403 continue; 6404 } 6405 6406 final int resourceId = t.getResourceId(index, 0); 6407 if (resourceId == 0) { 6408 // Value is not a reference. Skip it. 6409 continue; 6410 } 6411 6412 String resourceName = attributeMap.get(resourceId); 6413 if (resourceName == null) { 6414 try { 6415 resourceName = res.getResourceName(resourceId); 6416 } catch (Resources.NotFoundException e) { 6417 resourceName = "0x" + Integer.toHexString(resourceId); 6418 } 6419 attributeMap.put(resourceId, resourceName); 6420 } 6421 6422 attributes[i] = resourceName; 6423 attributes[i + 1] = t.getString(index); 6424 i += 2; 6425 } 6426 6427 // Trim to fit contents. 6428 final String[] trimmed = new String[i]; 6429 System.arraycopy(attributes, 0, trimmed, 0, i); 6430 mAttributes = trimmed; 6431 } 6432 6433 @Override 6434 public String toString() { 6435 StringBuilder out = new StringBuilder(128); 6436 out.append(getClass().getName()); 6437 out.append('{'); 6438 out.append(Integer.toHexString(System.identityHashCode(this))); 6439 out.append(' '); 6440 switch (mViewFlags&VISIBILITY_MASK) { 6441 case VISIBLE: out.append('V'); break; 6442 case INVISIBLE: out.append('I'); break; 6443 case GONE: out.append('G'); break; 6444 default: out.append('.'); break; 6445 } 6446 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6447 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6448 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6449 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6450 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6451 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6452 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6453 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6454 out.append(' '); 6455 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6456 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6457 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6458 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6459 out.append('p'); 6460 } else { 6461 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6462 } 6463 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6464 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6465 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6466 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6467 out.append(' '); 6468 out.append(mLeft); 6469 out.append(','); 6470 out.append(mTop); 6471 out.append('-'); 6472 out.append(mRight); 6473 out.append(','); 6474 out.append(mBottom); 6475 final int id = getId(); 6476 if (id != NO_ID) { 6477 out.append(" #"); 6478 out.append(Integer.toHexString(id)); 6479 final Resources r = mResources; 6480 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6481 try { 6482 String pkgname; 6483 switch (id&0xff000000) { 6484 case 0x7f000000: 6485 pkgname="app"; 6486 break; 6487 case 0x01000000: 6488 pkgname="android"; 6489 break; 6490 default: 6491 pkgname = r.getResourcePackageName(id); 6492 break; 6493 } 6494 String typename = r.getResourceTypeName(id); 6495 String entryname = r.getResourceEntryName(id); 6496 out.append(" "); 6497 out.append(pkgname); 6498 out.append(":"); 6499 out.append(typename); 6500 out.append("/"); 6501 out.append(entryname); 6502 } catch (Resources.NotFoundException e) { 6503 } 6504 } 6505 } 6506 if (mAutofillId != null) { 6507 out.append(" aid="); out.append(mAutofillId); 6508 } 6509 out.append("}"); 6510 return out.toString(); 6511 } 6512 6513 /** 6514 * <p> 6515 * Initializes the fading edges from a given set of styled attributes. This 6516 * method should be called by subclasses that need fading edges and when an 6517 * instance of these subclasses is created programmatically rather than 6518 * being inflated from XML. This method is automatically called when the XML 6519 * is inflated. 6520 * </p> 6521 * 6522 * @param a the styled attributes set to initialize the fading edges from 6523 * 6524 * @removed 6525 */ 6526 protected void initializeFadingEdge(TypedArray a) { 6527 // This method probably shouldn't have been included in the SDK to begin with. 6528 // It relies on 'a' having been initialized using an attribute filter array that is 6529 // not publicly available to the SDK. The old method has been renamed 6530 // to initializeFadingEdgeInternal and hidden for framework use only; 6531 // this one initializes using defaults to make it safe to call for apps. 6532 6533 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6534 6535 initializeFadingEdgeInternal(arr); 6536 6537 arr.recycle(); 6538 } 6539 6540 /** 6541 * <p> 6542 * Initializes the fading edges from a given set of styled attributes. This 6543 * method should be called by subclasses that need fading edges and when an 6544 * instance of these subclasses is created programmatically rather than 6545 * being inflated from XML. This method is automatically called when the XML 6546 * is inflated. 6547 * </p> 6548 * 6549 * @param a the styled attributes set to initialize the fading edges from 6550 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6551 */ 6552 protected void initializeFadingEdgeInternal(TypedArray a) { 6553 initScrollCache(); 6554 6555 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6556 R.styleable.View_fadingEdgeLength, 6557 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6558 } 6559 6560 /** 6561 * Returns the size of the vertical faded edges used to indicate that more 6562 * content in this view is visible. 6563 * 6564 * @return The size in pixels of the vertical faded edge or 0 if vertical 6565 * faded edges are not enabled for this view. 6566 * @attr ref android.R.styleable#View_fadingEdgeLength 6567 */ 6568 public int getVerticalFadingEdgeLength() { 6569 if (isVerticalFadingEdgeEnabled()) { 6570 ScrollabilityCache cache = mScrollCache; 6571 if (cache != null) { 6572 return cache.fadingEdgeLength; 6573 } 6574 } 6575 return 0; 6576 } 6577 6578 /** 6579 * Set the size of the faded edge used to indicate that more content in this 6580 * view is available. Will not change whether the fading edge is enabled; use 6581 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6582 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6583 * for the vertical or horizontal fading edges. 6584 * 6585 * @param length The size in pixels of the faded edge used to indicate that more 6586 * content in this view is visible. 6587 */ 6588 public void setFadingEdgeLength(int length) { 6589 initScrollCache(); 6590 mScrollCache.fadingEdgeLength = length; 6591 } 6592 6593 /** 6594 * Returns the size of the horizontal faded edges used to indicate that more 6595 * content in this view is visible. 6596 * 6597 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6598 * faded edges are not enabled for this view. 6599 * @attr ref android.R.styleable#View_fadingEdgeLength 6600 */ 6601 public int getHorizontalFadingEdgeLength() { 6602 if (isHorizontalFadingEdgeEnabled()) { 6603 ScrollabilityCache cache = mScrollCache; 6604 if (cache != null) { 6605 return cache.fadingEdgeLength; 6606 } 6607 } 6608 return 0; 6609 } 6610 6611 /** 6612 * Returns the width of the vertical scrollbar. 6613 * 6614 * @return The width in pixels of the vertical scrollbar or 0 if there 6615 * is no vertical scrollbar. 6616 */ 6617 public int getVerticalScrollbarWidth() { 6618 ScrollabilityCache cache = mScrollCache; 6619 if (cache != null) { 6620 ScrollBarDrawable scrollBar = cache.scrollBar; 6621 if (scrollBar != null) { 6622 int size = scrollBar.getSize(true); 6623 if (size <= 0) { 6624 size = cache.scrollBarSize; 6625 } 6626 return size; 6627 } 6628 return 0; 6629 } 6630 return 0; 6631 } 6632 6633 /** 6634 * Returns the height of the horizontal scrollbar. 6635 * 6636 * @return The height in pixels of the horizontal scrollbar or 0 if 6637 * there is no horizontal scrollbar. 6638 */ 6639 protected int getHorizontalScrollbarHeight() { 6640 ScrollabilityCache cache = mScrollCache; 6641 if (cache != null) { 6642 ScrollBarDrawable scrollBar = cache.scrollBar; 6643 if (scrollBar != null) { 6644 int size = scrollBar.getSize(false); 6645 if (size <= 0) { 6646 size = cache.scrollBarSize; 6647 } 6648 return size; 6649 } 6650 return 0; 6651 } 6652 return 0; 6653 } 6654 6655 /** 6656 * <p> 6657 * Initializes the scrollbars from a given set of styled attributes. This 6658 * method should be called by subclasses that need scrollbars and when an 6659 * instance of these subclasses is created programmatically rather than 6660 * being inflated from XML. This method is automatically called when the XML 6661 * is inflated. 6662 * </p> 6663 * 6664 * @param a the styled attributes set to initialize the scrollbars from 6665 * 6666 * @removed 6667 */ 6668 protected void initializeScrollbars(TypedArray a) { 6669 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6670 // using the View filter array which is not available to the SDK. As such, internal 6671 // framework usage now uses initializeScrollbarsInternal and we grab a default 6672 // TypedArray with the right filter instead here. 6673 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6674 6675 initializeScrollbarsInternal(arr); 6676 6677 // We ignored the method parameter. Recycle the one we actually did use. 6678 arr.recycle(); 6679 } 6680 6681 private void initializeScrollBarDrawable() { 6682 initScrollCache(); 6683 6684 if (mScrollCache.scrollBar == null) { 6685 mScrollCache.scrollBar = new ScrollBarDrawable(); 6686 mScrollCache.scrollBar.setState(getDrawableState()); 6687 mScrollCache.scrollBar.setCallback(this); 6688 } 6689 } 6690 6691 /** 6692 * <p> 6693 * Initializes the scrollbars from a given set of styled attributes. This 6694 * method should be called by subclasses that need scrollbars and when an 6695 * instance of these subclasses is created programmatically rather than 6696 * being inflated from XML. This method is automatically called when the XML 6697 * is inflated. 6698 * </p> 6699 * 6700 * @param a the styled attributes set to initialize the scrollbars from 6701 * @hide 6702 */ 6703 @UnsupportedAppUsage 6704 protected void initializeScrollbarsInternal(TypedArray a) { 6705 initScrollCache(); 6706 6707 final ScrollabilityCache scrollabilityCache = mScrollCache; 6708 6709 if (scrollabilityCache.scrollBar == null) { 6710 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6711 scrollabilityCache.scrollBar.setState(getDrawableState()); 6712 scrollabilityCache.scrollBar.setCallback(this); 6713 } 6714 6715 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6716 6717 if (!fadeScrollbars) { 6718 scrollabilityCache.state = ScrollabilityCache.ON; 6719 } 6720 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6721 6722 6723 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6724 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6725 .getScrollBarFadeDuration()); 6726 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6727 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6728 ViewConfiguration.getScrollDefaultDelay()); 6729 6730 6731 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6732 com.android.internal.R.styleable.View_scrollbarSize, 6733 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6734 6735 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6736 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6737 6738 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6739 if (thumb != null) { 6740 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6741 } 6742 6743 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6744 false); 6745 if (alwaysDraw) { 6746 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6747 } 6748 6749 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6750 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6751 6752 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6753 if (thumb != null) { 6754 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6755 } 6756 6757 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6758 false); 6759 if (alwaysDraw) { 6760 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6761 } 6762 6763 // Apply layout direction to the new Drawables if needed 6764 final int layoutDirection = getLayoutDirection(); 6765 if (track != null) { 6766 track.setLayoutDirection(layoutDirection); 6767 } 6768 if (thumb != null) { 6769 thumb.setLayoutDirection(layoutDirection); 6770 } 6771 6772 // Re-apply user/background padding so that scrollbar(s) get added 6773 resolvePadding(); 6774 } 6775 6776 /** 6777 * Defines the vertical scrollbar thumb drawable 6778 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6779 * 6780 * @see #awakenScrollBars(int) 6781 * @see #isVerticalScrollBarEnabled() 6782 * @see #setVerticalScrollBarEnabled(boolean) 6783 */ 6784 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6785 initializeScrollBarDrawable(); 6786 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 6787 } 6788 6789 /** 6790 * Defines the vertical scrollbar track drawable 6791 * @attr ref android.R.styleable#View_scrollbarTrackVertical 6792 * 6793 * @see #awakenScrollBars(int) 6794 * @see #isVerticalScrollBarEnabled() 6795 * @see #setVerticalScrollBarEnabled(boolean) 6796 */ 6797 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6798 initializeScrollBarDrawable(); 6799 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 6800 } 6801 6802 /** 6803 * Defines the horizontal thumb drawable 6804 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 6805 * 6806 * @see #awakenScrollBars(int) 6807 * @see #isHorizontalScrollBarEnabled() 6808 * @see #setHorizontalScrollBarEnabled(boolean) 6809 */ 6810 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6811 initializeScrollBarDrawable(); 6812 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 6813 } 6814 6815 /** 6816 * Defines the horizontal track drawable 6817 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 6818 * 6819 * @see #awakenScrollBars(int) 6820 * @see #isHorizontalScrollBarEnabled() 6821 * @see #setHorizontalScrollBarEnabled(boolean) 6822 */ 6823 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6824 initializeScrollBarDrawable(); 6825 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 6826 } 6827 6828 /** 6829 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 6830 * exists, null otherwise. 6831 * 6832 * @see #awakenScrollBars(int) 6833 * @see #isVerticalScrollBarEnabled() 6834 * @see #setVerticalScrollBarEnabled(boolean) 6835 */ 6836 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 6837 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 6838 } 6839 6840 /** 6841 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 6842 * exists, null otherwise. 6843 * 6844 * @see #awakenScrollBars(int) 6845 * @see #isVerticalScrollBarEnabled() 6846 * @see #setVerticalScrollBarEnabled(boolean) 6847 */ 6848 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 6849 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 6850 } 6851 6852 /** 6853 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 6854 * exists, null otherwise. 6855 * 6856 * @see #awakenScrollBars(int) 6857 * @see #isHorizontalScrollBarEnabled() 6858 * @see #setHorizontalScrollBarEnabled(boolean) 6859 */ 6860 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 6861 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 6862 } 6863 6864 /** 6865 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 6866 * exists, null otherwise. 6867 * 6868 * @see #awakenScrollBars(int) 6869 * @see #isHorizontalScrollBarEnabled() 6870 * @see #setHorizontalScrollBarEnabled(boolean) 6871 */ 6872 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 6873 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 6874 } 6875 6876 private void initializeScrollIndicatorsInternal() { 6877 // Some day maybe we'll break this into top/left/start/etc. and let the 6878 // client control it. Until then, you can have any scroll indicator you 6879 // want as long as it's a 1dp foreground-colored rectangle. 6880 if (mScrollIndicatorDrawable == null) { 6881 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6882 } 6883 } 6884 6885 /** 6886 * <p> 6887 * Initalizes the scrollability cache if necessary. 6888 * </p> 6889 */ 6890 private void initScrollCache() { 6891 if (mScrollCache == null) { 6892 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6893 } 6894 } 6895 6896 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 6897 private ScrollabilityCache getScrollCache() { 6898 initScrollCache(); 6899 return mScrollCache; 6900 } 6901 6902 /** 6903 * Set the position of the vertical scroll bar. Should be one of 6904 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 6905 * {@link #SCROLLBAR_POSITION_RIGHT}. 6906 * 6907 * @param position Where the vertical scroll bar should be positioned. 6908 */ 6909 public void setVerticalScrollbarPosition(int position) { 6910 if (mVerticalScrollbarPosition != position) { 6911 mVerticalScrollbarPosition = position; 6912 computeOpaqueFlags(); 6913 resolvePadding(); 6914 } 6915 } 6916 6917 /** 6918 * @return The position where the vertical scroll bar will show, if applicable. 6919 * @see #setVerticalScrollbarPosition(int) 6920 */ 6921 public int getVerticalScrollbarPosition() { 6922 return mVerticalScrollbarPosition; 6923 } 6924 6925 boolean isOnScrollbar(float x, float y) { 6926 if (mScrollCache == null) { 6927 return false; 6928 } 6929 x += getScrollX(); 6930 y += getScrollY(); 6931 final boolean canScrollVertically = 6932 computeVerticalScrollRange() > computeVerticalScrollExtent(); 6933 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 6934 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6935 getVerticalScrollBarBounds(null, touchBounds); 6936 if (touchBounds.contains((int) x, (int) y)) { 6937 return true; 6938 } 6939 } 6940 final boolean canScrollHorizontally = 6941 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 6942 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 6943 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6944 getHorizontalScrollBarBounds(null, touchBounds); 6945 if (touchBounds.contains((int) x, (int) y)) { 6946 return true; 6947 } 6948 } 6949 return false; 6950 } 6951 6952 @UnsupportedAppUsage 6953 boolean isOnScrollbarThumb(float x, float y) { 6954 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 6955 } 6956 6957 private boolean isOnVerticalScrollbarThumb(float x, float y) { 6958 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 6959 return false; 6960 } 6961 final int range = computeVerticalScrollRange(); 6962 final int extent = computeVerticalScrollExtent(); 6963 if (range > extent) { 6964 x += getScrollX(); 6965 y += getScrollY(); 6966 final Rect bounds = mScrollCache.mScrollBarBounds; 6967 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6968 getVerticalScrollBarBounds(bounds, touchBounds); 6969 final int offset = computeVerticalScrollOffset(); 6970 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 6971 extent, range); 6972 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 6973 extent, range, offset); 6974 final int thumbTop = bounds.top + thumbOffset; 6975 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6976 if (x >= touchBounds.left && x <= touchBounds.right 6977 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 6978 return true; 6979 } 6980 } 6981 return false; 6982 } 6983 6984 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 6985 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 6986 return false; 6987 } 6988 final int range = computeHorizontalScrollRange(); 6989 final int extent = computeHorizontalScrollExtent(); 6990 if (range > extent) { 6991 x += getScrollX(); 6992 y += getScrollY(); 6993 final Rect bounds = mScrollCache.mScrollBarBounds; 6994 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6995 getHorizontalScrollBarBounds(bounds, touchBounds); 6996 final int offset = computeHorizontalScrollOffset(); 6997 6998 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 6999 extent, range); 7000 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7001 extent, range, offset); 7002 final int thumbLeft = bounds.left + thumbOffset; 7003 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7004 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7005 && y >= touchBounds.top && y <= touchBounds.bottom) { 7006 return true; 7007 } 7008 } 7009 return false; 7010 } 7011 7012 @UnsupportedAppUsage 7013 boolean isDraggingScrollBar() { 7014 return mScrollCache != null 7015 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7016 } 7017 7018 /** 7019 * Sets the state of all scroll indicators. 7020 * <p> 7021 * See {@link #setScrollIndicators(int, int)} for usage information. 7022 * 7023 * @param indicators a bitmask of indicators that should be enabled, or 7024 * {@code 0} to disable all indicators 7025 * @see #setScrollIndicators(int, int) 7026 * @see #getScrollIndicators() 7027 * @attr ref android.R.styleable#View_scrollIndicators 7028 */ 7029 @RemotableViewMethod 7030 public void setScrollIndicators(@ScrollIndicators int indicators) { 7031 setScrollIndicators(indicators, 7032 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7033 } 7034 7035 /** 7036 * Sets the state of the scroll indicators specified by the mask. To change 7037 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7038 * <p> 7039 * When a scroll indicator is enabled, it will be displayed if the view 7040 * can scroll in the direction of the indicator. 7041 * <p> 7042 * Multiple indicator types may be enabled or disabled by passing the 7043 * logical OR of the desired types. If multiple types are specified, they 7044 * will all be set to the same enabled state. 7045 * <p> 7046 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7047 * 7048 * @param indicators the indicator direction, or the logical OR of multiple 7049 * indicator directions. One or more of: 7050 * <ul> 7051 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7052 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7053 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7054 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7055 * <li>{@link #SCROLL_INDICATOR_START}</li> 7056 * <li>{@link #SCROLL_INDICATOR_END}</li> 7057 * </ul> 7058 * @see #setScrollIndicators(int) 7059 * @see #getScrollIndicators() 7060 * @attr ref android.R.styleable#View_scrollIndicators 7061 */ 7062 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7063 // Shift and sanitize mask. 7064 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7065 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7066 7067 // Shift and mask indicators. 7068 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7069 indicators &= mask; 7070 7071 // Merge with non-masked flags. 7072 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7073 7074 if (mPrivateFlags3 != updatedFlags) { 7075 mPrivateFlags3 = updatedFlags; 7076 7077 if (indicators != 0) { 7078 initializeScrollIndicatorsInternal(); 7079 } 7080 invalidate(); 7081 } 7082 } 7083 7084 /** 7085 * Returns a bitmask representing the enabled scroll indicators. 7086 * <p> 7087 * For example, if the top and left scroll indicators are enabled and all 7088 * other indicators are disabled, the return value will be 7089 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7090 * <p> 7091 * To check whether the bottom scroll indicator is enabled, use the value 7092 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7093 * 7094 * @return a bitmask representing the enabled scroll indicators 7095 */ 7096 @InspectableProperty(flagMapping = { 7097 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7098 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7099 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7100 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7101 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7102 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7103 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7104 }) 7105 @ScrollIndicators 7106 public int getScrollIndicators() { 7107 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7108 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7109 } 7110 7111 @UnsupportedAppUsage 7112 ListenerInfo getListenerInfo() { 7113 if (mListenerInfo != null) { 7114 return mListenerInfo; 7115 } 7116 mListenerInfo = new ListenerInfo(); 7117 return mListenerInfo; 7118 } 7119 7120 /** 7121 * Register a callback to be invoked when the scroll X or Y positions of 7122 * this view change. 7123 * <p> 7124 * <b>Note:</b> Some views handle scrolling independently from View and may 7125 * have their own separate listeners for scroll-type events. For example, 7126 * {@link android.widget.ListView ListView} allows clients to register an 7127 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7128 * to listen for changes in list scroll position. 7129 * 7130 * @param l The listener to notify when the scroll X or Y position changes. 7131 * @see android.view.View#getScrollX() 7132 * @see android.view.View#getScrollY() 7133 */ 7134 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7135 getListenerInfo().mOnScrollChangeListener = l; 7136 } 7137 7138 /** 7139 * Register a callback to be invoked when focus of this view changed. 7140 * 7141 * @param l The callback that will run. 7142 */ 7143 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7144 getListenerInfo().mOnFocusChangeListener = l; 7145 } 7146 7147 /** 7148 * Add a listener that will be called when the bounds of the view change due to 7149 * layout processing. 7150 * 7151 * @param listener The listener that will be called when layout bounds change. 7152 */ 7153 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7154 ListenerInfo li = getListenerInfo(); 7155 if (li.mOnLayoutChangeListeners == null) { 7156 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7157 } 7158 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7159 li.mOnLayoutChangeListeners.add(listener); 7160 } 7161 } 7162 7163 /** 7164 * Remove a listener for layout changes. 7165 * 7166 * @param listener The listener for layout bounds change. 7167 */ 7168 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7169 ListenerInfo li = mListenerInfo; 7170 if (li == null || li.mOnLayoutChangeListeners == null) { 7171 return; 7172 } 7173 li.mOnLayoutChangeListeners.remove(listener); 7174 } 7175 7176 /** 7177 * Add a listener for attach state changes. 7178 * 7179 * This listener will be called whenever this view is attached or detached 7180 * from a window. Remove the listener using 7181 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7182 * 7183 * @param listener Listener to attach 7184 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7185 */ 7186 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7187 ListenerInfo li = getListenerInfo(); 7188 if (li.mOnAttachStateChangeListeners == null) { 7189 li.mOnAttachStateChangeListeners 7190 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7191 } 7192 li.mOnAttachStateChangeListeners.add(listener); 7193 } 7194 7195 /** 7196 * Remove a listener for attach state changes. The listener will receive no further 7197 * notification of window attach/detach events. 7198 * 7199 * @param listener Listener to remove 7200 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7201 */ 7202 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7203 ListenerInfo li = mListenerInfo; 7204 if (li == null || li.mOnAttachStateChangeListeners == null) { 7205 return; 7206 } 7207 li.mOnAttachStateChangeListeners.remove(listener); 7208 } 7209 7210 /** 7211 * Returns the focus-change callback registered for this view. 7212 * 7213 * @return The callback, or null if one is not registered. 7214 */ 7215 public OnFocusChangeListener getOnFocusChangeListener() { 7216 ListenerInfo li = mListenerInfo; 7217 return li != null ? li.mOnFocusChangeListener : null; 7218 } 7219 7220 /** 7221 * Register a callback to be invoked when this view is clicked. If this view is not 7222 * clickable, it becomes clickable. 7223 * 7224 * @param l The callback that will run 7225 * 7226 * @see #setClickable(boolean) 7227 */ 7228 public void setOnClickListener(@Nullable OnClickListener l) { 7229 if (!isClickable()) { 7230 setClickable(true); 7231 } 7232 getListenerInfo().mOnClickListener = l; 7233 } 7234 7235 /** 7236 * Return whether this view has an attached OnClickListener. Returns 7237 * true if there is a listener, false if there is none. 7238 */ 7239 public boolean hasOnClickListeners() { 7240 ListenerInfo li = mListenerInfo; 7241 return (li != null && li.mOnClickListener != null); 7242 } 7243 7244 /** 7245 * Register a callback to be invoked when this view is clicked and held. If this view is not 7246 * long clickable, it becomes long clickable. 7247 * 7248 * @param l The callback that will run 7249 * 7250 * @see #setLongClickable(boolean) 7251 */ 7252 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7253 if (!isLongClickable()) { 7254 setLongClickable(true); 7255 } 7256 getListenerInfo().mOnLongClickListener = l; 7257 } 7258 7259 /** 7260 * Return whether this view has an attached OnLongClickListener. Returns 7261 * true if there is a listener, false if there is none. 7262 */ 7263 public boolean hasOnLongClickListeners() { 7264 ListenerInfo li = mListenerInfo; 7265 return (li != null && li.mOnLongClickListener != null); 7266 } 7267 7268 /** 7269 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7270 * @hide 7271 */ 7272 @Nullable 7273 public OnLongClickListener getOnLongClickListener() { 7274 ListenerInfo li = mListenerInfo; 7275 return (li != null) ? li.mOnLongClickListener : null; 7276 } 7277 7278 /** 7279 * Register a callback to be invoked when this view is context clicked. If the view is not 7280 * context clickable, it becomes context clickable. 7281 * 7282 * @param l The callback that will run 7283 * @see #setContextClickable(boolean) 7284 */ 7285 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7286 if (!isContextClickable()) { 7287 setContextClickable(true); 7288 } 7289 getListenerInfo().mOnContextClickListener = l; 7290 } 7291 7292 /** 7293 * Register a callback to be invoked when the context menu for this view is 7294 * being built. If this view is not long clickable, it becomes long clickable. 7295 * 7296 * @param l The callback that will run 7297 * 7298 */ 7299 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7300 if (!isLongClickable()) { 7301 setLongClickable(true); 7302 } 7303 getListenerInfo().mOnCreateContextMenuListener = l; 7304 } 7305 7306 /** 7307 * Set an observer to collect stats for each frame rendered for this view. 7308 * 7309 * @hide 7310 */ 7311 public void addFrameMetricsListener(Window window, 7312 Window.OnFrameMetricsAvailableListener listener, 7313 Handler handler) { 7314 if (mAttachInfo != null) { 7315 if (mAttachInfo.mThreadedRenderer != null) { 7316 if (mFrameMetricsObservers == null) { 7317 mFrameMetricsObservers = new ArrayList<>(); 7318 } 7319 7320 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7321 mFrameMetricsObservers.add(fmo); 7322 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7323 } else { 7324 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7325 } 7326 } else { 7327 if (mFrameMetricsObservers == null) { 7328 mFrameMetricsObservers = new ArrayList<>(); 7329 } 7330 7331 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7332 mFrameMetricsObservers.add(fmo); 7333 } 7334 } 7335 7336 /** 7337 * Remove observer configured to collect frame stats for this view. 7338 * 7339 * @hide 7340 */ 7341 public void removeFrameMetricsListener( 7342 Window.OnFrameMetricsAvailableListener listener) { 7343 ThreadedRenderer renderer = getThreadedRenderer(); 7344 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7345 if (fmo == null) { 7346 throw new IllegalArgumentException( 7347 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7348 } 7349 7350 if (mFrameMetricsObservers != null) { 7351 mFrameMetricsObservers.remove(fmo); 7352 if (renderer != null) { 7353 renderer.removeObserver(fmo.getRendererObserver()); 7354 } 7355 } 7356 } 7357 7358 private void registerPendingFrameMetricsObservers() { 7359 if (mFrameMetricsObservers != null) { 7360 ThreadedRenderer renderer = getThreadedRenderer(); 7361 if (renderer != null) { 7362 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7363 renderer.addObserver(fmo.getRendererObserver()); 7364 } 7365 } else { 7366 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7367 } 7368 } 7369 } 7370 7371 private FrameMetricsObserver findFrameMetricsObserver( 7372 Window.OnFrameMetricsAvailableListener listener) { 7373 if (mFrameMetricsObservers != null) { 7374 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7375 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7376 if (observer.mListener == listener) { 7377 return observer; 7378 } 7379 } 7380 } 7381 7382 return null; 7383 } 7384 7385 /** @hide */ 7386 public void setNotifyAutofillManagerOnClick(boolean notify) { 7387 if (notify) { 7388 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7389 } else { 7390 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7391 } 7392 } 7393 7394 private void notifyAutofillManagerOnClick() { 7395 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7396 try { 7397 getAutofillManager().notifyViewClicked(this); 7398 } finally { 7399 // Set it to already called so it's not called twice when called by 7400 // performClickInternal() 7401 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7402 } 7403 } 7404 } 7405 7406 /** 7407 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7408 * {@code performClick()} directly to make sure the autofill manager is notified when 7409 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7410 * method). 7411 */ 7412 private boolean performClickInternal() { 7413 // Must notify autofill manager before performing the click actions to avoid scenarios where 7414 // the app has a click listener that changes the state of views the autofill service might 7415 // be interested on. 7416 notifyAutofillManagerOnClick(); 7417 7418 return performClick(); 7419 } 7420 7421 /** 7422 * Call this view's OnClickListener, if it is defined. Performs all normal 7423 * actions associated with clicking: reporting accessibility event, playing 7424 * a sound, etc. 7425 * 7426 * @return True there was an assigned OnClickListener that was called, false 7427 * otherwise is returned. 7428 */ 7429 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7430 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7431 // could extend this method without calling super.performClick()). 7432 public boolean performClick() { 7433 // We still need to call this method to handle the cases where performClick() was called 7434 // externally, instead of through performClickInternal() 7435 notifyAutofillManagerOnClick(); 7436 7437 final boolean result; 7438 final ListenerInfo li = mListenerInfo; 7439 if (li != null && li.mOnClickListener != null) { 7440 playSoundEffect(SoundEffectConstants.CLICK); 7441 li.mOnClickListener.onClick(this); 7442 result = true; 7443 } else { 7444 result = false; 7445 } 7446 7447 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7448 7449 notifyEnterOrExitForAutoFillIfNeeded(true); 7450 7451 return result; 7452 } 7453 7454 /** 7455 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7456 * this only calls the listener, and does not do any associated clicking 7457 * actions like reporting an accessibility event. 7458 * 7459 * @return True there was an assigned OnClickListener that was called, false 7460 * otherwise is returned. 7461 */ 7462 public boolean callOnClick() { 7463 ListenerInfo li = mListenerInfo; 7464 if (li != null && li.mOnClickListener != null) { 7465 li.mOnClickListener.onClick(this); 7466 return true; 7467 } 7468 return false; 7469 } 7470 7471 /** 7472 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7473 * context menu if the OnLongClickListener did not consume the event. 7474 * 7475 * @return {@code true} if one of the above receivers consumed the event, 7476 * {@code false} otherwise 7477 */ 7478 public boolean performLongClick() { 7479 return performLongClickInternal(mLongClickX, mLongClickY); 7480 } 7481 7482 /** 7483 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7484 * context menu if the OnLongClickListener did not consume the event, 7485 * anchoring it to an (x,y) coordinate. 7486 * 7487 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7488 * to disable anchoring 7489 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7490 * to disable anchoring 7491 * @return {@code true} if one of the above receivers consumed the event, 7492 * {@code false} otherwise 7493 */ 7494 public boolean performLongClick(float x, float y) { 7495 mLongClickX = x; 7496 mLongClickY = y; 7497 final boolean handled = performLongClick(); 7498 mLongClickX = Float.NaN; 7499 mLongClickY = Float.NaN; 7500 return handled; 7501 } 7502 7503 /** 7504 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7505 * context menu if the OnLongClickListener did not consume the event, 7506 * optionally anchoring it to an (x,y) coordinate. 7507 * 7508 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7509 * to disable anchoring 7510 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7511 * to disable anchoring 7512 * @return {@code true} if one of the above receivers consumed the event, 7513 * {@code false} otherwise 7514 */ 7515 private boolean performLongClickInternal(float x, float y) { 7516 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7517 7518 boolean handled = false; 7519 final ListenerInfo li = mListenerInfo; 7520 if (li != null && li.mOnLongClickListener != null) { 7521 handled = li.mOnLongClickListener.onLongClick(View.this); 7522 } 7523 if (!handled) { 7524 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7525 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7526 } 7527 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7528 if (!handled) { 7529 handled = showLongClickTooltip((int) x, (int) y); 7530 } 7531 } 7532 if (handled) { 7533 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7534 } 7535 return handled; 7536 } 7537 7538 /** 7539 * Call this view's OnContextClickListener, if it is defined. 7540 * 7541 * @param x the x coordinate of the context click 7542 * @param y the y coordinate of the context click 7543 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7544 * otherwise. 7545 */ 7546 public boolean performContextClick(float x, float y) { 7547 return performContextClick(); 7548 } 7549 7550 /** 7551 * Call this view's OnContextClickListener, if it is defined. 7552 * 7553 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7554 * otherwise. 7555 */ 7556 public boolean performContextClick() { 7557 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7558 7559 boolean handled = false; 7560 ListenerInfo li = mListenerInfo; 7561 if (li != null && li.mOnContextClickListener != null) { 7562 handled = li.mOnContextClickListener.onContextClick(View.this); 7563 } 7564 if (handled) { 7565 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7566 } 7567 return handled; 7568 } 7569 7570 /** 7571 * Performs button-related actions during a touch down event. 7572 * 7573 * @param event The event. 7574 * @return True if the down was consumed. 7575 * 7576 * @hide 7577 */ 7578 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7579 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7580 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7581 showContextMenu(event.getX(), event.getY()); 7582 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7583 return true; 7584 } 7585 return false; 7586 } 7587 7588 /** 7589 * Shows the context menu for this view. 7590 * 7591 * @return {@code true} if the context menu was shown, {@code false} 7592 * otherwise 7593 * @see #showContextMenu(float, float) 7594 */ 7595 public boolean showContextMenu() { 7596 return getParent().showContextMenuForChild(this); 7597 } 7598 7599 /** 7600 * Shows the context menu for this view anchored to the specified 7601 * view-relative coordinate. 7602 * 7603 * @param x the X coordinate in pixels relative to the view to which the 7604 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7605 * @param y the Y coordinate in pixels relative to the view to which the 7606 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7607 * @return {@code true} if the context menu was shown, {@code false} 7608 * otherwise 7609 */ 7610 public boolean showContextMenu(float x, float y) { 7611 return getParent().showContextMenuForChild(this, x, y); 7612 } 7613 7614 /** 7615 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7616 * 7617 * @param callback Callback that will control the lifecycle of the action mode 7618 * @return The new action mode if it is started, null otherwise 7619 * 7620 * @see ActionMode 7621 * @see #startActionMode(android.view.ActionMode.Callback, int) 7622 */ 7623 public ActionMode startActionMode(ActionMode.Callback callback) { 7624 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7625 } 7626 7627 /** 7628 * Start an action mode with the given type. 7629 * 7630 * @param callback Callback that will control the lifecycle of the action mode 7631 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7632 * @return The new action mode if it is started, null otherwise 7633 * 7634 * @see ActionMode 7635 */ 7636 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7637 ViewParent parent = getParent(); 7638 if (parent == null) return null; 7639 try { 7640 return parent.startActionModeForChild(this, callback, type); 7641 } catch (AbstractMethodError ame) { 7642 // Older implementations of custom views might not implement this. 7643 return parent.startActionModeForChild(this, callback); 7644 } 7645 } 7646 7647 /** 7648 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7649 * Context, creating a unique View identifier to retrieve the result. 7650 * 7651 * @param intent The Intent to be started. 7652 * @param requestCode The request code to use. 7653 * @hide 7654 */ 7655 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7656 public void startActivityForResult(Intent intent, int requestCode) { 7657 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7658 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7659 } 7660 7661 /** 7662 * If this View corresponds to the calling who, dispatches the activity result. 7663 * @param who The identifier for the targeted View to receive the result. 7664 * @param requestCode The integer request code originally supplied to 7665 * startActivityForResult(), allowing you to identify who this 7666 * result came from. 7667 * @param resultCode The integer result code returned by the child activity 7668 * through its setResult(). 7669 * @param data An Intent, which can return result data to the caller 7670 * (various data can be attached to Intent "extras"). 7671 * @return {@code true} if the activity result was dispatched. 7672 * @hide 7673 */ 7674 public boolean dispatchActivityResult( 7675 String who, int requestCode, int resultCode, Intent data) { 7676 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7677 onActivityResult(requestCode, resultCode, data); 7678 mStartActivityRequestWho = null; 7679 return true; 7680 } 7681 return false; 7682 } 7683 7684 /** 7685 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7686 * 7687 * @param requestCode The integer request code originally supplied to 7688 * startActivityForResult(), allowing you to identify who this 7689 * result came from. 7690 * @param resultCode The integer result code returned by the child activity 7691 * through its setResult(). 7692 * @param data An Intent, which can return result data to the caller 7693 * (various data can be attached to Intent "extras"). 7694 * @hide 7695 */ 7696 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7697 // Do nothing. 7698 } 7699 7700 /** 7701 * Register a callback to be invoked when a hardware key is pressed in this view. 7702 * Key presses in software input methods will generally not trigger the methods of 7703 * this listener. 7704 * @param l the key listener to attach to this view 7705 */ 7706 public void setOnKeyListener(OnKeyListener l) { 7707 getListenerInfo().mOnKeyListener = l; 7708 } 7709 7710 /** 7711 * Register a callback to be invoked when a touch event is sent to this view. 7712 * @param l the touch listener to attach to this view 7713 */ 7714 public void setOnTouchListener(OnTouchListener l) { 7715 getListenerInfo().mOnTouchListener = l; 7716 } 7717 7718 /** 7719 * Register a callback to be invoked when a generic motion event is sent to this view. 7720 * @param l the generic motion listener to attach to this view 7721 */ 7722 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7723 getListenerInfo().mOnGenericMotionListener = l; 7724 } 7725 7726 /** 7727 * Register a callback to be invoked when a hover event is sent to this view. 7728 * @param l the hover listener to attach to this view 7729 */ 7730 public void setOnHoverListener(OnHoverListener l) { 7731 getListenerInfo().mOnHoverListener = l; 7732 } 7733 7734 /** 7735 * Register a drag event listener callback object for this View. The parameter is 7736 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7737 * View, the system calls the 7738 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7739 * @param l An implementation of {@link android.view.View.OnDragListener}. 7740 */ 7741 public void setOnDragListener(OnDragListener l) { 7742 getListenerInfo().mOnDragListener = l; 7743 } 7744 7745 /** 7746 * Give this view focus. This will cause 7747 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7748 * 7749 * Note: this does not check whether this {@link View} should get focus, it just 7750 * gives it focus no matter what. It should only be called internally by framework 7751 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7752 * 7753 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7754 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7755 * focus moved when requestFocus() is called. It may not always 7756 * apply, in which case use the default View.FOCUS_DOWN. 7757 * @param previouslyFocusedRect The rectangle of the view that had focus 7758 * prior in this View's coordinate system. 7759 */ 7760 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7761 if (DBG) { 7762 System.out.println(this + " requestFocus()"); 7763 } 7764 7765 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7766 mPrivateFlags |= PFLAG_FOCUSED; 7767 7768 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7769 7770 if (mParent != null) { 7771 mParent.requestChildFocus(this, this); 7772 updateFocusedInCluster(oldFocus, direction); 7773 } 7774 7775 if (mAttachInfo != null) { 7776 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 7777 } 7778 7779 onFocusChanged(true, direction, previouslyFocusedRect); 7780 refreshDrawableState(); 7781 } 7782 } 7783 7784 /** 7785 * Sets this view's preference for reveal behavior when it gains focus. 7786 * 7787 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 7788 * this view would prefer to be brought fully into view when it gains focus. 7789 * For example, a text field that a user is meant to type into. Other views such 7790 * as scrolling containers may prefer to opt-out of this behavior.</p> 7791 * 7792 * <p>The default value for views is true, though subclasses may change this 7793 * based on their preferred behavior.</p> 7794 * 7795 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 7796 * 7797 * @see #getRevealOnFocusHint() 7798 */ 7799 public final void setRevealOnFocusHint(boolean revealOnFocus) { 7800 if (revealOnFocus) { 7801 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 7802 } else { 7803 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 7804 } 7805 } 7806 7807 /** 7808 * Returns this view's preference for reveal behavior when it gains focus. 7809 * 7810 * <p>When this method returns true for a child view requesting focus, ancestor 7811 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 7812 * should make a best effort to make the newly focused child fully visible to the user. 7813 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 7814 * other properties affecting visibility to the user as part of the focus change.</p> 7815 * 7816 * @return true if this view would prefer to become fully visible when it gains focus, 7817 * false if it would prefer not to disrupt scroll positioning 7818 * 7819 * @see #setRevealOnFocusHint(boolean) 7820 */ 7821 public final boolean getRevealOnFocusHint() { 7822 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 7823 } 7824 7825 /** 7826 * Populates <code>outRect</code> with the hotspot bounds. By default, 7827 * the hotspot bounds are identical to the screen bounds. 7828 * 7829 * @param outRect rect to populate with hotspot bounds 7830 * @hide Only for internal use by views and widgets. 7831 */ 7832 public void getHotspotBounds(Rect outRect) { 7833 final Drawable background = getBackground(); 7834 if (background != null) { 7835 background.getHotspotBounds(outRect); 7836 } else { 7837 getBoundsOnScreen(outRect); 7838 } 7839 } 7840 7841 /** 7842 * Request that a rectangle of this view be visible on the screen, 7843 * scrolling if necessary just enough. 7844 * 7845 * <p>A View should call this if it maintains some notion of which part 7846 * of its content is interesting. For example, a text editing view 7847 * should call this when its cursor moves. 7848 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7849 * It should not be affected by which part of the View is currently visible or its scroll 7850 * position. 7851 * 7852 * @param rectangle The rectangle in the View's content coordinate space 7853 * @return Whether any parent scrolled. 7854 */ 7855 public boolean requestRectangleOnScreen(Rect rectangle) { 7856 return requestRectangleOnScreen(rectangle, false); 7857 } 7858 7859 /** 7860 * Request that a rectangle of this view be visible on the screen, 7861 * scrolling if necessary just enough. 7862 * 7863 * <p>A View should call this if it maintains some notion of which part 7864 * of its content is interesting. For example, a text editing view 7865 * should call this when its cursor moves. 7866 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7867 * It should not be affected by which part of the View is currently visible or its scroll 7868 * position. 7869 * <p>When <code>immediate</code> is set to true, scrolling will not be 7870 * animated. 7871 * 7872 * @param rectangle The rectangle in the View's content coordinate space 7873 * @param immediate True to forbid animated scrolling, false otherwise 7874 * @return Whether any parent scrolled. 7875 */ 7876 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7877 if (mParent == null) { 7878 return false; 7879 } 7880 7881 View child = this; 7882 7883 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7884 position.set(rectangle); 7885 7886 ViewParent parent = mParent; 7887 boolean scrolled = false; 7888 while (parent != null) { 7889 rectangle.set((int) position.left, (int) position.top, 7890 (int) position.right, (int) position.bottom); 7891 7892 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7893 7894 if (!(parent instanceof View)) { 7895 break; 7896 } 7897 7898 // move it from child's content coordinate space to parent's content coordinate space 7899 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 7900 7901 child = (View) parent; 7902 parent = child.getParent(); 7903 } 7904 7905 return scrolled; 7906 } 7907 7908 /** 7909 * Called when this view wants to give up focus. If focus is cleared 7910 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 7911 * <p> 7912 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 7913 * to the first focusable View from the top after focus is cleared. Hence, if this 7914 * View is the first from the top that can take focus, then all callbacks 7915 * related to clearing focus will be invoked after which the framework will 7916 * give focus to this view. 7917 * </p> 7918 */ 7919 public void clearFocus() { 7920 if (DBG) { 7921 System.out.println(this + " clearFocus()"); 7922 } 7923 7924 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 7925 clearFocusInternal(null, true, refocus); 7926 } 7927 7928 /** 7929 * Clears focus from the view, optionally propagating the change up through 7930 * the parent hierarchy and requesting that the root view place new focus. 7931 * 7932 * @param propagate whether to propagate the change up through the parent 7933 * hierarchy 7934 * @param refocus when propagate is true, specifies whether to request the 7935 * root view place new focus 7936 */ 7937 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 7938 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 7939 mPrivateFlags &= ~PFLAG_FOCUSED; 7940 clearParentsWantFocus(); 7941 7942 if (propagate && mParent != null) { 7943 mParent.clearChildFocus(this); 7944 } 7945 7946 onFocusChanged(false, 0, null); 7947 refreshDrawableState(); 7948 7949 if (propagate && (!refocus || !rootViewRequestFocus())) { 7950 notifyGlobalFocusCleared(this); 7951 } 7952 } 7953 } 7954 7955 void notifyGlobalFocusCleared(View oldFocus) { 7956 if (oldFocus != null && mAttachInfo != null) { 7957 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 7958 } 7959 } 7960 7961 boolean rootViewRequestFocus() { 7962 final View root = getRootView(); 7963 return root != null && root.requestFocus(); 7964 } 7965 7966 /** 7967 * Called internally by the view system when a new view is getting focus. 7968 * This is what clears the old focus. 7969 * <p> 7970 * <b>NOTE:</b> The parent view's focused child must be updated manually 7971 * after calling this method. Otherwise, the view hierarchy may be left in 7972 * an inconstent state. 7973 */ 7974 void unFocus(View focused) { 7975 if (DBG) { 7976 System.out.println(this + " unFocus()"); 7977 } 7978 7979 clearFocusInternal(focused, false, false); 7980 } 7981 7982 /** 7983 * Returns true if this view has focus itself, or is the ancestor of the 7984 * view that has focus. 7985 * 7986 * @return True if this view has or contains focus, false otherwise. 7987 */ 7988 @ViewDebug.ExportedProperty(category = "focus") 7989 public boolean hasFocus() { 7990 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7991 } 7992 7993 /** 7994 * Returns true if this view is focusable or if it contains a reachable View 7995 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 7996 * is a view whose parents do not block descendants focus. 7997 * Only {@link #VISIBLE} views are considered focusable. 7998 * 7999 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8000 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8001 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8002 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8003 * {@code false} for views not explicitly marked as focusable. 8004 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8005 * behavior.</p> 8006 * 8007 * @return {@code true} if the view is focusable or if the view contains a focusable 8008 * view, {@code false} otherwise 8009 * 8010 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8011 * @see ViewGroup#getTouchscreenBlocksFocus() 8012 * @see #hasExplicitFocusable() 8013 */ 8014 public boolean hasFocusable() { 8015 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8016 } 8017 8018 /** 8019 * Returns true if this view is focusable or if it contains a reachable View 8020 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8021 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8022 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8023 * {@link #FOCUSABLE} are considered focusable. 8024 * 8025 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8026 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8027 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8028 * to focusable will not.</p> 8029 * 8030 * @return {@code true} if the view is focusable or if the view contains a focusable 8031 * view, {@code false} otherwise 8032 * 8033 * @see #hasFocusable() 8034 */ 8035 public boolean hasExplicitFocusable() { 8036 return hasFocusable(false, true); 8037 } 8038 8039 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8040 if (!isFocusableInTouchMode()) { 8041 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8042 final ViewGroup g = (ViewGroup) p; 8043 if (g.shouldBlockFocusForTouchscreen()) { 8044 return false; 8045 } 8046 } 8047 } 8048 8049 // Invisible, gone, or disabled views are never focusable. 8050 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8051 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8052 return false; 8053 } 8054 8055 // Only use effective focusable value when allowed. 8056 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8057 return true; 8058 } 8059 8060 return false; 8061 } 8062 8063 /** 8064 * Called by the view system when the focus state of this view changes. 8065 * When the focus change event is caused by directional navigation, direction 8066 * and previouslyFocusedRect provide insight into where the focus is coming from. 8067 * When overriding, be sure to call up through to the super class so that 8068 * the standard focus handling will occur. 8069 * 8070 * @param gainFocus True if the View has focus; false otherwise. 8071 * @param direction The direction focus has moved when requestFocus() 8072 * is called to give this view focus. Values are 8073 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8074 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8075 * It may not always apply, in which case use the default. 8076 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8077 * system, of the previously focused view. If applicable, this will be 8078 * passed in as finer grained information about where the focus is coming 8079 * from (in addition to direction). Will be <code>null</code> otherwise. 8080 */ 8081 @CallSuper 8082 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8083 @Nullable Rect previouslyFocusedRect) { 8084 if (gainFocus) { 8085 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8086 } else { 8087 notifyViewAccessibilityStateChangedIfNeeded( 8088 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8089 } 8090 8091 // Here we check whether we still need the default focus highlight, and switch it on/off. 8092 switchDefaultFocusHighlight(); 8093 8094 if (!gainFocus) { 8095 if (isPressed()) { 8096 setPressed(false); 8097 } 8098 if (hasWindowFocus()) { 8099 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8100 } 8101 onFocusLost(); 8102 } else if (hasWindowFocus()) { 8103 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8104 } 8105 8106 invalidate(true); 8107 ListenerInfo li = mListenerInfo; 8108 if (li != null && li.mOnFocusChangeListener != null) { 8109 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8110 } 8111 8112 if (mAttachInfo != null) { 8113 mAttachInfo.mKeyDispatchState.reset(this); 8114 } 8115 8116 if (mParent != null) { 8117 mParent.onDescendantUnbufferedRequested(); 8118 } 8119 8120 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8121 } 8122 8123 /** 8124 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8125 * 8126 * @param hasFocus {@code true} when the {@link View} is being focused. 8127 */ 8128 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8129 if (mAttachInfo == null) { 8130 return; 8131 } 8132 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8133 } 8134 8135 /** @hide */ 8136 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8137 if (canNotifyAutofillEnterExitEvent()) { 8138 AutofillManager afm = getAutofillManager(); 8139 if (afm != null) { 8140 if (enter && isFocused()) { 8141 // We have not been laid out yet, hence cannot evaluate 8142 // whether this view is visible to the user, we will do 8143 // the evaluation once layout is complete. 8144 if (!isLaidOut()) { 8145 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8146 } else if (isVisibleToUser()) { 8147 // TODO This is a potential problem that View gets focus before it's visible 8148 // to User. Ideally View should handle the event when isVisibleToUser() 8149 // becomes true where it should issue notifyViewEntered(). 8150 afm.notifyViewEntered(this); 8151 } 8152 } else if (!enter && !isFocused()) { 8153 afm.notifyViewExited(this); 8154 } 8155 } 8156 } 8157 } 8158 8159 /** 8160 * Visually distinct portion of a window with window-like semantics are considered panes for 8161 * accessibility purposes. One example is the content view of a fragment that is replaced. 8162 * In order for accessibility services to understand a pane's window-like behavior, panes 8163 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 8164 * when they appear, disappear, or change title. 8165 * 8166 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8167 * View is not a pane. 8168 * 8169 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8170 * 8171 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8172 */ 8173 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8174 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8175 mAccessibilityPaneTitle = accessibilityPaneTitle; 8176 notifyViewAccessibilityStateChangedIfNeeded( 8177 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8178 } 8179 } 8180 8181 /** 8182 * Get the title of the pane for purposes of accessibility. 8183 * 8184 * @return The current pane title. 8185 * 8186 * {@see #setAccessibilityPaneTitle}. 8187 * 8188 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8189 */ 8190 @InspectableProperty 8191 @Nullable 8192 public CharSequence getAccessibilityPaneTitle() { 8193 return mAccessibilityPaneTitle; 8194 } 8195 8196 private boolean isAccessibilityPane() { 8197 return mAccessibilityPaneTitle != null; 8198 } 8199 8200 /** 8201 * Sends an accessibility event of the given type. If accessibility is 8202 * not enabled this method has no effect. The default implementation calls 8203 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8204 * to populate information about the event source (this View), then calls 8205 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8206 * populate the text content of the event source including its descendants, 8207 * and last calls 8208 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8209 * on its parent to request sending of the event to interested parties. 8210 * <p> 8211 * If an {@link AccessibilityDelegate} has been specified via calling 8212 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8213 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8214 * responsible for handling this call. 8215 * </p> 8216 * 8217 * @param eventType The type of the event to send, as defined by several types from 8218 * {@link android.view.accessibility.AccessibilityEvent}, such as 8219 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 8220 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8221 * 8222 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8223 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8224 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8225 * @see AccessibilityDelegate 8226 */ 8227 public void sendAccessibilityEvent(int eventType) { 8228 if (mAccessibilityDelegate != null) { 8229 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8230 } else { 8231 sendAccessibilityEventInternal(eventType); 8232 } 8233 } 8234 8235 /** 8236 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8237 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8238 * specified text to its users. 8239 * <p> 8240 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8241 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8242 * accurately supplying the semantics of their UI. 8243 * They should not need to specify what exactly is announced to users. 8244 * 8245 * @param text The announcement text. 8246 */ 8247 public void announceForAccessibility(CharSequence text) { 8248 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8249 AccessibilityEvent event = AccessibilityEvent.obtain( 8250 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8251 onInitializeAccessibilityEvent(event); 8252 event.getText().add(text); 8253 event.setContentDescription(null); 8254 mParent.requestSendAccessibilityEvent(this, event); 8255 } 8256 } 8257 8258 /** 8259 * @see #sendAccessibilityEvent(int) 8260 * 8261 * Note: Called from the default {@link AccessibilityDelegate}. 8262 * 8263 * @hide 8264 */ 8265 public void sendAccessibilityEventInternal(int eventType) { 8266 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8267 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8268 } 8269 } 8270 8271 /** 8272 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8273 * takes as an argument an empty {@link AccessibilityEvent} and does not 8274 * perform a check whether accessibility is enabled. 8275 * <p> 8276 * If an {@link AccessibilityDelegate} has been specified via calling 8277 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8278 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8279 * is responsible for handling this call. 8280 * </p> 8281 * 8282 * @param event The event to send. 8283 * 8284 * @see #sendAccessibilityEvent(int) 8285 */ 8286 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8287 if (mAccessibilityDelegate != null) { 8288 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8289 } else { 8290 sendAccessibilityEventUncheckedInternal(event); 8291 } 8292 } 8293 8294 /** 8295 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8296 * 8297 * Note: Called from the default {@link AccessibilityDelegate}. 8298 * 8299 * @hide 8300 */ 8301 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8302 // Panes disappearing are relevant even if though the view is no longer visible. 8303 boolean isWindowStateChanged = 8304 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8305 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8306 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8307 boolean detached = detached(); 8308 if (!isShown() && !isWindowDisappearedEvent && !detached) { 8309 return; 8310 } 8311 onInitializeAccessibilityEvent(event); 8312 // Only a subset of accessibility events populates text content. 8313 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8314 dispatchPopulateAccessibilityEvent(event); 8315 } 8316 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 8317 if (throttle != null) { 8318 throttle.post(event); 8319 } else if (!isWindowDisappearedEvent && detached) { 8320 // Views could be attached soon later. Accessibility events during this temporarily 8321 // detached period should be sent too. 8322 postDelayed(() -> { 8323 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 8324 requestParentSendAccessibilityEvent(event); 8325 } 8326 }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 8327 } else { 8328 requestParentSendAccessibilityEvent(event); 8329 } 8330 } 8331 8332 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 8333 ViewParent parent = getParent(); 8334 if (parent != null) { 8335 getParent().requestSendAccessibilityEvent(this, event); 8336 } 8337 } 8338 8339 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 8340 AccessibilityEvent event) { 8341 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 8342 if (mSendViewScrolledAccessibilityEvent == null) { 8343 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 8344 } 8345 return mSendViewScrolledAccessibilityEvent; 8346 } 8347 boolean isStateContentChanged = (event.getContentChangeTypes() 8348 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 8349 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 8350 && isStateContentChanged) { 8351 if (mSendStateChangedAccessibilityEvent == null) { 8352 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 8353 } 8354 return mSendStateChangedAccessibilityEvent; 8355 } 8356 return null; 8357 } 8358 8359 private void clearAccessibilityThrottles() { 8360 cancel(mSendViewScrolledAccessibilityEvent); 8361 cancel(mSendStateChangedAccessibilityEvent); 8362 } 8363 8364 /** 8365 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8366 * to its children for adding their text content to the event. Note that the 8367 * event text is populated in a separate dispatch path since we add to the 8368 * event not only the text of the source but also the text of all its descendants. 8369 * A typical implementation will call 8370 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8371 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8372 * on each child. Override this method if custom population of the event text 8373 * content is required. 8374 * <p> 8375 * If an {@link AccessibilityDelegate} has been specified via calling 8376 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8377 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8378 * is responsible for handling this call. 8379 * </p> 8380 * <p> 8381 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8382 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8383 * </p> 8384 * 8385 * @param event The event. 8386 * 8387 * @return True if the event population was completed. 8388 */ 8389 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8390 if (mAccessibilityDelegate != null) { 8391 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8392 } else { 8393 return dispatchPopulateAccessibilityEventInternal(event); 8394 } 8395 } 8396 8397 /** 8398 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8399 * 8400 * Note: Called from the default {@link AccessibilityDelegate}. 8401 * 8402 * @hide 8403 */ 8404 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8405 onPopulateAccessibilityEvent(event); 8406 return false; 8407 } 8408 8409 /** 8410 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8411 * giving a chance to this View to populate the accessibility event with its 8412 * text content. While this method is free to modify event 8413 * attributes other than text content, doing so should normally be performed in 8414 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8415 * <p> 8416 * Example: Adding formatted date string to an accessibility event in addition 8417 * to the text added by the super implementation: 8418 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8419 * super.onPopulateAccessibilityEvent(event); 8420 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8421 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8422 * mCurrentDate.getTimeInMillis(), flags); 8423 * event.getText().add(selectedDateUtterance); 8424 * }</pre> 8425 * <p> 8426 * If an {@link AccessibilityDelegate} has been specified via calling 8427 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8428 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8429 * is responsible for handling this call. 8430 * </p> 8431 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8432 * information to the event, in case the default implementation has basic information to add. 8433 * </p> 8434 * 8435 * @param event The accessibility event which to populate. 8436 * 8437 * @see #sendAccessibilityEvent(int) 8438 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8439 */ 8440 @CallSuper 8441 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8442 if (mAccessibilityDelegate != null) { 8443 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8444 } else { 8445 onPopulateAccessibilityEventInternal(event); 8446 } 8447 } 8448 8449 /** 8450 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8451 * 8452 * Note: Called from the default {@link AccessibilityDelegate}. 8453 * 8454 * @hide 8455 */ 8456 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8457 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8458 && isAccessibilityPane()) { 8459 event.getText().add(getAccessibilityPaneTitle()); 8460 } 8461 } 8462 8463 /** 8464 * Initializes an {@link AccessibilityEvent} with information about 8465 * this View which is the event source. In other words, the source of 8466 * an accessibility event is the view whose state change triggered firing 8467 * the event. 8468 * <p> 8469 * Example: Setting the password property of an event in addition 8470 * to properties set by the super implementation: 8471 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8472 * super.onInitializeAccessibilityEvent(event); 8473 * event.setPassword(true); 8474 * }</pre> 8475 * <p> 8476 * If an {@link AccessibilityDelegate} has been specified via calling 8477 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8478 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8479 * is responsible for handling this call. 8480 * </p> 8481 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8482 * information to the event, in case the default implementation has basic information to add. 8483 * </p> 8484 * @param event The event to initialize. 8485 * 8486 * @see #sendAccessibilityEvent(int) 8487 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8488 */ 8489 @CallSuper 8490 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8491 if (mAccessibilityDelegate != null) { 8492 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8493 } else { 8494 onInitializeAccessibilityEventInternal(event); 8495 } 8496 } 8497 8498 /** 8499 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8500 * 8501 * Note: Called from the default {@link AccessibilityDelegate}. 8502 * 8503 * @hide 8504 */ 8505 @UnsupportedAppUsage 8506 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8507 event.setSource(this); 8508 event.setClassName(getAccessibilityClassName()); 8509 event.setPackageName(getContext().getPackageName()); 8510 event.setEnabled(isEnabled()); 8511 event.setContentDescription(mContentDescription); 8512 event.setScrollX(getScrollX()); 8513 event.setScrollY(getScrollY()); 8514 8515 switch (event.getEventType()) { 8516 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8517 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8518 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8519 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8520 event.setItemCount(focusablesTempList.size()); 8521 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8522 if (mAttachInfo != null) { 8523 focusablesTempList.clear(); 8524 } 8525 } break; 8526 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8527 CharSequence text = getIterableTextForAccessibility(); 8528 if (text != null && text.length() > 0) { 8529 event.setFromIndex(getAccessibilitySelectionStart()); 8530 event.setToIndex(getAccessibilitySelectionEnd()); 8531 event.setItemCount(text.length()); 8532 } 8533 } break; 8534 } 8535 } 8536 8537 /** 8538 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8539 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8540 * This method is responsible for obtaining an accessibility node info from a 8541 * pool of reusable instances and calling 8542 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8543 * initialize the former. 8544 * <p> 8545 * Note: The client is responsible for recycling the obtained instance by calling 8546 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8547 * </p> 8548 * 8549 * @return A populated {@link AccessibilityNodeInfo}. 8550 * 8551 * @see AccessibilityNodeInfo 8552 */ 8553 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8554 if (mAccessibilityDelegate != null) { 8555 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8556 } else { 8557 return createAccessibilityNodeInfoInternal(); 8558 } 8559 } 8560 8561 /** 8562 * @see #createAccessibilityNodeInfo() 8563 * 8564 * @hide 8565 */ 8566 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8567 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8568 if (provider != null) { 8569 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8570 } else { 8571 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8572 onInitializeAccessibilityNodeInfo(info); 8573 return info; 8574 } 8575 } 8576 8577 /** 8578 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8579 * The base implementation sets: 8580 * <ul> 8581 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8582 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8583 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8584 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8585 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8586 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8587 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8588 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8589 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8590 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8591 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8592 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8593 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8594 * </ul> 8595 * <p> 8596 * Subclasses should override this method, call the super implementation, 8597 * and set additional attributes. 8598 * </p> 8599 * <p> 8600 * If an {@link AccessibilityDelegate} has been specified via calling 8601 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8602 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8603 * is responsible for handling this call. 8604 * </p> 8605 * 8606 * @param info The instance to initialize. 8607 */ 8608 @CallSuper 8609 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8610 if (mAccessibilityDelegate != null) { 8611 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8612 } else { 8613 onInitializeAccessibilityNodeInfoInternal(info); 8614 } 8615 } 8616 8617 /** 8618 * Gets the location of this view in screen coordinates. 8619 * 8620 * @param outRect The output location 8621 * @hide 8622 */ 8623 @UnsupportedAppUsage 8624 public void getBoundsOnScreen(Rect outRect) { 8625 getBoundsOnScreen(outRect, false); 8626 } 8627 8628 /** 8629 * Gets the location of this view in screen coordinates. 8630 * 8631 * @param outRect The output location 8632 * @param clipToParent Whether to clip child bounds to the parent ones. 8633 * @hide 8634 */ 8635 @UnsupportedAppUsage 8636 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 8637 if (mAttachInfo == null) { 8638 return; 8639 } 8640 8641 RectF position = mAttachInfo.mTmpTransformRect; 8642 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8643 mapRectFromViewToScreenCoords(position, clipToParent); 8644 outRect.set(Math.round(position.left), Math.round(position.top), 8645 Math.round(position.right), Math.round(position.bottom)); 8646 } 8647 8648 /** 8649 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8650 * 8651 * @param rect The rectangle to be mapped 8652 * @param clipToParent Whether to clip child bounds to the parent ones. 8653 * @hide 8654 */ 8655 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8656 if (!hasIdentityMatrix()) { 8657 getMatrix().mapRect(rect); 8658 } 8659 8660 rect.offset(mLeft, mTop); 8661 8662 ViewParent parent = mParent; 8663 while (parent instanceof View) { 8664 View parentView = (View) parent; 8665 8666 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 8667 8668 if (clipToParent) { 8669 rect.left = Math.max(rect.left, 0); 8670 rect.top = Math.max(rect.top, 0); 8671 rect.right = Math.min(rect.right, parentView.getWidth()); 8672 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 8673 } 8674 8675 if (!parentView.hasIdentityMatrix()) { 8676 parentView.getMatrix().mapRect(rect); 8677 } 8678 8679 rect.offset(parentView.mLeft, parentView.mTop); 8680 8681 parent = parentView.mParent; 8682 } 8683 8684 if (parent instanceof ViewRootImpl) { 8685 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 8686 rect.offset(0, -viewRootImpl.mCurScrollY); 8687 } 8688 8689 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8690 } 8691 8692 /** 8693 * Return the class name of this object to be used for accessibility purposes. 8694 * Subclasses should only override this if they are implementing something that 8695 * should be seen as a completely new class of view when used by accessibility, 8696 * unrelated to the class it is deriving from. This is used to fill in 8697 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 8698 */ 8699 public CharSequence getAccessibilityClassName() { 8700 return View.class.getName(); 8701 } 8702 8703 /** 8704 * Called when assist structure is being retrieved from a view as part of 8705 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 8706 * @param structure Fill in with structured view data. The default implementation 8707 * fills in all data that can be inferred from the view itself. 8708 */ 8709 public void onProvideStructure(ViewStructure structure) { 8710 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 8711 } 8712 8713 /** 8714 * Populates a {@link ViewStructure} to fullfil an autofill request. 8715 * 8716 * <p>The structure should contain at least the following properties: 8717 * <ul> 8718 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 8719 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 8720 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 8721 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 8722 * </ul> 8723 * 8724 * <p>It's also recommended to set the following properties - the more properties the structure 8725 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 8726 * using the structure: 8727 * 8728 * <ul> 8729 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 8730 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 8731 * view can only be filled with predefined values (typically used when the autofill type 8732 * is {@link #AUTOFILL_TYPE_LIST}). 8733 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 8734 * <li>Class name ({@link ViewStructure#setClassName(String)}). 8735 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 8736 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 8737 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 8738 * opacity ({@link ViewStructure#setOpaque(boolean)}). 8739 * <li>For views representing text fields, text properties such as the text itself 8740 * ({@link ViewStructure#setText(CharSequence)}), text hints 8741 * ({@link ViewStructure#setHint(CharSequence)}, input type 8742 * ({@link ViewStructure#setInputType(int)}), 8743 * <li>For views representing HTML nodes, its web domain 8744 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 8745 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 8746 * </ul> 8747 * 8748 * <p>The default implementation of this method already sets most of these properties based on 8749 * related {@link View} methods (for example, the autofill id is set using 8750 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 8751 * and views in the standard Android widgets library also override it to set their 8752 * relevant properties (for example, {@link android.widget.TextView} already sets the text 8753 * properties), so it's recommended to only override this method 8754 * (and call {@code super.onProvideAutofillStructure()}) when: 8755 * 8756 * <ul> 8757 * <li>The view contents does not include PII (Personally Identifiable Information), so it 8758 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 8759 * <li>The view can only be autofilled with predefined options, so it can call 8760 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 8761 * </ul> 8762 * 8763 * <p><b>Note:</b> The {@code left} and {@code top} values set in 8764 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 8765 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 8766 * 8767 * <p>Views support the Autofill Framework mainly by: 8768 * <ul> 8769 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8770 * <li>Notifying the Android System when the view value changed by calling 8771 * {@link AutofillManager#notifyValueChanged(View)}. 8772 * <li>Implementing the methods that autofill the view. 8773 * </ul> 8774 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 8775 * for the latter. 8776 * 8777 * @param structure fill in with structured view data for autofill purposes. 8778 * @param flags optional flags. 8779 * 8780 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8781 */ 8782 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 8783 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 8784 } 8785 8786 /** 8787 * Populates a {@link ViewStructure} for content capture. 8788 * 8789 * <p>This method is called after a view that is eligible for content capture 8790 * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is 8791 * enabled for the user, and the activity rendering the view is enabled for content capture) 8792 * is laid out and is visible. The populated structure is then passed to the service through 8793 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 8794 * 8795 * <p>The default implementation of this method sets the most relevant properties based on 8796 * related {@link View} methods, and views in the standard Android widgets library also 8797 * override it to set their relevant properties. Therefore, if overriding this method, it 8798 * is recommended to call {@code super.onProvideContentCaptureStructure()}. 8799 * 8800 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 8801 * the node representing this view and return right away, then asynchronously report (not 8802 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 8803 * changed by calling 8804 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 8805 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 8806 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 8807 * respectively. The structure for a child must be created using 8808 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 8809 * {@code autofillId} for a child can be obtained either through 8810 * {@code childStructure.getAutofillId()} or 8811 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 8812 * 8813 * <p>When the virtual view hierarchy represents a web page, you should also: 8814 * 8815 * <ul> 8816 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 8817 * capture events should be generate for that URL. 8818 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 8819 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 8820 * that subtree. 8821 * </ul> 8822 * 8823 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 8824 * <ul> 8825 * <li>{@link ViewStructure#setChildCount(int)} 8826 * <li>{@link ViewStructure#addChildCount(int)} 8827 * <li>{@link ViewStructure#getChildCount()} 8828 * <li>{@link ViewStructure#newChild(int)} 8829 * <li>{@link ViewStructure#asyncNewChild(int)} 8830 * <li>{@link ViewStructure#asyncCommit()} 8831 * <li>{@link ViewStructure#setWebDomain(String)} 8832 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 8833 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 8834 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 8835 * <li>{@link ViewStructure#setAlpha(float)} 8836 * <li>{@link ViewStructure#setElevation(float)} 8837 * <li>{@link ViewStructure#setTransformation(Matrix)} 8838 * 8839 * </ul> 8840 */ 8841 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 8842 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 8843 } 8844 8845 /** @hide */ 8846 protected void onProvideStructure(@NonNull ViewStructure structure, 8847 @ViewStructureType int viewFor, int flags) { 8848 final int id = mID; 8849 if (id != NO_ID && !isViewIdGenerated(id)) { 8850 String pkg, type, entry; 8851 try { 8852 final Resources res = getResources(); 8853 entry = res.getResourceEntryName(id); 8854 type = res.getResourceTypeName(id); 8855 pkg = res.getResourcePackageName(id); 8856 } catch (Resources.NotFoundException e) { 8857 entry = type = pkg = null; 8858 } 8859 structure.setId(id, pkg, type, entry); 8860 } else { 8861 structure.setId(id, null, null, null); 8862 } 8863 8864 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8865 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 8866 final @AutofillType int autofillType = getAutofillType(); 8867 // Don't need to fill autofill info if view does not support it. 8868 // For example, only TextViews that are editable support autofill 8869 if (autofillType != AUTOFILL_TYPE_NONE) { 8870 structure.setAutofillType(autofillType); 8871 structure.setAutofillHints(getAutofillHints()); 8872 structure.setAutofillValue(getAutofillValue()); 8873 } 8874 structure.setImportantForAutofill(getImportantForAutofill()); 8875 structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); 8876 } 8877 8878 int ignoredParentLeft = 0; 8879 int ignoredParentTop = 0; 8880 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8881 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 8882 View parentGroup = null; 8883 8884 ViewParent viewParent = getParent(); 8885 if (viewParent instanceof View) { 8886 parentGroup = (View) viewParent; 8887 } 8888 8889 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 8890 ignoredParentLeft += parentGroup.mLeft; 8891 ignoredParentTop += parentGroup.mTop; 8892 8893 viewParent = parentGroup.getParent(); 8894 if (viewParent instanceof View) { 8895 parentGroup = (View) viewParent; 8896 } else { 8897 break; 8898 } 8899 } 8900 } 8901 8902 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 8903 mRight - mLeft, mBottom - mTop); 8904 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 8905 if (!hasIdentityMatrix()) { 8906 structure.setTransformation(getMatrix()); 8907 } 8908 structure.setElevation(getZ()); 8909 } 8910 structure.setVisibility(getVisibility()); 8911 structure.setEnabled(isEnabled()); 8912 if (isClickable()) { 8913 structure.setClickable(true); 8914 } 8915 if (isFocusable()) { 8916 structure.setFocusable(true); 8917 } 8918 if (isFocused()) { 8919 structure.setFocused(true); 8920 } 8921 if (isAccessibilityFocused()) { 8922 structure.setAccessibilityFocused(true); 8923 } 8924 if (isSelected()) { 8925 structure.setSelected(true); 8926 } 8927 if (isActivated()) { 8928 structure.setActivated(true); 8929 } 8930 if (isLongClickable()) { 8931 structure.setLongClickable(true); 8932 } 8933 if (this instanceof Checkable) { 8934 structure.setCheckable(true); 8935 if (((Checkable)this).isChecked()) { 8936 structure.setChecked(true); 8937 } 8938 } 8939 if (isOpaque()) { 8940 structure.setOpaque(true); 8941 } 8942 if (isContextClickable()) { 8943 structure.setContextClickable(true); 8944 } 8945 structure.setClassName(getAccessibilityClassName().toString()); 8946 structure.setContentDescription(getContentDescription()); 8947 } 8948 8949 /** 8950 * Called when assist structure is being retrieved from a view as part of 8951 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 8952 * generate additional virtual structure under this view. The default implementation 8953 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 8954 * view's virtual accessibility nodes, if any. You can override this for a more 8955 * optimal implementation providing this data. 8956 */ 8957 public void onProvideVirtualStructure(ViewStructure structure) { 8958 onProvideVirtualStructureCompat(structure, false); 8959 } 8960 8961 /** 8962 * Fallback implementation to populate a ViewStructure from accessibility state. 8963 * 8964 * @param structure The structure to populate. 8965 * @param forAutofill Whether the structure is needed for autofill. 8966 */ 8967 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 8968 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8969 if (provider != null) { 8970 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8971 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 8972 } 8973 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 8974 structure.setChildCount(1); 8975 final ViewStructure root = structure.newChild(0); 8976 populateVirtualStructure(root, provider, info, forAutofill); 8977 info.recycle(); 8978 } 8979 } 8980 8981 /** 8982 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 8983 * request. 8984 * 8985 * <p>This method should be used when the view manages a virtual structure under this view. For 8986 * example, a view that draws input fields using {@link #draw(Canvas)}. 8987 * 8988 * <p>When implementing this method, subclasses must follow the rules below: 8989 * 8990 * <ul> 8991 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 8992 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 8993 * identifying the children in the virtual structure. 8994 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 8995 * exclude intermediate levels that are irrelevant for autofill; that would improve the 8996 * autofill performance. 8997 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 8998 * children. 8999 * <li>Set the autofill properties of the child structure as defined by 9000 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 9001 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 9002 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 9003 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 9004 * when the focused virtual child changed. 9005 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9006 * whether a given virtual view is visible to the user in order to support triggering 9007 * save when all views of interest go away. 9008 * <li>Call 9009 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9010 * when the value of a virtual child changed. 9011 * <li>Call {@link 9012 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9013 * when the visibility of a virtual child changed. 9014 * <li>Call 9015 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9016 * child is clicked. 9017 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9018 * changed and the current context should be committed (for example, when the user tapped 9019 * a {@code SUBMIT} button in an HTML page). 9020 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9021 * changed and the current context should be canceled (for example, when the user tapped 9022 * a {@code CANCEL} button in an HTML page). 9023 * <li>Provide ways for users to manually request autofill by calling 9024 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9025 * <li>The {@code left} and {@code top} values set in 9026 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9027 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9028 * structure. 9029 * </ul> 9030 * 9031 * <p>Views with virtual children support the Autofill Framework mainly by: 9032 * <ul> 9033 * <li>Providing the metadata defining what the virtual children mean and how they can be 9034 * autofilled. 9035 * <li>Implementing the methods that autofill the virtual children. 9036 * </ul> 9037 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9038 * for the latter. 9039 * 9040 * @param structure fill in with virtual children data for autofill purposes. 9041 * @param flags optional flags. 9042 * 9043 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9044 */ 9045 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9046 if (mContext.isAutofillCompatibilityEnabled()) { 9047 onProvideVirtualStructureCompat(structure, true); 9048 } 9049 } 9050 9051 /** 9052 * Sets the listener to be {@link #performReceiveContent used} to handle insertion of 9053 * content into this view. 9054 * 9055 * <p>Depending on the type of view, this listener may be invoked for different scenarios. For 9056 * example, for an editable {@link android.widget.TextView}, this listener will be invoked for 9057 * the following scenarios: 9058 * <ol> 9059 * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the 9060 * insertion/selection menu) 9061 * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent}) 9062 * <li>Drag and drop (drop events from {@link #onDragEvent}) 9063 * <li>Autofill 9064 * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT} 9065 * </ol> 9066 * 9067 * <p>When setting a listener, clients must also declare the accepted MIME types. 9068 * The listener will still be invoked even if the MIME type of the content is not one of the 9069 * declared MIME types (e.g. if the user pastes content whose type is not one of the declared 9070 * MIME types). 9071 * In that case, the listener may reject the content (defer to the default platform behavior) 9072 * or execute some other fallback logic (e.g. show an appropriate message to the user). 9073 * The declared MIME types serve as a hint to allow different features to optionally alter 9074 * their behavior. For example, a soft keyboard may optionally choose to hide its UI for 9075 * inserting GIFs for a particular input field if the MIME types set here for that field 9076 * don't include "image/gif" or "image/*". 9077 * 9078 * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC 9079 * MIME types. As a result, you should always write your MIME types with lowercase letters, 9080 * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9081 * lowercase. 9082 * 9083 * @param mimeTypes The MIME types accepted by the given listener. These may use patterns 9084 * such as "image/*", but may not start with a wildcard. This argument must 9085 * not be null or empty if a non-null listener is passed in. 9086 * @param listener The listener to use. This can be null to reset to the default behavior. 9087 */ 9088 public void setOnReceiveContentListener( 9089 @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, 9090 @Nullable OnReceiveContentListener listener) { 9091 if (listener != null) { 9092 Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, 9093 "When the listener is set, MIME types must also be set"); 9094 } 9095 if (mimeTypes != null) { 9096 Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")), 9097 "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes)); 9098 } 9099 mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; 9100 getListenerInfo().mOnReceiveContentListener = listener; 9101 } 9102 9103 /** 9104 * Receives the given content. If no listener is set, invokes {@link #onReceiveContent}. If a 9105 * listener is {@link #setOnReceiveContentListener set}, invokes the listener instead; if the 9106 * listener returns a non-null result, invokes {@link #onReceiveContent} to handle it. 9107 * 9108 * @param payload The content to insert and related metadata. 9109 * 9110 * @return The portion of the passed-in content that was not accepted (may be all, some, or none 9111 * of the passed-in content). 9112 */ 9113 @Nullable performReceiveContent(@onNull ContentInfo payload)9114 public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { 9115 final OnReceiveContentListener listener = (mListenerInfo == null) ? null 9116 : getListenerInfo().mOnReceiveContentListener; 9117 if (listener != null) { 9118 final ContentInfo remaining = listener.onReceiveContent(this, payload); 9119 return (remaining == null) ? null : onReceiveContent(remaining); 9120 } 9121 return onReceiveContent(payload); 9122 } 9123 9124 /** 9125 * Implements the default behavior for receiving content for this type of view. The default 9126 * view implementation is a no-op (returns the passed-in content without acting on it). 9127 * 9128 * <p>Widgets should override this method to define their default behavior for receiving 9129 * content. Apps should {@link #setOnReceiveContentListener set a listener} to provide 9130 * app-specific handling for receiving content. 9131 * 9132 * <p>See {@link #setOnReceiveContentListener} and {@link #performReceiveContent} for more info. 9133 * 9134 * @param payload The content to insert and related metadata. 9135 * 9136 * @return The portion of the passed-in content that was not handled (may be all, some, or none 9137 * of the passed-in content). 9138 */ 9139 @Nullable onReceiveContent(@onNull ContentInfo payload)9140 public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { 9141 return payload; 9142 } 9143 9144 /** 9145 * Returns the MIME types accepted by {@link #performReceiveContent} for this view, as 9146 * configured via {@link #setOnReceiveContentListener}. By default returns null. 9147 * 9148 * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft 9149 * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For 9150 * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular 9151 * input field if the MIME types returned here for that field don't include "image/gif" or 9152 * "image/*". 9153 * 9154 * <p>Note: Comparisons of MIME types should be performed using utilities such as 9155 * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to 9156 * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching 9157 * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result, 9158 * you should always write your MIME types with lowercase letters, or use 9159 * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9160 * lowercase. 9161 * 9162 * @return The MIME types accepted by {@link #performReceiveContent} for this view (may 9163 * include patterns such as "image/*"). 9164 */ 9165 @SuppressLint("NullableCollection") 9166 @Nullable getReceiveContentMimeTypes()9167 public String[] getReceiveContentMimeTypes() { 9168 return mReceiveContentMimeTypes; 9169 } 9170 9171 /** 9172 * Automatically fills the content of this view with the {@code value}. 9173 * 9174 * <p>Views support the Autofill Framework mainly by: 9175 * <ul> 9176 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9177 * <li>Implementing the methods that autofill the view. 9178 * </ul> 9179 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 9180 * this method is responsible for latter. 9181 * 9182 * <p>This method does nothing by default, but when overridden it typically: 9183 * <ol> 9184 * <li>Checks if the provided value matches the expected type (which is defined by 9185 * {@link #getAutofillType()}). 9186 * <li>Checks if the view is editable - if it isn't, it should return right away. 9187 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 9188 * <li>Pass the actual value to the equivalent setter in the view. 9189 * </ol> 9190 * 9191 * <p>For example, a text-field view could implement the method this way: 9192 * 9193 * <pre class="prettyprint"> 9194 * @Override 9195 * public void autofill(AutofillValue value) { 9196 * if (!value.isText() || !this.isEditable()) { 9197 * return; 9198 * } 9199 * CharSequence text = value.getTextValue(); 9200 * if (text != null) { 9201 * this.setText(text); 9202 * } 9203 * } 9204 * </pre> 9205 * 9206 * <p>If the value is updated asynchronously, the next call to 9207 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 9208 * changed to the autofilled value. If not, the view will not be considered autofilled. 9209 * 9210 * <p><b>Note:</b> After this method is called, the value returned by 9211 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 9212 * view will not be highlighted as autofilled. 9213 * 9214 * @param value value to be autofilled. 9215 */ autofill(@uppressWarnings"unused") AutofillValue value)9216 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 9217 } 9218 9219 /** 9220 * Automatically fills the content of the virtual children within this view. 9221 * 9222 * <p>Views with virtual children support the Autofill Framework mainly by: 9223 * <ul> 9224 * <li>Providing the metadata defining what the virtual children mean and how they can be 9225 * autofilled. 9226 * <li>Implementing the methods that autofill the virtual children. 9227 * </ul> 9228 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 9229 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 9230 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 9231 * 9232 * <p>If a child value is updated asynchronously, the next call to 9233 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 9234 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 9235 * considered autofilled. 9236 * 9237 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 9238 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 9239 * changes. 9240 * 9241 * @param values map of values to be autofilled, keyed by virtual child id. 9242 * 9243 * @attr ref android.R.styleable#Theme_autofilledHighlight 9244 */ autofill(@onNull @uppressWarnings"unused") SparseArray<AutofillValue> values)9245 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 9246 if (!mContext.isAutofillCompatibilityEnabled()) { 9247 return; 9248 } 9249 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9250 if (provider == null) { 9251 return; 9252 } 9253 final int valueCount = values.size(); 9254 for (int i = 0; i < valueCount; i++) { 9255 final AutofillValue value = values.valueAt(i); 9256 if (value.isText()) { 9257 final int virtualId = values.keyAt(i); 9258 final CharSequence text = value.getTextValue(); 9259 final Bundle arguments = new Bundle(); 9260 arguments.putCharSequence( 9261 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 9262 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 9263 } 9264 } 9265 } 9266 9267 /** 9268 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 9269 * 9270 * <p>The autofill id is created on demand, unless it is explicitly set by 9271 * {@link #setAutofillId(AutofillId)}. 9272 * 9273 * <p>See {@link #setAutofillId(AutofillId)} for more info. 9274 * 9275 * @return The View's autofill id. 9276 */ getAutofillId()9277 public final AutofillId getAutofillId() { 9278 if (mAutofillId == null) { 9279 // The autofill id needs to be unique, but its value doesn't matter, 9280 // so it's better to reuse the accessibility id to save space. 9281 mAutofillId = new AutofillId(getAutofillViewId()); 9282 } 9283 return mAutofillId; 9284 } 9285 9286 /** 9287 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 9288 * 9289 * <p>The autofill id is created on demand, and this method should only be called when a view is 9290 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 9291 * that method creates a snapshot of the view that is passed along to the autofill service. 9292 * 9293 * <p>This method is typically used when view subtrees are recycled to represent different 9294 * content* —in this case, the autofill id can be saved before the view content is swapped 9295 * out, and restored later when it's swapped back in. For example: 9296 * 9297 * <pre> 9298 * EditText reusableView = ...; 9299 * ViewGroup parentView = ...; 9300 * AutofillManager afm = ...; 9301 * 9302 * // Swap out the view and change its contents 9303 * AutofillId oldId = reusableView.getAutofillId(); 9304 * CharSequence oldText = reusableView.getText(); 9305 * parentView.removeView(reusableView); 9306 * AutofillId newId = afm.getNextAutofillId(); 9307 * reusableView.setText("New I am"); 9308 * reusableView.setAutofillId(newId); 9309 * parentView.addView(reusableView); 9310 * 9311 * // Later, swap the old content back in 9312 * parentView.removeView(reusableView); 9313 * reusableView.setAutofillId(oldId); 9314 * reusableView.setText(oldText); 9315 * parentView.addView(reusableView); 9316 * </pre> 9317 * 9318 * <p>NOTE: If this view is a descendant of an {@link android.widget.AdapterView}, the system 9319 * may reset its autofill id when this view is recycled. If the autofill ids need to be stable, 9320 * they should be set again in 9321 * {@link android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)}. 9322 * 9323 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 9324 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 9325 * obtained through {@link #getAutofillId()}), or a new value obtained through 9326 * {@link AutofillManager#getNextAutofillId()}. 9327 * 9328 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 9329 * a window}. 9330 * 9331 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 9332 */ setAutofillId(@ullable AutofillId id)9333 public void setAutofillId(@Nullable AutofillId id) { 9334 // TODO(b/37566627): add unit / CTS test for all possible combinations below 9335 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9336 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 9337 } 9338 if (isAttachedToWindow()) { 9339 throw new IllegalStateException("Cannot set autofill id when view is attached"); 9340 } 9341 if (id != null && !id.isNonVirtual()) { 9342 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 9343 } 9344 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 9345 // Ignore reset because it was never explicitly set before. 9346 return; 9347 } 9348 mAutofillId = id; 9349 if (id != null) { 9350 mAutofillViewId = id.getViewId(); 9351 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9352 } else { 9353 mAutofillViewId = NO_ID; 9354 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9355 } 9356 } 9357 9358 /** 9359 * Forces a reset of the autofill ids of the subtree rooted at this view. Like calling 9360 * {@link #setAutofillId(AutofillId) setAutofillId(null)} for each view, but works even if the 9361 * views are attached to a window. 9362 * 9363 * <p>This is useful if the views are being recycled, since an autofill id should uniquely 9364 * identify a particular piece of content. 9365 * 9366 * @hide 9367 */ resetSubtreeAutofillIds()9368 public void resetSubtreeAutofillIds() { 9369 if (mAutofillViewId == NO_ID) { 9370 return; 9371 } 9372 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9373 Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9374 } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9375 Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9376 } 9377 mAutofillId = null; 9378 mAutofillViewId = NO_ID; 9379 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9380 } 9381 9382 /** 9383 * Describes the autofill type of this view, so an 9384 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 9385 * when autofilling the view. 9386 * 9387 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 9388 * support the Autofill Framework. 9389 * 9390 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 9391 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 9392 * 9393 * @see #onProvideAutofillStructure(ViewStructure, int) 9394 * @see #autofill(AutofillValue) 9395 */ getAutofillType()9396 public @AutofillType int getAutofillType() { 9397 return AUTOFILL_TYPE_NONE; 9398 } 9399 9400 /** 9401 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 9402 * to autofill the view with the user's data. 9403 * 9404 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 9405 * 9406 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 9407 * {@code null} if no hints were set. 9408 * 9409 * @attr ref android.R.styleable#View_autofillHints 9410 */ 9411 @ViewDebug.ExportedProperty() 9412 @InspectableProperty getAutofillHints()9413 @Nullable public String[] getAutofillHints() { 9414 return mAutofillHints; 9415 } 9416 9417 /** 9418 * @hide 9419 */ 9420 @TestApi isAutofilled()9421 public boolean isAutofilled() { 9422 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 9423 } 9424 9425 /** 9426 * @hide 9427 */ hideAutofillHighlight()9428 public boolean hideAutofillHighlight() { 9429 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 9430 } 9431 9432 /** 9433 * Gets the {@link View}'s current autofill value. 9434 * 9435 * <p>By default returns {@code null}, but subclasses should override it and return an 9436 * appropriate value to properly support the Autofill Framework. 9437 * 9438 * @see #onProvideAutofillStructure(ViewStructure, int) 9439 * @see #autofill(AutofillValue) 9440 */ 9441 @Nullable getAutofillValue()9442 public AutofillValue getAutofillValue() { 9443 return null; 9444 } 9445 9446 /** 9447 * Gets the mode for determining whether this view is important for autofill. 9448 * 9449 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 9450 * info about this mode. 9451 * 9452 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 9453 * {@link #setImportantForAutofill(int)}. 9454 * 9455 * @attr ref android.R.styleable#View_importantForAutofill 9456 */ 9457 @ViewDebug.ExportedProperty(mapping = { 9458 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 9459 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 9460 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 9461 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9462 to = "yesExcludeDescendants"), 9463 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9464 to = "noExcludeDescendants")}) 9465 @InspectableProperty(enumMapping = { 9466 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 9467 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 9468 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 9469 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9470 name = "yesExcludeDescendants"), 9471 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9472 name = "noExcludeDescendants"), 9473 }) getImportantForAutofill()9474 public @AutofillImportance int getImportantForAutofill() { 9475 return (mPrivateFlags3 9476 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 9477 } 9478 9479 /** 9480 * Sets the mode for determining whether this view is considered important for autofill. 9481 * 9482 * <p>The platform determines the importance for autofill automatically but you 9483 * can use this method to customize the behavior. For example: 9484 * 9485 * <ol> 9486 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 9487 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 9488 * <li>When both the view and its children are irrelevant for autofill (for example, the root 9489 * view of an activity containing a spreadhseet editor), it should be 9490 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9491 * <li>When the view content is relevant for autofill but its children aren't (for example, 9492 * a credit card expiration date represented by a custom view that overrides the proper 9493 * autofill methods and has 2 children representing the month and year), it should 9494 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 9495 * </ol> 9496 * 9497 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9498 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 9499 * children) will be always be considered not important; for example, when the user explicitly 9500 * makes an autofill request, all views are considered important. See 9501 * {@link #isImportantForAutofill()} for more details about how the View's importance for 9502 * autofill is used. 9503 * 9504 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 9505 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 9506 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9507 * 9508 * @attr ref android.R.styleable#View_importantForAutofill 9509 */ setImportantForAutofill(@utofillImportance int mode)9510 public void setImportantForAutofill(@AutofillImportance int mode) { 9511 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9512 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 9513 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9514 } 9515 9516 /** 9517 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 9518 * associated with this view is considered important for autofill purposes. 9519 * 9520 * <p>Generally speaking, a view is important for autofill if: 9521 * <ol> 9522 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 9523 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 9524 * determine how other views can be autofilled. 9525 * <ol> 9526 * 9527 * <p>For example, view containers should typically return {@code false} for performance reasons 9528 * (since the important info is provided by their children), but if its properties have relevant 9529 * information (for example, a resource id called {@code credentials}, it should return 9530 * {@code true}. On the other hand, views representing labels or editable fields should 9531 * typically return {@code true}, but in some cases they could return {@code false} 9532 * (for example, if they're part of a "Captcha" mechanism). 9533 * 9534 * <p>The value returned by this method depends on the value returned by 9535 * {@link #getImportantForAutofill()}: 9536 * 9537 * <ol> 9538 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 9539 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 9540 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9541 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 9542 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 9543 * that can return {@code true} in some cases (like a container with a resource id), 9544 * but {@code false} in most. 9545 * <li>otherwise, it returns {@code false}. 9546 * </ol> 9547 * 9548 * <p>When a view is considered important for autofill: 9549 * <ul> 9550 * <li>The view might automatically trigger an autofill request when focused on. 9551 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 9552 * request. 9553 * </ul> 9554 * 9555 * <p>On the other hand, when a view is considered not important for autofill: 9556 * <ul> 9557 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 9558 * request through {@link AutofillManager#requestAutofill(View)}. 9559 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 9560 * autofill request, unless the request has the 9561 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9562 * </ul> 9563 * 9564 * @return whether the view is considered important for autofill. 9565 * 9566 * @see #setImportantForAutofill(int) 9567 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9568 * @see #IMPORTANT_FOR_AUTOFILL_YES 9569 * @see #IMPORTANT_FOR_AUTOFILL_NO 9570 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9571 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9572 * @see AutofillManager#requestAutofill(View) 9573 */ isImportantForAutofill()9574 public final boolean isImportantForAutofill() { 9575 // Check parent mode to ensure we're not hidden. 9576 ViewParent parent = mParent; 9577 while (parent instanceof View) { 9578 final int parentImportance = ((View) parent).getImportantForAutofill(); 9579 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9580 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9581 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9582 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9583 + "because parent " + parent + "'s importance is " + parentImportance); 9584 } 9585 return false; 9586 } 9587 parent = parent.getParent(); 9588 } 9589 9590 final int importance = getImportantForAutofill(); 9591 9592 // First, check the explicit states. 9593 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9594 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9595 return true; 9596 } 9597 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9598 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9599 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9600 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9601 + "because its importance is " + importance); 9602 } 9603 return false; 9604 } 9605 9606 // Then use some heuristics to handle AUTO. 9607 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9608 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9609 + this); 9610 return false; 9611 } 9612 9613 // Always include views that have an explicit resource id. 9614 final int id = mID; 9615 if (id != NO_ID && !isViewIdGenerated(id)) { 9616 final Resources res = getResources(); 9617 String entry = null; 9618 String pkg = null; 9619 try { 9620 entry = res.getResourceEntryName(id); 9621 pkg = res.getResourcePackageName(id); 9622 } catch (Resources.NotFoundException e) { 9623 // ignore 9624 } 9625 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9626 return true; 9627 } 9628 } 9629 9630 // If the app developer explicitly set hints for it, it's important. 9631 if (getAutofillHints() != null) { 9632 return true; 9633 } 9634 9635 // Otherwise, assume it's not important... 9636 return false; 9637 } 9638 9639 /** 9640 * Gets the mode for determining whether this view is important for content capture. 9641 * 9642 * <p>See {@link #setImportantForContentCapture(int)} and 9643 * {@link #isImportantForContentCapture()} for more info about this mode. 9644 * 9645 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 9646 * {@link #setImportantForContentCapture(int)}. 9647 * 9648 * @attr ref android.R.styleable#View_importantForContentCapture 9649 */ 9650 @ViewDebug.ExportedProperty(mapping = { 9651 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 9652 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 9653 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 9654 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9655 to = "yesExcludeDescendants"), 9656 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9657 to = "noExcludeDescendants")}) 9658 @InspectableProperty(enumMapping = { 9659 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 9660 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 9661 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 9662 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9663 name = "yesExcludeDescendants"), 9664 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9665 name = "noExcludeDescendants"), 9666 }) getImportantForContentCapture()9667 public @ContentCaptureImportance int getImportantForContentCapture() { 9668 // NOTE: the important for content capture values were the first flags added and are set in 9669 // the rightmost position, so we don't need to shift them 9670 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9671 } 9672 9673 /** 9674 * Sets the mode for determining whether this view is considered important for content capture. 9675 * 9676 * <p>The platform determines the importance for autofill automatically but you 9677 * can use this method to customize the behavior. Typically, a view that provides text should 9678 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 9679 * 9680 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 9681 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 9682 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 9683 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 9684 * 9685 * @attr ref android.R.styleable#View_importantForContentCapture 9686 */ setImportantForContentCapture(@ontentCaptureImportance int mode)9687 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 9688 // Reset first 9689 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9690 // Then set again 9691 // NOTE: the important for content capture values were the first flags added and are set in 9692 // the rightmost position, so we don't need to shift them 9693 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 9694 } 9695 9696 /** 9697 * Hints the Android System whether this view is considered important for content capture, based 9698 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 9699 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 9700 * 9701 * <p>See {@link ContentCaptureManager} for more info about content capture. 9702 * 9703 * @return whether the view is considered important for content capture. 9704 * 9705 * @see #setImportantForContentCapture(int) 9706 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 9707 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 9708 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 9709 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9710 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9711 */ isImportantForContentCapture()9712 public final boolean isImportantForContentCapture() { 9713 boolean isImportant; 9714 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 9715 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 9716 return isImportant; 9717 } 9718 9719 isImportant = calculateIsImportantForContentCapture(); 9720 9721 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9722 if (isImportant) { 9723 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9724 } 9725 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 9726 return isImportant; 9727 } 9728 9729 /** 9730 * Calculates whether the flag is important for content capture so it can be used by 9731 * {@link #isImportantForContentCapture()} while the tree is traversed. 9732 */ calculateIsImportantForContentCapture()9733 private boolean calculateIsImportantForContentCapture() { 9734 // Check parent mode to ensure we're important 9735 ViewParent parent = mParent; 9736 while (parent instanceof View) { 9737 final int parentImportance = ((View) parent).getImportantForContentCapture(); 9738 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9739 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 9740 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9741 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 9742 + "content capture because parent " + parent + "'s importance is " 9743 + parentImportance); 9744 } 9745 return false; 9746 } 9747 parent = parent.getParent(); 9748 } 9749 9750 final int importance = getImportantForContentCapture(); 9751 9752 // First, check the explicit states. 9753 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9754 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 9755 return true; 9756 } 9757 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9758 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 9759 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9760 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 9761 + "capture because its importance is " + importance); 9762 } 9763 return false; 9764 } 9765 9766 // Then use some heuristics to handle AUTO. 9767 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 9768 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 9769 + " on view " + this); 9770 return false; 9771 } 9772 9773 // View group is important if at least one children also is 9774 if (this instanceof ViewGroup) { 9775 final ViewGroup group = (ViewGroup) this; 9776 for (int i = 0; i < group.getChildCount(); i++) { 9777 final View child = group.getChildAt(i); 9778 if (child.isImportantForContentCapture()) { 9779 return true; 9780 } 9781 } 9782 } 9783 9784 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 9785 if (getAutofillHints() != null) { 9786 return true; 9787 } 9788 9789 // Otherwise, assume it's not important... 9790 return false; 9791 } 9792 9793 /** 9794 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 9795 * added, based on whether it's laid out and visible, and without knowing if the parent removed 9796 * it from the view hierarchy. 9797 * 9798 * <p>This method is called from many places (visibility changed, view laid out, view attached 9799 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 9800 * described below: 9801 * 9802 * <ol> 9803 * <li>It should only be called when content capture is enabled for the view. 9804 * <li>It must call viewAppeared() before viewDisappeared() 9805 * <li>viewAppearead() can only be called when the view is visible and laidout 9806 * <li>It should not call the same event twice. 9807 * </ol> 9808 */ notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared)9809 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 9810 AttachInfo ai = mAttachInfo; 9811 // Skip it while the view is being laid out for the first time 9812 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 9813 9814 // First check if context has client, so it saves a service lookup when it doesn't 9815 if (mContext.getContentCaptureOptions() == null) return; 9816 9817 if (appeared) { 9818 // The appeared event stops sending to AiAi. 9819 // 1. The view is hidden. 9820 // 2. The same event was sent. 9821 // 3. The view is not laid out, and it will be laid out in the future. 9822 // Some recycled views cached its layout and a relayout is unnecessary. In this case, 9823 // system still needs to notify content capture the view appeared. When a view is 9824 // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED. 9825 final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() 9826 && getVisibility() == VISIBLE 9827 && !isLayoutRequested(); 9828 if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() 9829 || !(isLaidOut() || isRecycledWithoutRelayout)) { 9830 if (DEBUG_CONTENT_CAPTURE) { 9831 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 9832 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9833 + ", visible=" + (getVisibility() == VISIBLE) 9834 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 9835 + ", alreadyNotifiedDisappeared=" 9836 + getNotifiedContentCaptureDisappeared()); 9837 } 9838 return; 9839 } 9840 } else { 9841 if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { 9842 if (DEBUG_CONTENT_CAPTURE) { 9843 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 9844 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9845 + ", visible=" + (getVisibility() == VISIBLE) 9846 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 9847 + ", alreadyNotifiedDisappeared=" 9848 + getNotifiedContentCaptureDisappeared()); 9849 } 9850 return; 9851 } 9852 } 9853 9854 ContentCaptureSession session = getContentCaptureSession(); 9855 if (session == null) return; 9856 9857 // ... and finally at the view level 9858 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 9859 if (!isImportantForContentCapture()) return; 9860 9861 if (appeared) { 9862 setNotifiedContentCaptureAppeared(); 9863 9864 if (ai != null) { 9865 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9866 } else { 9867 if (DEBUG_CONTENT_CAPTURE) { 9868 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 9869 } 9870 } 9871 } else { 9872 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9873 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9874 9875 if (ai != null) { 9876 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9877 } else { 9878 if (DEBUG_CONTENT_CAPTURE) { 9879 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 9880 } 9881 } 9882 } 9883 } 9884 setNotifiedContentCaptureAppeared()9885 private void setNotifiedContentCaptureAppeared() { 9886 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9887 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9888 } 9889 9890 /** @hide */ getNotifiedContentCaptureAppeared()9891 protected boolean getNotifiedContentCaptureAppeared() { 9892 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 9893 } 9894 9895 getNotifiedContentCaptureDisappeared()9896 private boolean getNotifiedContentCaptureDisappeared() { 9897 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; 9898 } 9899 9900 /** 9901 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 9902 * 9903 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 9904 * the content capture events associated with this view or its view hierarchy (if it's a 9905 * {@link ViewGroup}). 9906 * 9907 * <p>For example, if your activity is associated with a web domain, first you would need to 9908 * set the context for the main DOM: 9909 * 9910 * <pre> 9911 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 9912 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 9913 * </pre> 9914 * 9915 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 9916 * 9917 * <pre> 9918 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 9919 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 9920 * iframeView.setContentCaptureSession(iframeSession); 9921 * </pre> 9922 * 9923 * @param contentCaptureSession a session created by 9924 * {@link ContentCaptureSession#createContentCaptureSession( 9925 * android.view.contentcapture.ContentCaptureContext)}. 9926 */ setContentCaptureSession(@ullable ContentCaptureSession contentCaptureSession)9927 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 9928 mContentCaptureSession = contentCaptureSession; 9929 } 9930 9931 /** 9932 * Gets the session used to notify content capture events. 9933 * 9934 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 9935 * inherited by ancestors, default session or {@code null} if content capture is disabled for 9936 * this view. 9937 */ 9938 @Nullable getContentCaptureSession()9939 public final ContentCaptureSession getContentCaptureSession() { 9940 if (mContentCaptureSessionCached) { 9941 return mContentCaptureSession; 9942 } 9943 9944 mContentCaptureSession = getAndCacheContentCaptureSession(); 9945 mContentCaptureSessionCached = true; 9946 return mContentCaptureSession; 9947 } 9948 9949 @Nullable getAndCacheContentCaptureSession()9950 private ContentCaptureSession getAndCacheContentCaptureSession() { 9951 // First try the session explicitly set by setContentCaptureSession() 9952 if (mContentCaptureSession != null) { 9953 return mContentCaptureSession; 9954 } 9955 9956 // Then the session explicitly set in an ancestor 9957 ContentCaptureSession session = null; 9958 if (mParent instanceof View) { 9959 session = ((View) mParent).getContentCaptureSession(); 9960 } 9961 9962 // Finally, if no session was explicitly set, use the context's default session. 9963 if (session == null) { 9964 final ContentCaptureManager ccm = mContext 9965 .getSystemService(ContentCaptureManager.class); 9966 return ccm == null ? null : ccm.getMainContentCaptureSession(); 9967 } 9968 return session; 9969 } 9970 9971 @Nullable getAutofillManager()9972 private AutofillManager getAutofillManager() { 9973 return mContext.getSystemService(AutofillManager.class); 9974 } 9975 isAutofillable()9976 private boolean isAutofillable() { 9977 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 9978 9979 if (!isImportantForAutofill()) { 9980 // View is not important for "regular" autofill, so we must check if Augmented Autofill 9981 // is enabled for the activity 9982 final AutofillOptions options = mContext.getAutofillOptions(); 9983 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 9984 return false; 9985 } 9986 final AutofillManager afm = getAutofillManager(); 9987 if (afm == null) return false; 9988 afm.notifyViewEnteredForAugmentedAutofill(this); 9989 } 9990 9991 return getAutofillViewId() > LAST_APP_AUTOFILL_ID; 9992 } 9993 9994 /** @hide */ canNotifyAutofillEnterExitEvent()9995 public boolean canNotifyAutofillEnterExitEvent() { 9996 return isAutofillable() && isAttachedToWindow(); 9997 } 9998 populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutofill)9999 private void populateVirtualStructure(ViewStructure structure, 10000 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 10001 boolean forAutofill) { 10002 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 10003 null, null, info.getViewIdResourceName()); 10004 Rect rect = structure.getTempRect(); 10005 info.getBoundsInParent(rect); 10006 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 10007 structure.setVisibility(VISIBLE); 10008 structure.setEnabled(info.isEnabled()); 10009 if (info.isClickable()) { 10010 structure.setClickable(true); 10011 } 10012 if (info.isFocusable()) { 10013 structure.setFocusable(true); 10014 } 10015 if (info.isFocused()) { 10016 structure.setFocused(true); 10017 } 10018 if (info.isAccessibilityFocused()) { 10019 structure.setAccessibilityFocused(true); 10020 } 10021 if (info.isSelected()) { 10022 structure.setSelected(true); 10023 } 10024 if (info.isLongClickable()) { 10025 structure.setLongClickable(true); 10026 } 10027 if (info.isCheckable()) { 10028 structure.setCheckable(true); 10029 if (info.isChecked()) { 10030 structure.setChecked(true); 10031 } 10032 } 10033 if (info.isContextClickable()) { 10034 structure.setContextClickable(true); 10035 } 10036 if (forAutofill) { 10037 structure.setAutofillId(new AutofillId(getAutofillId(), 10038 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 10039 } 10040 CharSequence cname = info.getClassName(); 10041 structure.setClassName(cname != null ? cname.toString() : null); 10042 structure.setContentDescription(info.getContentDescription()); 10043 if (forAutofill) { 10044 final int maxTextLength = info.getMaxTextLength(); 10045 if (maxTextLength != -1) { 10046 structure.setMaxTextLength(maxTextLength); 10047 } 10048 structure.setHint(info.getHintText()); 10049 } 10050 CharSequence text = info.getText(); 10051 boolean hasText = text != null || info.getError() != null; 10052 if (hasText) { 10053 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 10054 } 10055 if (forAutofill) { 10056 if (info.isEditable()) { 10057 structure.setDataIsSensitive(true); 10058 if (hasText) { 10059 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 10060 structure.setAutofillValue(AutofillValue.forText(text)); 10061 } 10062 int inputType = info.getInputType(); 10063 if (inputType == 0 && info.isPassword()) { 10064 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 10065 } 10066 structure.setInputType(inputType); 10067 } else { 10068 structure.setDataIsSensitive(false); 10069 } 10070 } 10071 final int NCHILDREN = info.getChildCount(); 10072 if (NCHILDREN > 0) { 10073 structure.setChildCount(NCHILDREN); 10074 for (int i=0; i<NCHILDREN; i++) { 10075 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 10076 == AccessibilityNodeProvider.HOST_VIEW_ID) { 10077 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 10078 continue; 10079 } 10080 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 10081 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 10082 if (cinfo != null) { 10083 ViewStructure child = structure.newChild(i); 10084 populateVirtualStructure(child, provider, cinfo, forAutofill); 10085 cinfo.recycle(); 10086 } 10087 } 10088 } 10089 } 10090 10091 /** 10092 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 10093 * implementation calls {@link #onProvideStructure} and 10094 * {@link #onProvideVirtualStructure}. 10095 */ dispatchProvideStructure(ViewStructure structure)10096 public void dispatchProvideStructure(ViewStructure structure) { 10097 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 10098 } 10099 10100 /** 10101 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 10102 * when an Assist structure is being created as part of an autofill request. 10103 * 10104 * <p>The default implementation does the following: 10105 * <ul> 10106 * <li>Sets the {@link AutofillId} in the structure. 10107 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 10108 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 10109 * </ul> 10110 * 10111 * <p>Typically, this method should only be overridden by subclasses that provide a view 10112 * hierarchy (such as {@link ViewGroup}) - other classes should override 10113 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 10114 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 10115 * 10116 * <p>When overridden, it must: 10117 * 10118 * <ul> 10119 * <li>Either call 10120 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 10121 * set the {@link AutofillId} in the structure (for example, by calling 10122 * {@code structure.setAutofillId(getAutofillId())}). 10123 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 10124 * set, all views in the structure should be considered important for autofill, 10125 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 10126 * respect this flag to provide a better user experience - this flag is typically used 10127 * when an user explicitly requested autofill. If the flag is not set, 10128 * then only views marked as important for autofill should be included in the 10129 * structure - skipping non-important views optimizes the overall autofill performance. 10130 * </ul> 10131 * 10132 * @param structure fill in with structured view data for autofill purposes. 10133 * @param flags optional flags. 10134 * 10135 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 10136 */ dispatchProvideAutofillStructure(@onNull ViewStructure structure, @AutofillFlags int flags)10137 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 10138 @AutofillFlags int flags) { 10139 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 10140 } 10141 dispatchProvideStructure(@onNull ViewStructure structure, @ViewStructureType int viewFor, @AutofillFlags int flags)10142 private void dispatchProvideStructure(@NonNull ViewStructure structure, 10143 @ViewStructureType int viewFor, @AutofillFlags int flags) { 10144 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 10145 structure.setAutofillId(getAutofillId()); 10146 onProvideAutofillStructure(structure, flags); 10147 onProvideAutofillVirtualStructure(structure, flags); 10148 } else if (!isAssistBlocked()) { 10149 onProvideStructure(structure); 10150 onProvideVirtualStructure(structure); 10151 } else { 10152 structure.setClassName(getAccessibilityClassName().toString()); 10153 structure.setAssistBlocked(true); 10154 } 10155 } 10156 10157 /** 10158 * Dispatches the initial content capture events for a view structure. 10159 * 10160 * @hide 10161 */ dispatchInitialProvideContentCaptureStructure()10162 public void dispatchInitialProvideContentCaptureStructure() { 10163 AttachInfo ai = mAttachInfo; 10164 if (ai == null) { 10165 Log.w(CONTENT_CAPTURE_LOG_TAG, 10166 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 10167 return; 10168 } 10169 ContentCaptureManager ccm = ai.mContentCaptureManager; 10170 if (ccm == null) { 10171 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 10172 + "no ContentCaptureManager for " + this); 10173 return; 10174 } 10175 10176 // We must set it before checkign if the view itself is important, because it might 10177 // initially not be (for example, if it's empty), although that might change later (for 10178 // example, if important views are added) 10179 ai.mReadyForContentCaptureUpdates = true; 10180 10181 if (!isImportantForContentCapture()) { 10182 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10183 Log.d(CONTENT_CAPTURE_LOG_TAG, 10184 "dispatchProvideContentCaptureStructure(): decorView is not important"); 10185 } 10186 return; 10187 } 10188 10189 ai.mContentCaptureManager = ccm; 10190 10191 ContentCaptureSession session = getContentCaptureSession(); 10192 if (session == null) { 10193 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10194 Log.d(CONTENT_CAPTURE_LOG_TAG, 10195 "dispatchProvideContentCaptureStructure(): no session for " + this); 10196 } 10197 return; 10198 } 10199 10200 session.internalNotifyViewTreeEvent(/* started= */ true); 10201 try { 10202 dispatchProvideContentCaptureStructure(); 10203 } finally { 10204 session.internalNotifyViewTreeEvent(/* started= */ false); 10205 } 10206 } 10207 10208 /** @hide */ dispatchProvideContentCaptureStructure()10209 void dispatchProvideContentCaptureStructure() { 10210 ContentCaptureSession session = getContentCaptureSession(); 10211 if (session != null) { 10212 ViewStructure structure = session.newViewStructure(this); 10213 onProvideContentCaptureStructure(structure, /* flags= */ 0); 10214 setNotifiedContentCaptureAppeared(); 10215 session.notifyViewAppeared(structure); 10216 } 10217 } 10218 10219 /** 10220 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 10221 * 10222 * Note: Called from the default {@link AccessibilityDelegate}. 10223 * 10224 * @hide 10225 */ onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)10226 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 10227 if (mAttachInfo == null) { 10228 return; 10229 } 10230 10231 Rect bounds = mAttachInfo.mTmpInvalRect; 10232 10233 getDrawingRect(bounds); 10234 info.setBoundsInParent(bounds); 10235 10236 getBoundsOnScreen(bounds, true); 10237 info.setBoundsInScreen(bounds); 10238 10239 ViewParent parent = getParentForAccessibility(); 10240 if (parent instanceof View) { 10241 info.setParent((View) parent); 10242 } 10243 10244 if (mID != View.NO_ID) { 10245 View rootView = getRootView(); 10246 if (rootView == null) { 10247 rootView = this; 10248 } 10249 10250 View label = rootView.findLabelForView(this, mID); 10251 if (label != null) { 10252 info.setLabeledBy(label); 10253 } 10254 10255 if ((mAttachInfo.mAccessibilityFetchFlags 10256 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 10257 && Resources.resourceHasPackage(mID)) { 10258 try { 10259 String viewId = getResources().getResourceName(mID); 10260 info.setViewIdResourceName(viewId); 10261 } catch (Resources.NotFoundException nfe) { 10262 /* ignore */ 10263 } 10264 } 10265 } 10266 10267 if (mLabelForId != View.NO_ID) { 10268 View rootView = getRootView(); 10269 if (rootView == null) { 10270 rootView = this; 10271 } 10272 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 10273 if (labeled != null) { 10274 info.setLabelFor(labeled); 10275 } 10276 } 10277 10278 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 10279 View rootView = getRootView(); 10280 if (rootView == null) { 10281 rootView = this; 10282 } 10283 View next = rootView.findViewInsideOutShouldExist(this, 10284 mAccessibilityTraversalBeforeId); 10285 if (next != null && next.includeForAccessibility()) { 10286 info.setTraversalBefore(next); 10287 } 10288 } 10289 10290 if (mAccessibilityTraversalAfterId != View.NO_ID) { 10291 View rootView = getRootView(); 10292 if (rootView == null) { 10293 rootView = this; 10294 } 10295 View next = rootView.findViewInsideOutShouldExist(this, 10296 mAccessibilityTraversalAfterId); 10297 if (next != null && next.includeForAccessibility()) { 10298 info.setTraversalAfter(next); 10299 } 10300 } 10301 10302 info.setVisibleToUser(isVisibleToUser()); 10303 10304 info.setImportantForAccessibility(isImportantForAccessibility()); 10305 info.setPackageName(mContext.getPackageName()); 10306 info.setClassName(getAccessibilityClassName()); 10307 info.setStateDescription(getStateDescription()); 10308 info.setContentDescription(getContentDescription()); 10309 10310 info.setEnabled(isEnabled()); 10311 info.setClickable(isClickable()); 10312 info.setFocusable(isFocusable()); 10313 info.setScreenReaderFocusable(isScreenReaderFocusable()); 10314 info.setFocused(isFocused()); 10315 info.setAccessibilityFocused(isAccessibilityFocused()); 10316 info.setSelected(isSelected()); 10317 info.setLongClickable(isLongClickable()); 10318 info.setContextClickable(isContextClickable()); 10319 info.setLiveRegion(getAccessibilityLiveRegion()); 10320 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 10321 info.setTooltipText(mTooltipInfo.mTooltipText); 10322 info.addAction((mTooltipInfo.mTooltipPopup == null) 10323 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 10324 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 10325 } 10326 10327 // TODO: These make sense only if we are in an AdapterView but all 10328 // views can be selected. Maybe from accessibility perspective 10329 // we should report as selectable view in an AdapterView. 10330 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 10331 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 10332 10333 if (isFocusable()) { 10334 if (isFocused()) { 10335 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 10336 } else { 10337 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 10338 } 10339 } 10340 10341 if (!isAccessibilityFocused()) { 10342 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 10343 } else { 10344 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 10345 } 10346 10347 if (isClickable() && isEnabled()) { 10348 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 10349 } 10350 10351 if (isLongClickable() && isEnabled()) { 10352 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 10353 } 10354 10355 if (isContextClickable() && isEnabled()) { 10356 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 10357 } 10358 10359 CharSequence text = getIterableTextForAccessibility(); 10360 if (text != null && text.length() > 0) { 10361 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 10362 10363 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 10364 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 10365 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 10366 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 10367 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 10368 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 10369 } 10370 10371 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 10372 populateAccessibilityNodeInfoDrawingOrderInParent(info); 10373 info.setPaneTitle(mAccessibilityPaneTitle); 10374 info.setHeading(isAccessibilityHeading()); 10375 10376 if (mTouchDelegate != null) { 10377 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 10378 } 10379 } 10380 10381 /** 10382 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 10383 * additional data. 10384 * <p> 10385 * This method only needs overloading if the node is marked as having extra data available. 10386 * </p> 10387 * 10388 * @param info The info to which to add the extra data. Never {@code null}. 10389 * @param extraDataKey A key specifying the type of extra data to add to the info. The 10390 * extra data should be added to the {@link Bundle} returned by 10391 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 10392 * {@code null}. 10393 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 10394 * {@code null} if the service provided no arguments. 10395 * 10396 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 10397 */ addExtraDataToAccessibilityNodeInfo( @onNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)10398 public void addExtraDataToAccessibilityNodeInfo( 10399 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 10400 @Nullable Bundle arguments) { 10401 } 10402 10403 /** 10404 * Determine the order in which this view will be drawn relative to its siblings for a11y 10405 * 10406 * @param info The info whose drawing order should be populated 10407 */ populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info)10408 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 10409 /* 10410 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 10411 * drawing order may not be well-defined, and some Views with custom drawing order may 10412 * not be initialized sufficiently to respond properly getChildDrawingOrder. 10413 */ 10414 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 10415 info.setDrawingOrder(0); 10416 return; 10417 } 10418 int drawingOrderInParent = 1; 10419 // Iterate up the hierarchy if parents are not important for a11y 10420 View viewAtDrawingLevel = this; 10421 final ViewParent parent = getParentForAccessibility(); 10422 while (viewAtDrawingLevel != parent) { 10423 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 10424 if (!(currentParent instanceof ViewGroup)) { 10425 // Should only happen for the Decor 10426 drawingOrderInParent = 0; 10427 break; 10428 } else { 10429 final ViewGroup parentGroup = (ViewGroup) currentParent; 10430 final int childCount = parentGroup.getChildCount(); 10431 if (childCount > 1) { 10432 List<View> preorderedList = parentGroup.buildOrderedChildList(); 10433 if (preorderedList != null) { 10434 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 10435 for (int i = 0; i < childDrawIndex; i++) { 10436 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 10437 } 10438 preorderedList.clear(); 10439 } else { 10440 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 10441 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 10442 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 10443 .getChildDrawingOrder(childCount, childIndex) : childIndex; 10444 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 10445 if (childDrawIndex != 0) { 10446 for (int i = 0; i < numChildrenToIterate; i++) { 10447 final int otherDrawIndex = (customOrder ? 10448 parentGroup.getChildDrawingOrder(childCount, i) : i); 10449 if (otherDrawIndex < childDrawIndex) { 10450 drawingOrderInParent += 10451 numViewsForAccessibility(parentGroup.getChildAt(i)); 10452 } 10453 } 10454 } 10455 } 10456 } 10457 } 10458 viewAtDrawingLevel = (View) currentParent; 10459 } 10460 info.setDrawingOrder(drawingOrderInParent); 10461 } 10462 numViewsForAccessibility(View view)10463 private static int numViewsForAccessibility(View view) { 10464 if (view != null) { 10465 if (view.includeForAccessibility()) { 10466 return 1; 10467 } else if (view instanceof ViewGroup) { 10468 return ((ViewGroup) view).getNumChildrenForAccessibility(); 10469 } 10470 } 10471 return 0; 10472 } 10473 findLabelForView(View view, int labeledId)10474 private View findLabelForView(View view, int labeledId) { 10475 if (mMatchLabelForPredicate == null) { 10476 mMatchLabelForPredicate = new MatchLabelForPredicate(); 10477 } 10478 mMatchLabelForPredicate.mLabeledId = labeledId; 10479 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 10480 } 10481 10482 /** 10483 * Computes whether this virtual autofill view is visible to the user. 10484 * 10485 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 10486 * view must override it. 10487 * 10488 * @return Whether the view is visible on the screen. 10489 */ isVisibleToUserForAutofill(int virtualId)10490 public boolean isVisibleToUserForAutofill(int virtualId) { 10491 if (mContext.isAutofillCompatibilityEnabled()) { 10492 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10493 if (provider != null) { 10494 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 10495 if (node != null) { 10496 return node.isVisibleToUser(); 10497 } 10498 // if node is null, assume it's not visible anymore 10499 } else { 10500 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 10501 } 10502 return false; 10503 } 10504 return true; 10505 } 10506 10507 /** 10508 * Computes whether this view is visible to the user. Such a view is 10509 * attached, visible, all its predecessors are visible, it is not clipped 10510 * entirely by its predecessors, and has an alpha greater than zero. 10511 * 10512 * @return Whether the view is visible on the screen. 10513 * 10514 * @hide 10515 */ 10516 @UnsupportedAppUsage isVisibleToUser()10517 public boolean isVisibleToUser() { 10518 return isVisibleToUser(null); 10519 } 10520 10521 /** 10522 * Computes whether the given portion of this view is visible to the user. 10523 * Such a view is attached, visible, all its predecessors are visible, 10524 * has an alpha greater than zero, and the specified portion is not 10525 * clipped entirely by its predecessors. 10526 * 10527 * @param boundInView the portion of the view to test; coordinates should be relative; may be 10528 * <code>null</code>, and the entire view will be tested in this case. 10529 * When <code>true</code> is returned by the function, the actual visible 10530 * region will be stored in this parameter; that is, if boundInView is fully 10531 * contained within the view, no modification will be made, otherwise regions 10532 * outside of the visible area of the view will be clipped. 10533 * 10534 * @return Whether the specified portion of the view is visible on the screen. 10535 * 10536 * @hide 10537 */ 10538 @UnsupportedAppUsage(trackingBug = 171933273) isVisibleToUser(Rect boundInView)10539 protected boolean isVisibleToUser(Rect boundInView) { 10540 if (mAttachInfo != null) { 10541 // Attached to invisible window means this view is not visible. 10542 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 10543 return false; 10544 } 10545 // An invisible predecessor or one with alpha zero means 10546 // that this view is not visible to the user. 10547 Object current = this; 10548 while (current instanceof View) { 10549 View view = (View) current; 10550 // We have attach info so this view is attached and there is no 10551 // need to check whether we reach to ViewRootImpl on the way up. 10552 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 10553 view.getVisibility() != VISIBLE) { 10554 return false; 10555 } 10556 current = view.mParent; 10557 } 10558 // Check if the view is entirely covered by its predecessors. 10559 Rect visibleRect = mAttachInfo.mTmpInvalRect; 10560 Point offset = mAttachInfo.mPoint; 10561 if (!getGlobalVisibleRect(visibleRect, offset)) { 10562 return false; 10563 } 10564 // Check if the visible portion intersects the rectangle of interest. 10565 if (boundInView != null) { 10566 visibleRect.offset(-offset.x, -offset.y); 10567 return boundInView.intersect(visibleRect); 10568 } 10569 return true; 10570 } 10571 return false; 10572 } 10573 10574 /** 10575 * Returns the delegate for implementing accessibility support via 10576 * composition. For more details see {@link AccessibilityDelegate}. 10577 * 10578 * @return The delegate, or null if none set. 10579 */ getAccessibilityDelegate()10580 public AccessibilityDelegate getAccessibilityDelegate() { 10581 return mAccessibilityDelegate; 10582 } 10583 10584 /** 10585 * Sets a delegate for implementing accessibility support via composition 10586 * (as opposed to inheritance). For more details, see 10587 * {@link AccessibilityDelegate}. 10588 * <p> 10589 * <strong>Note:</strong> On platform versions prior to 10590 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 10591 * views in the {@code android.widget.*} package are called <i>before</i> 10592 * host methods. This prevents certain properties such as class name from 10593 * being modified by overriding 10594 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 10595 * as any changes will be overwritten by the host class. 10596 * <p> 10597 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 10598 * methods are called <i>after</i> host methods, which all properties to be 10599 * modified without being overwritten by the host class. 10600 * 10601 * @param delegate the object to which accessibility method calls should be 10602 * delegated 10603 * @see AccessibilityDelegate 10604 */ setAccessibilityDelegate(@ullable AccessibilityDelegate delegate)10605 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 10606 mAccessibilityDelegate = delegate; 10607 } 10608 10609 /** 10610 * Gets the provider for managing a virtual view hierarchy rooted at this View 10611 * and reported to {@link android.accessibilityservice.AccessibilityService}s 10612 * that explore the window content. 10613 * <p> 10614 * If this method returns an instance, this instance is responsible for managing 10615 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 10616 * View including the one representing the View itself. Similarly the returned 10617 * instance is responsible for performing accessibility actions on any virtual 10618 * view or the root view itself. 10619 * </p> 10620 * <p> 10621 * If an {@link AccessibilityDelegate} has been specified via calling 10622 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10623 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 10624 * is responsible for handling this call. 10625 * </p> 10626 * 10627 * @return The provider. 10628 * 10629 * @see AccessibilityNodeProvider 10630 */ getAccessibilityNodeProvider()10631 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 10632 if (mAccessibilityDelegate != null) { 10633 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 10634 } else { 10635 return null; 10636 } 10637 } 10638 10639 /** 10640 * Gets the unique identifier of this view on the screen for accessibility purposes. 10641 * 10642 * @return The view accessibility id. 10643 * 10644 * @hide 10645 */ 10646 @UnsupportedAppUsage getAccessibilityViewId()10647 public int getAccessibilityViewId() { 10648 if (mAccessibilityViewId == NO_ID) { 10649 mAccessibilityViewId = sNextAccessibilityViewId++; 10650 } 10651 return mAccessibilityViewId; 10652 } 10653 10654 /** 10655 * Gets the unique identifier of this view on the screen for autofill purposes. 10656 * 10657 * @return The view autofill id. 10658 * 10659 * @hide 10660 */ getAutofillViewId()10661 public int getAutofillViewId() { 10662 if (mAutofillViewId == NO_ID) { 10663 mAutofillViewId = mContext.getNextAutofillId(); 10664 } 10665 return mAutofillViewId; 10666 } 10667 10668 /** 10669 * Gets the unique identifier of the window in which this View resides. 10670 * 10671 * @return The window accessibility id. 10672 * 10673 * @hide 10674 */ getAccessibilityWindowId()10675 public int getAccessibilityWindowId() { 10676 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 10677 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 10678 } 10679 10680 /** 10681 * Returns the {@link View}'s state description. 10682 * <p> 10683 * <strong>Note:</strong> Do not override this method, as it will have no 10684 * effect on the state description presented to accessibility services. 10685 * You must call {@link #setStateDescription(CharSequence)} to modify the 10686 * state description. 10687 * 10688 * @return the state description 10689 * @see #setStateDescription(CharSequence) 10690 */ 10691 @ViewDebug.ExportedProperty(category = "accessibility") getStateDescription()10692 public final @Nullable CharSequence getStateDescription() { 10693 return mStateDescription; 10694 } 10695 10696 /** 10697 * Returns the {@link View}'s content description. 10698 * <p> 10699 * <strong>Note:</strong> Do not override this method, as it will have no 10700 * effect on the content description presented to accessibility services. 10701 * You must call {@link #setContentDescription(CharSequence)} to modify the 10702 * content description. 10703 * 10704 * @return the content description 10705 * @see #setContentDescription(CharSequence) 10706 * @attr ref android.R.styleable#View_contentDescription 10707 */ 10708 @ViewDebug.ExportedProperty(category = "accessibility") 10709 @InspectableProperty getContentDescription()10710 public CharSequence getContentDescription() { 10711 return mContentDescription; 10712 } 10713 10714 /** 10715 * Sets the {@link View}'s state description. 10716 * <p> 10717 * A state description briefly describes the states of the view and is primarily used 10718 * for accessibility support to determine how the states of a view should be presented to 10719 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 10720 * it is used for customized state description (for example, "wifi, connected, three bars"). 10721 * State description changes frequently while content description should change less often. 10722 * State description should be localized. For android widgets which have default state 10723 * descriptions, app developers can call this method to override the state descriptions. 10724 * Setting state description to null restores the default behavior. 10725 * 10726 * @param stateDescription The state description. 10727 * @see #getStateDescription() 10728 */ 10729 @RemotableViewMethod setStateDescription(@ullable CharSequence stateDescription)10730 public void setStateDescription(@Nullable CharSequence stateDescription) { 10731 if (mStateDescription == null) { 10732 if (stateDescription == null) { 10733 return; 10734 } 10735 } else if (mStateDescription.equals(stateDescription)) { 10736 return; 10737 } 10738 mStateDescription = stateDescription; 10739 if (!TextUtils.isEmpty(stateDescription) 10740 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10741 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10742 } 10743 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10744 AccessibilityEvent event = AccessibilityEvent.obtain(); 10745 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 10746 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 10747 sendAccessibilityEventUnchecked(event); 10748 } 10749 } 10750 10751 /** 10752 * Sets the {@link View}'s content description. 10753 * <p> 10754 * A content description briefly describes the view and is primarily used 10755 * for accessibility support to determine how a view should be presented to 10756 * the user. In the case of a view with no textual representation, such as 10757 * {@link android.widget.ImageButton}, a useful content description 10758 * explains what the view does. For example, an image button with a phone 10759 * icon that is used to place a call may use "Call" as its content 10760 * description. An image of a floppy disk that is used to save a file may 10761 * use "Save". 10762 * 10763 * @param contentDescription The content description. 10764 * @see #getContentDescription() 10765 * @attr ref android.R.styleable#View_contentDescription 10766 */ 10767 @RemotableViewMethod setContentDescription(CharSequence contentDescription)10768 public void setContentDescription(CharSequence contentDescription) { 10769 if (mContentDescription == null) { 10770 if (contentDescription == null) { 10771 return; 10772 } 10773 } else if (mContentDescription.equals(contentDescription)) { 10774 return; 10775 } 10776 mContentDescription = contentDescription; 10777 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 10778 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10779 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10780 notifySubtreeAccessibilityStateChangedIfNeeded(); 10781 } else { 10782 notifyViewAccessibilityStateChangedIfNeeded( 10783 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 10784 } 10785 } 10786 10787 /** 10788 * Sets the id of a view before which this one is visited in accessibility traversal. 10789 * A screen-reader must visit the content of this view before the content of the one 10790 * it precedes. For example, if view B is set to be before view A, then a screen-reader 10791 * will traverse the entire content of B before traversing the entire content of A, 10792 * regardles of what traversal strategy it is using. 10793 * <p> 10794 * Views that do not have specified before/after relationships are traversed in order 10795 * determined by the screen-reader. 10796 * </p> 10797 * <p> 10798 * Setting that this view is before a view that is not important for accessibility 10799 * or if this view is not important for accessibility will have no effect as the 10800 * screen-reader is not aware of unimportant views. 10801 * </p> 10802 * 10803 * @param beforeId The id of a view this one precedes in accessibility traversal. 10804 * 10805 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 10806 * 10807 * @see #setImportantForAccessibility(int) 10808 */ 10809 @RemotableViewMethod setAccessibilityTraversalBefore(@dRes int beforeId)10810 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 10811 if (mAccessibilityTraversalBeforeId == beforeId) { 10812 return; 10813 } 10814 mAccessibilityTraversalBeforeId = beforeId; 10815 notifyViewAccessibilityStateChangedIfNeeded( 10816 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10817 } 10818 10819 /** 10820 * Gets the id of a view before which this one is visited in accessibility traversal. 10821 * 10822 * @return The id of a view this one precedes in accessibility traversal if 10823 * specified, otherwise {@link #NO_ID}. 10824 * 10825 * @see #setAccessibilityTraversalBefore(int) 10826 */ 10827 @IdRes 10828 @InspectableProperty getAccessibilityTraversalBefore()10829 public int getAccessibilityTraversalBefore() { 10830 return mAccessibilityTraversalBeforeId; 10831 } 10832 10833 /** 10834 * Sets the id of a view after which this one is visited in accessibility traversal. 10835 * A screen-reader must visit the content of the other view before the content of this 10836 * one. For example, if view B is set to be after view A, then a screen-reader 10837 * will traverse the entire content of A before traversing the entire content of B, 10838 * regardles of what traversal strategy it is using. 10839 * <p> 10840 * Views that do not have specified before/after relationships are traversed in order 10841 * determined by the screen-reader. 10842 * </p> 10843 * <p> 10844 * Setting that this view is after a view that is not important for accessibility 10845 * or if this view is not important for accessibility will have no effect as the 10846 * screen-reader is not aware of unimportant views. 10847 * </p> 10848 * 10849 * @param afterId The id of a view this one succedees in accessibility traversal. 10850 * 10851 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 10852 * 10853 * @see #setImportantForAccessibility(int) 10854 */ 10855 @RemotableViewMethod setAccessibilityTraversalAfter(@dRes int afterId)10856 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 10857 if (mAccessibilityTraversalAfterId == afterId) { 10858 return; 10859 } 10860 mAccessibilityTraversalAfterId = afterId; 10861 notifyViewAccessibilityStateChangedIfNeeded( 10862 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10863 } 10864 10865 /** 10866 * Gets the id of a view after which this one is visited in accessibility traversal. 10867 * 10868 * @return The id of a view this one succeedes in accessibility traversal if 10869 * specified, otherwise {@link #NO_ID}. 10870 * 10871 * @see #setAccessibilityTraversalAfter(int) 10872 */ 10873 @IdRes 10874 @InspectableProperty getAccessibilityTraversalAfter()10875 public int getAccessibilityTraversalAfter() { 10876 return mAccessibilityTraversalAfterId; 10877 } 10878 10879 /** 10880 * Gets the id of a view for which this view serves as a label for 10881 * accessibility purposes. 10882 * 10883 * @return The labeled view id. 10884 */ 10885 @IdRes 10886 @ViewDebug.ExportedProperty(category = "accessibility") 10887 @InspectableProperty getLabelFor()10888 public int getLabelFor() { 10889 return mLabelForId; 10890 } 10891 10892 /** 10893 * Sets the id of a view for which this view serves as a label for 10894 * accessibility purposes. 10895 * 10896 * @param id The labeled view id. 10897 */ 10898 @RemotableViewMethod setLabelFor(@dRes int id)10899 public void setLabelFor(@IdRes int id) { 10900 if (mLabelForId == id) { 10901 return; 10902 } 10903 mLabelForId = id; 10904 if (mLabelForId != View.NO_ID 10905 && mID == View.NO_ID) { 10906 mID = generateViewId(); 10907 } 10908 notifyViewAccessibilityStateChangedIfNeeded( 10909 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10910 } 10911 10912 /** 10913 * Invoked whenever this view loses focus, either by losing window focus or by losing 10914 * focus within its window. This method can be used to clear any state tied to the 10915 * focus. For instance, if a button is held pressed with the trackball and the window 10916 * loses focus, this method can be used to cancel the press. 10917 * 10918 * Subclasses of View overriding this method should always call super.onFocusLost(). 10919 * 10920 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 10921 * @see #onWindowFocusChanged(boolean) 10922 * 10923 * @hide pending API council approval 10924 */ 10925 @CallSuper 10926 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onFocusLost()10927 protected void onFocusLost() { 10928 resetPressedState(); 10929 } 10930 resetPressedState()10931 private void resetPressedState() { 10932 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10933 return; 10934 } 10935 10936 if (isPressed()) { 10937 setPressed(false); 10938 10939 if (!mHasPerformedLongPress) { 10940 removeLongPressCallback(); 10941 } 10942 } 10943 } 10944 10945 /** 10946 * Returns true if this view has focus 10947 * 10948 * @return True if this view has focus, false otherwise. 10949 */ 10950 @ViewDebug.ExportedProperty(category = "focus") 10951 @InspectableProperty(hasAttributeId = false) isFocused()10952 public boolean isFocused() { 10953 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 10954 } 10955 10956 /** 10957 * Find the view in the hierarchy rooted at this view that currently has 10958 * focus. 10959 * 10960 * @return The view that currently has focus, or null if no focused view can 10961 * be found. 10962 */ findFocus()10963 public View findFocus() { 10964 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 10965 } 10966 10967 /** 10968 * Indicates whether this view is one of the set of scrollable containers in 10969 * its window. 10970 * 10971 * @return whether this view is one of the set of scrollable containers in 10972 * its window 10973 * 10974 * @attr ref android.R.styleable#View_isScrollContainer 10975 */ 10976 @InspectableProperty(name = "isScrollContainer") isScrollContainer()10977 public boolean isScrollContainer() { 10978 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 10979 } 10980 10981 /** 10982 * Change whether this view is one of the set of scrollable containers in 10983 * its window. This will be used to determine whether the window can 10984 * resize or must pan when a soft input area is open -- scrollable 10985 * containers allow the window to use resize mode since the container 10986 * will appropriately shrink. 10987 * 10988 * @attr ref android.R.styleable#View_isScrollContainer 10989 */ setScrollContainer(boolean isScrollContainer)10990 public void setScrollContainer(boolean isScrollContainer) { 10991 if (isScrollContainer) { 10992 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 10993 mAttachInfo.mScrollContainers.add(this); 10994 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 10995 } 10996 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 10997 } else { 10998 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 10999 mAttachInfo.mScrollContainers.remove(this); 11000 } 11001 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 11002 } 11003 } 11004 11005 /** 11006 * Returns the quality of the drawing cache. 11007 * 11008 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11009 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11010 * 11011 * @see #setDrawingCacheQuality(int) 11012 * @see #setDrawingCacheEnabled(boolean) 11013 * @see #isDrawingCacheEnabled() 11014 * 11015 * @attr ref android.R.styleable#View_drawingCacheQuality 11016 * 11017 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11018 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11019 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11020 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11021 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11022 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11023 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11024 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11025 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11026 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11027 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11028 * reports or unit testing the {@link PixelCopy} API is recommended. 11029 */ 11030 @Deprecated 11031 @DrawingCacheQuality 11032 @InspectableProperty(enumMapping = { 11033 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 11034 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 11035 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 11036 }) getDrawingCacheQuality()11037 public int getDrawingCacheQuality() { 11038 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 11039 } 11040 11041 /** 11042 * Set the drawing cache quality of this view. This value is used only when the 11043 * drawing cache is enabled 11044 * 11045 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11046 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11047 * 11048 * @see #getDrawingCacheQuality() 11049 * @see #setDrawingCacheEnabled(boolean) 11050 * @see #isDrawingCacheEnabled() 11051 * 11052 * @attr ref android.R.styleable#View_drawingCacheQuality 11053 * 11054 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11055 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11056 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11057 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11058 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11059 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11060 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11061 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11062 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11063 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11064 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11065 * reports or unit testing the {@link PixelCopy} API is recommended. 11066 */ 11067 @Deprecated setDrawingCacheQuality(@rawingCacheQuality int quality)11068 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 11069 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 11070 } 11071 11072 /** 11073 * Returns whether the screen should remain on, corresponding to the current 11074 * value of {@link #KEEP_SCREEN_ON}. 11075 * 11076 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 11077 * 11078 * @see #setKeepScreenOn(boolean) 11079 * 11080 * @attr ref android.R.styleable#View_keepScreenOn 11081 */ 11082 @InspectableProperty getKeepScreenOn()11083 public boolean getKeepScreenOn() { 11084 return (mViewFlags & KEEP_SCREEN_ON) != 0; 11085 } 11086 11087 /** 11088 * Controls whether the screen should remain on, modifying the 11089 * value of {@link #KEEP_SCREEN_ON}. 11090 * 11091 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 11092 * 11093 * @see #getKeepScreenOn() 11094 * 11095 * @attr ref android.R.styleable#View_keepScreenOn 11096 */ setKeepScreenOn(boolean keepScreenOn)11097 public void setKeepScreenOn(boolean keepScreenOn) { 11098 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 11099 } 11100 11101 /** 11102 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11103 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11104 * 11105 * @attr ref android.R.styleable#View_nextFocusLeft 11106 */ 11107 @IdRes 11108 @InspectableProperty(name = "nextFocusLeft") getNextFocusLeftId()11109 public int getNextFocusLeftId() { 11110 return mNextFocusLeftId; 11111 } 11112 11113 /** 11114 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11115 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 11116 * decide automatically. 11117 * 11118 * @attr ref android.R.styleable#View_nextFocusLeft 11119 */ setNextFocusLeftId(@dRes int nextFocusLeftId)11120 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 11121 mNextFocusLeftId = nextFocusLeftId; 11122 } 11123 11124 /** 11125 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11126 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11127 * 11128 * @attr ref android.R.styleable#View_nextFocusRight 11129 */ 11130 @IdRes 11131 @InspectableProperty(name = "nextFocusRight") getNextFocusRightId()11132 public int getNextFocusRightId() { 11133 return mNextFocusRightId; 11134 } 11135 11136 /** 11137 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11138 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 11139 * decide automatically. 11140 * 11141 * @attr ref android.R.styleable#View_nextFocusRight 11142 */ setNextFocusRightId(@dRes int nextFocusRightId)11143 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 11144 mNextFocusRightId = nextFocusRightId; 11145 } 11146 11147 /** 11148 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11149 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11150 * 11151 * @attr ref android.R.styleable#View_nextFocusUp 11152 */ 11153 @IdRes 11154 @InspectableProperty(name = "nextFocusUp") getNextFocusUpId()11155 public int getNextFocusUpId() { 11156 return mNextFocusUpId; 11157 } 11158 11159 /** 11160 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11161 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 11162 * decide automatically. 11163 * 11164 * @attr ref android.R.styleable#View_nextFocusUp 11165 */ setNextFocusUpId(@dRes int nextFocusUpId)11166 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 11167 mNextFocusUpId = nextFocusUpId; 11168 } 11169 11170 /** 11171 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11172 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11173 * 11174 * @attr ref android.R.styleable#View_nextFocusDown 11175 */ 11176 @IdRes 11177 @InspectableProperty(name = "nextFocusDown") getNextFocusDownId()11178 public int getNextFocusDownId() { 11179 return mNextFocusDownId; 11180 } 11181 11182 /** 11183 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11184 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 11185 * decide automatically. 11186 * 11187 * @attr ref android.R.styleable#View_nextFocusDown 11188 */ setNextFocusDownId(@dRes int nextFocusDownId)11189 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 11190 mNextFocusDownId = nextFocusDownId; 11191 } 11192 11193 /** 11194 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11195 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11196 * 11197 * @attr ref android.R.styleable#View_nextFocusForward 11198 */ 11199 @IdRes 11200 @InspectableProperty(name = "nextFocusForward") getNextFocusForwardId()11201 public int getNextFocusForwardId() { 11202 return mNextFocusForwardId; 11203 } 11204 11205 /** 11206 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11207 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 11208 * decide automatically. 11209 * 11210 * @attr ref android.R.styleable#View_nextFocusForward 11211 */ setNextFocusForwardId(@dRes int nextFocusForwardId)11212 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 11213 mNextFocusForwardId = nextFocusForwardId; 11214 } 11215 11216 /** 11217 * Gets the id of the root of the next keyboard navigation cluster. 11218 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 11219 * decide automatically. 11220 * 11221 * @attr ref android.R.styleable#View_nextClusterForward 11222 */ 11223 @IdRes 11224 @InspectableProperty(name = "nextClusterForward") getNextClusterForwardId()11225 public int getNextClusterForwardId() { 11226 return mNextClusterForwardId; 11227 } 11228 11229 /** 11230 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 11231 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 11232 * decide automatically. 11233 * 11234 * @attr ref android.R.styleable#View_nextClusterForward 11235 */ setNextClusterForwardId(@dRes int nextClusterForwardId)11236 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 11237 mNextClusterForwardId = nextClusterForwardId; 11238 } 11239 11240 /** 11241 * Returns the visibility of this view and all of its ancestors 11242 * 11243 * @return True if this view and all of its ancestors are {@link #VISIBLE} 11244 */ isShown()11245 public boolean isShown() { 11246 View current = this; 11247 //noinspection ConstantConditions 11248 do { 11249 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 11250 return false; 11251 } 11252 ViewParent parent = current.mParent; 11253 if (parent == null) { 11254 return false; // We are not attached to the view root 11255 } 11256 if (!(parent instanceof View)) { 11257 return true; 11258 } 11259 current = (View) parent; 11260 } while (current != null); 11261 11262 return false; 11263 } 11264 detached()11265 private boolean detached() { 11266 View current = this; 11267 //noinspection ConstantConditions 11268 do { 11269 if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { 11270 return true; 11271 } 11272 ViewParent parent = current.mParent; 11273 if (parent == null) { 11274 return false; 11275 } 11276 if (!(parent instanceof View)) { 11277 return false; 11278 } 11279 current = (View) parent; 11280 } while (current != null); 11281 11282 return false; 11283 } 11284 11285 /** 11286 * Called by the view hierarchy when the content insets for a window have 11287 * changed, to allow it to adjust its content to fit within those windows. 11288 * The content insets tell you the space that the status bar, input method, 11289 * and other system windows infringe on the application's window. 11290 * 11291 * <p>You do not normally need to deal with this function, since the default 11292 * window decoration given to applications takes care of applying it to the 11293 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 11294 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 11295 * and your content can be placed under those system elements. You can then 11296 * use this method within your view hierarchy if you have parts of your UI 11297 * which you would like to ensure are not being covered. 11298 * 11299 * <p>The default implementation of this method simply applies the content 11300 * insets to the view's padding, consuming that content (modifying the 11301 * insets to be 0), and returning true. This behavior is off by default, but can 11302 * be enabled through {@link #setFitsSystemWindows(boolean)}. 11303 * 11304 * <p>This function's traversal down the hierarchy is depth-first. The same content 11305 * insets object is propagated down the hierarchy, so any changes made to it will 11306 * be seen by all following views (including potentially ones above in 11307 * the hierarchy since this is a depth-first traversal). The first view 11308 * that returns true will abort the entire traversal. 11309 * 11310 * <p>The default implementation works well for a situation where it is 11311 * used with a container that covers the entire window, allowing it to 11312 * apply the appropriate insets to its content on all edges. If you need 11313 * a more complicated layout (such as two different views fitting system 11314 * windows, one on the top of the window, and one on the bottom), 11315 * you can override the method and handle the insets however you would like. 11316 * Note that the insets provided by the framework are always relative to the 11317 * far edges of the window, not accounting for the location of the called view 11318 * within that window. (In fact when this method is called you do not yet know 11319 * where the layout will place the view, as it is done before layout happens.) 11320 * 11321 * <p>Note: unlike many View methods, there is no dispatch phase to this 11322 * call. If you are overriding it in a ViewGroup and want to allow the 11323 * call to continue to your children, you must be sure to call the super 11324 * implementation. 11325 * 11326 * <p>Here is a sample layout that makes use of fitting system windows 11327 * to have controls for a video view placed inside of the window decorations 11328 * that it hides and shows. This can be used with code like the second 11329 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 11330 * 11331 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 11332 * 11333 * @param insets Current content insets of the window. Prior to 11334 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 11335 * the insets or else you and Android will be unhappy. 11336 * 11337 * @return {@code true} if this view applied the insets and it should not 11338 * continue propagating further down the hierarchy, {@code false} otherwise. 11339 * @see #getFitsSystemWindows() 11340 * @see #setFitsSystemWindows(boolean) 11341 * @see #setSystemUiVisibility(int) 11342 * 11343 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 11344 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 11345 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 11346 * to implement handling their own insets. 11347 */ 11348 @Deprecated fitSystemWindows(Rect insets)11349 protected boolean fitSystemWindows(Rect insets) { 11350 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 11351 if (insets == null) { 11352 // Null insets by definition have already been consumed. 11353 // This call cannot apply insets since there are none to apply, 11354 // so return false. 11355 return false; 11356 } 11357 // If we're not in the process of dispatching the newer apply insets call, 11358 // that means we're not in the compatibility path. Dispatch into the newer 11359 // apply insets path and take things from there. 11360 try { 11361 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 11362 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 11363 } finally { 11364 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 11365 } 11366 } else { 11367 // We're being called from the newer apply insets path. 11368 // Perform the standard fallback behavior. 11369 return fitSystemWindowsInt(insets); 11370 } 11371 } 11372 fitSystemWindowsInt(Rect insets)11373 private boolean fitSystemWindowsInt(Rect insets) { 11374 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 11375 Rect localInsets = sThreadLocal.get(); 11376 boolean res = computeFitSystemWindows(insets, localInsets); 11377 applyInsets(localInsets); 11378 return res; 11379 } 11380 return false; 11381 } 11382 applyInsets(Rect insets)11383 private void applyInsets(Rect insets) { 11384 mUserPaddingStart = UNDEFINED_PADDING; 11385 mUserPaddingEnd = UNDEFINED_PADDING; 11386 mUserPaddingLeftInitial = insets.left; 11387 mUserPaddingRightInitial = insets.right; 11388 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 11389 } 11390 11391 /** 11392 * Called when the view should apply {@link WindowInsets} according to its internal policy. 11393 * 11394 * <p>This method should be overridden by views that wish to apply a policy different from or 11395 * in addition to the default behavior. Clients that wish to force a view subtree 11396 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 11397 * 11398 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 11399 * it will be called during dispatch instead of this method. The listener may optionally 11400 * call this method from its own implementation if it wishes to apply the view's default 11401 * insets policy in addition to its own.</p> 11402 * 11403 * <p>Implementations of this method should either return the insets parameter unchanged 11404 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 11405 * that this view applied itself. This allows new inset types added in future platform 11406 * versions to pass through existing implementations unchanged without being erroneously 11407 * consumed.</p> 11408 * 11409 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 11410 * property is set then the view will consume the system window insets and apply them 11411 * as padding for the view.</p> 11412 * 11413 * @param insets Insets to apply 11414 * @return The supplied insets with any applied insets consumed 11415 */ onApplyWindowInsets(WindowInsets insets)11416 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 11417 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11418 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 11419 return onApplyFrameworkOptionalFitSystemWindows(insets); 11420 } 11421 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 11422 // We weren't called from within a direct call to fitSystemWindows, 11423 // call into it as a fallback in case we're in a class that overrides it 11424 // and has logic to perform. 11425 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 11426 return insets.consumeSystemWindowInsets(); 11427 } 11428 } else { 11429 // We were called from within a direct call to fitSystemWindows. 11430 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 11431 return insets.consumeSystemWindowInsets(); 11432 } 11433 } 11434 return insets; 11435 } 11436 onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets)11437 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 11438 Rect localInsets = sThreadLocal.get(); 11439 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 11440 applyInsets(localInsets); 11441 return result; 11442 } 11443 11444 /** 11445 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 11446 * window insets to this view. The listener's 11447 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 11448 * method will be called instead of the view's 11449 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 11450 * 11451 * @param listener Listener to set 11452 * 11453 * @see #onApplyWindowInsets(WindowInsets) 11454 */ setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)11455 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 11456 getListenerInfo().mOnApplyWindowInsetsListener = listener; 11457 } 11458 11459 /** 11460 * Request to apply the given window insets to this view or another view in its subtree. 11461 * 11462 * <p>This method should be called by clients wishing to apply insets corresponding to areas 11463 * obscured by window decorations or overlays. This can include the status and navigation bars, 11464 * action bars, input methods and more. New inset categories may be added in the future. 11465 * The method returns the insets provided minus any that were applied by this view or its 11466 * children.</p> 11467 * 11468 * <p>Clients wishing to provide custom behavior should override the 11469 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 11470 * {@link OnApplyWindowInsetsListener} via the 11471 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 11472 * method.</p> 11473 * 11474 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 11475 * </p> 11476 * 11477 * @param insets Insets to apply 11478 * @return The provided insets minus the insets that were consumed 11479 */ dispatchApplyWindowInsets(WindowInsets insets)11480 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 11481 try { 11482 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 11483 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 11484 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 11485 } else { 11486 return onApplyWindowInsets(insets); 11487 } 11488 } finally { 11489 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 11490 } 11491 } 11492 11493 /** 11494 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 11495 * cause insets. 11496 * <p> 11497 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 11498 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 11499 * this view. 11500 * </p> 11501 * @param callback The callback to set. 11502 */ setWindowInsetsAnimationCallback( @ullable WindowInsetsAnimation.Callback callback)11503 public void setWindowInsetsAnimationCallback( 11504 @Nullable WindowInsetsAnimation.Callback callback) { 11505 getListenerInfo().mWindowInsetsAnimationCallback = callback; 11506 } 11507 11508 /** 11509 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 11510 * or view tree of the sub-hierarchy {@code false} otherwise. 11511 * @hide 11512 */ hasWindowInsetsAnimationCallback()11513 public boolean hasWindowInsetsAnimationCallback() { 11514 return getListenerInfo().mWindowInsetsAnimationCallback != null; 11515 } 11516 11517 /** 11518 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 11519 * when Window Insets animation is being prepared. 11520 * @param animation current animation 11521 * 11522 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 11523 */ dispatchWindowInsetsAnimationPrepare( @onNull WindowInsetsAnimation animation)11524 public void dispatchWindowInsetsAnimationPrepare( 11525 @NonNull WindowInsetsAnimation animation) { 11526 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11527 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 11528 } 11529 } 11530 11531 /** 11532 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 11533 * when Window Insets animation is started. 11534 * @param animation current animation 11535 * @param bounds the upper and lower {@link Bounds} that provides range of 11536 * {@link WindowInsetsAnimation}. 11537 * @return the upper and lower {@link Bounds}. 11538 */ 11539 @NonNull dispatchWindowInsetsAnimationStart( @onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)11540 public Bounds dispatchWindowInsetsAnimationStart( 11541 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 11542 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11543 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 11544 } 11545 return bounds; 11546 } 11547 11548 /** 11549 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 11550 * when Window Insets animation makes progress. 11551 * @param insets The current {@link WindowInsets}. 11552 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 11553 * @return current {@link WindowInsets}. 11554 */ 11555 @NonNull dispatchWindowInsetsAnimationProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)11556 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 11557 @NonNull List<WindowInsetsAnimation> runningAnimations) { 11558 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11559 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 11560 runningAnimations); 11561 } else { 11562 return insets; 11563 } 11564 } 11565 11566 /** 11567 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 11568 * when Window Insets animation ends. 11569 * @param animation The current ongoing {@link WindowInsetsAnimation}. 11570 */ dispatchWindowInsetsAnimationEnd(@onNull WindowInsetsAnimation animation)11571 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 11572 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11573 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 11574 } 11575 } 11576 11577 /** 11578 * Sets a list of areas within this view's post-layout coordinate space where the system 11579 * should not intercept touch or other pointing device gestures. <em>This method should 11580 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 11581 * 11582 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 11583 * input in order to function correctly in the presence of global system gestures that may 11584 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 11585 * to provide system-level navigation functionality, a view such as a navigation drawer 11586 * container can mark the left (or starting) edge of itself as requiring gesture capture 11587 * priority using this API. The system may then choose to relax its own gesture recognition 11588 * to allow the app to consume the user's gesture. It is not necessary for an app to register 11589 * exclusion rects for broadly spanning regions such as the entirety of a 11590 * <code>ScrollView</code> or for simple press and release click targets such as 11591 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 11592 * a precision touch gesture in a small area in either the X or Y dimension, such as 11593 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 11594 * 11595 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 11596 * exclusions it takes into account. The limit does not apply while the navigation 11597 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 11598 * {@link android.inputmethodservice.InputMethodService input method} and 11599 * {@link Intent#CATEGORY_HOME home activity}. 11600 * </p> 11601 * 11602 * @param rects A list of precision gesture regions that this view needs to function correctly 11603 */ setSystemGestureExclusionRects(@onNull List<Rect> rects)11604 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 11605 if (rects.isEmpty() && mListenerInfo == null) return; 11606 11607 final ListenerInfo info = getListenerInfo(); 11608 if (info.mSystemGestureExclusionRects != null) { 11609 info.mSystemGestureExclusionRects.clear(); 11610 info.mSystemGestureExclusionRects.addAll(rects); 11611 } else { 11612 info.mSystemGestureExclusionRects = new ArrayList<>(rects); 11613 } 11614 if (rects.isEmpty()) { 11615 if (info.mPositionUpdateListener != null) { 11616 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 11617 } 11618 } else { 11619 if (info.mPositionUpdateListener == null) { 11620 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 11621 @Override 11622 public void positionChanged(long n, int l, int t, int r, int b) { 11623 postUpdateSystemGestureExclusionRects(); 11624 } 11625 11626 @Override 11627 public void positionLost(long frameNumber) { 11628 postUpdateSystemGestureExclusionRects(); 11629 } 11630 }; 11631 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 11632 } 11633 } 11634 postUpdateSystemGestureExclusionRects(); 11635 } 11636 11637 /** 11638 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 11639 */ postUpdateSystemGestureExclusionRects()11640 void postUpdateSystemGestureExclusionRects() { 11641 // Potentially racey from a background thread. It's ok if it's not perfect. 11642 final Handler h = getHandler(); 11643 if (h != null) { 11644 h.postAtFrontOfQueue(this::updateSystemGestureExclusionRects); 11645 } 11646 } 11647 updateSystemGestureExclusionRects()11648 void updateSystemGestureExclusionRects() { 11649 final AttachInfo ai = mAttachInfo; 11650 if (ai != null) { 11651 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 11652 } 11653 } 11654 11655 /** 11656 * Retrieve the list of areas within this view's post-layout coordinate space where the system 11657 * should not intercept touch or other pointing device gestures. 11658 * 11659 * <p>Do not modify the returned list.</p> 11660 * 11661 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 11662 */ 11663 @NonNull getSystemGestureExclusionRects()11664 public List<Rect> getSystemGestureExclusionRects() { 11665 final ListenerInfo info = mListenerInfo; 11666 if (info != null) { 11667 final List<Rect> list = info.mSystemGestureExclusionRects; 11668 if (list != null) { 11669 return list; 11670 } 11671 } 11672 return Collections.emptyList(); 11673 } 11674 11675 /** 11676 * Compute the view's coordinate within the surface. 11677 * 11678 * <p>Computes the coordinates of this view in its surface. The argument 11679 * must be an array of two integers. After the method returns, the array 11680 * contains the x and y location in that order.</p> 11681 * 11682 * @param location an array of two integers in which to hold the coordinates 11683 */ getLocationInSurface(@onNull @ize2) int[] location)11684 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 11685 getLocationInWindow(location); 11686 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 11687 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 11688 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 11689 } 11690 } 11691 11692 /** 11693 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 11694 * only available if the view is attached. 11695 * 11696 * @return WindowInsets from the top of the view hierarchy or null if View is detached 11697 */ getRootWindowInsets()11698 public WindowInsets getRootWindowInsets() { 11699 if (mAttachInfo != null) { 11700 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 11701 } 11702 return null; 11703 } 11704 11705 /** 11706 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 11707 * 11708 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 11709 * a window nor a view tree with a decor. 11710 * @see Window#getInsetsController() 11711 */ getWindowInsetsController()11712 public @Nullable WindowInsetsController getWindowInsetsController() { 11713 if (mAttachInfo != null) { 11714 return mAttachInfo.mViewRootImpl.getInsetsController(); 11715 } 11716 ViewParent parent = getParent(); 11717 if (parent instanceof View) { 11718 return ((View) parent).getWindowInsetsController(); 11719 } else if (parent instanceof ViewRootImpl) { 11720 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 11721 return ((ViewRootImpl) parent).getInsetsController(); 11722 } 11723 return null; 11724 } 11725 11726 /** 11727 * @hide Compute the insets that should be consumed by this view and the ones 11728 * that should propagate to those under it. 11729 * 11730 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 11731 * 11732 * @param inoutInsets the insets given to this view 11733 * @param outLocalInsets the insets that should be applied to this view 11734 * @deprecated use {@link #computeSystemWindowInsets} 11735 * @return 11736 */ 11737 @Deprecated 11738 @UnsupportedAppUsage computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets)11739 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 11740 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 11741 outLocalInsets); 11742 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 11743 return innerInsets.isSystemWindowInsetsConsumed(); 11744 } 11745 11746 /** 11747 * Compute insets that should be consumed by this view and the ones that should propagate 11748 * to those under it. 11749 * 11750 * @param in Insets currently being processed by this View, likely received as a parameter 11751 * to {@link #onApplyWindowInsets(WindowInsets)}. 11752 * @param outLocalInsets A Rect that will receive the insets that should be consumed 11753 * by this view 11754 * @return Insets that should be passed along to views under this one 11755 */ computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets)11756 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 11757 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11758 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 11759 if (isOptionalFitSystemWindows && mAttachInfo != null) { 11760 OnContentApplyWindowInsetsListener listener = 11761 mAttachInfo.mContentOnApplyWindowInsetsListener; 11762 if (listener == null) { 11763 // The application wants to take care of fitting system window for 11764 // the content. 11765 outLocalInsets.setEmpty(); 11766 return in; 11767 } 11768 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 11769 outLocalInsets.set(result.first.toRect()); 11770 return result.second; 11771 } else { 11772 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 11773 return in.consumeSystemWindowInsets().inset(outLocalInsets); 11774 } 11775 } 11776 11777 /** 11778 * Sets whether or not this view should account for system screen decorations 11779 * such as the status bar and inset its content; that is, controlling whether 11780 * the default implementation of {@link #fitSystemWindows(Rect)} will be 11781 * executed. See that method for more details. 11782 * 11783 * <p>Note that if you are providing your own implementation of 11784 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 11785 * flag to true -- your implementation will be overriding the default 11786 * implementation that checks this flag. 11787 * 11788 * @param fitSystemWindows If true, then the default implementation of 11789 * {@link #fitSystemWindows(Rect)} will be executed. 11790 * 11791 * @attr ref android.R.styleable#View_fitsSystemWindows 11792 * @see #getFitsSystemWindows() 11793 * @see #fitSystemWindows(Rect) 11794 * @see #setSystemUiVisibility(int) 11795 */ setFitsSystemWindows(boolean fitSystemWindows)11796 public void setFitsSystemWindows(boolean fitSystemWindows) { 11797 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 11798 } 11799 11800 /** 11801 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 11802 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 11803 * will be executed. 11804 * 11805 * @return {@code true} if the default implementation of 11806 * {@link #fitSystemWindows(Rect)} will be executed. 11807 * 11808 * @attr ref android.R.styleable#View_fitsSystemWindows 11809 * @see #setFitsSystemWindows(boolean) 11810 * @see #fitSystemWindows(Rect) 11811 * @see #setSystemUiVisibility(int) 11812 */ 11813 @ViewDebug.ExportedProperty 11814 @InspectableProperty getFitsSystemWindows()11815 public boolean getFitsSystemWindows() { 11816 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 11817 } 11818 11819 /** @hide */ 11820 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) fitsSystemWindows()11821 public boolean fitsSystemWindows() { 11822 return getFitsSystemWindows(); 11823 } 11824 11825 /** 11826 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 11827 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 11828 */ 11829 @Deprecated requestFitSystemWindows()11830 public void requestFitSystemWindows() { 11831 if (mParent != null) { 11832 mParent.requestFitSystemWindows(); 11833 } 11834 } 11835 11836 /** 11837 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 11838 */ requestApplyInsets()11839 public void requestApplyInsets() { 11840 requestFitSystemWindows(); 11841 } 11842 11843 /** 11844 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 11845 * @hide 11846 */ 11847 @UnsupportedAppUsage makeOptionalFitsSystemWindows()11848 public void makeOptionalFitsSystemWindows() { 11849 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 11850 } 11851 11852 /** 11853 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 11854 * @hide 11855 */ makeFrameworkOptionalFitsSystemWindows()11856 public void makeFrameworkOptionalFitsSystemWindows() { 11857 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 11858 } 11859 11860 /** 11861 * @hide 11862 */ isFrameworkOptionalFitsSystemWindows()11863 public boolean isFrameworkOptionalFitsSystemWindows() { 11864 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 11865 } 11866 11867 /** 11868 * Returns the visibility status for this view. 11869 * 11870 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11871 * @attr ref android.R.styleable#View_visibility 11872 */ 11873 @ViewDebug.ExportedProperty(mapping = { 11874 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 11875 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 11876 @ViewDebug.IntToString(from = GONE, to = "GONE") 11877 }) 11878 @InspectableProperty(enumMapping = { 11879 @EnumEntry(value = VISIBLE, name = "visible"), 11880 @EnumEntry(value = INVISIBLE, name = "invisible"), 11881 @EnumEntry(value = GONE, name = "gone") 11882 }) 11883 @Visibility getVisibility()11884 public int getVisibility() { 11885 return mViewFlags & VISIBILITY_MASK; 11886 } 11887 11888 /** 11889 * Set the visibility state of this view. 11890 * 11891 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11892 * @attr ref android.R.styleable#View_visibility 11893 */ 11894 @RemotableViewMethod setVisibility(@isibility int visibility)11895 public void setVisibility(@Visibility int visibility) { 11896 setFlags(visibility, VISIBILITY_MASK); 11897 } 11898 11899 /** 11900 * Returns the enabled status for this view. The interpretation of the 11901 * enabled state varies by subclass. 11902 * 11903 * @return True if this view is enabled, false otherwise. 11904 */ 11905 @ViewDebug.ExportedProperty 11906 @InspectableProperty isEnabled()11907 public boolean isEnabled() { 11908 return (mViewFlags & ENABLED_MASK) == ENABLED; 11909 } 11910 11911 /** 11912 * Set the enabled state of this view. The interpretation of the enabled 11913 * state varies by subclass. 11914 * 11915 * @param enabled True if this view is enabled, false otherwise. 11916 */ 11917 @RemotableViewMethod setEnabled(boolean enabled)11918 public void setEnabled(boolean enabled) { 11919 if (enabled == isEnabled()) return; 11920 11921 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 11922 11923 /* 11924 * The View most likely has to change its appearance, so refresh 11925 * the drawable state. 11926 */ 11927 refreshDrawableState(); 11928 11929 // Invalidate too, since the default behavior for views is to be 11930 // be drawn at 50% alpha rather than to change the drawable. 11931 invalidate(true); 11932 11933 if (!enabled) { 11934 cancelPendingInputEvents(); 11935 } 11936 } 11937 11938 /** 11939 * Set whether this view can receive the focus. 11940 * <p> 11941 * Setting this to false will also ensure that this view is not focusable 11942 * in touch mode. 11943 * 11944 * @param focusable If true, this view can receive the focus. 11945 * 11946 * @see #setFocusableInTouchMode(boolean) 11947 * @see #setFocusable(int) 11948 * @attr ref android.R.styleable#View_focusable 11949 */ 11950 @RemotableViewMethod setFocusable(boolean focusable)11951 public void setFocusable(boolean focusable) { 11952 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 11953 } 11954 11955 /** 11956 * Sets whether this view can receive focus. 11957 * <p> 11958 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 11959 * automatically based on the view's interactivity. This is the default. 11960 * <p> 11961 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 11962 * in touch mode. 11963 * 11964 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 11965 * or {@link #FOCUSABLE_AUTO}. 11966 * @see #setFocusableInTouchMode(boolean) 11967 * @attr ref android.R.styleable#View_focusable 11968 */ 11969 @RemotableViewMethod setFocusable(@ocusable int focusable)11970 public void setFocusable(@Focusable int focusable) { 11971 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 11972 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 11973 } 11974 setFlags(focusable, FOCUSABLE_MASK); 11975 } 11976 11977 /** 11978 * Set whether this view can receive focus while in touch mode. 11979 * 11980 * Setting this to true will also ensure that this view is focusable. 11981 * 11982 * @param focusableInTouchMode If true, this view can receive the focus while 11983 * in touch mode. 11984 * 11985 * @see #setFocusable(boolean) 11986 * @attr ref android.R.styleable#View_focusableInTouchMode 11987 */ 11988 @RemotableViewMethod setFocusableInTouchMode(boolean focusableInTouchMode)11989 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 11990 // Focusable in touch mode should always be set before the focusable flag 11991 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 11992 // which, in touch mode, will not successfully request focus on this view 11993 // because the focusable in touch mode flag is not set 11994 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 11995 11996 // Clear FOCUSABLE_AUTO if set. 11997 if (focusableInTouchMode) { 11998 // Clears FOCUSABLE_AUTO if set. 11999 setFlags(FOCUSABLE, FOCUSABLE_MASK); 12000 } 12001 } 12002 12003 /** 12004 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 12005 * to autofill the view with the user's data. 12006 * 12007 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 12008 * For example, if the application accepts either an username or email address to identify 12009 * an user. 12010 * 12011 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 12012 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 12013 * constants such as: 12014 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 12015 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 12016 * {@link #AUTOFILL_HINT_NAME}, 12017 * {@link #AUTOFILL_HINT_PHONE}, 12018 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 12019 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 12020 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 12021 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 12022 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 12023 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 12024 * 12025 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 12026 * @attr ref android.R.styleable#View_autofillHints 12027 */ setAutofillHints(@ullable String... autofillHints)12028 public void setAutofillHints(@Nullable String... autofillHints) { 12029 if (autofillHints == null || autofillHints.length == 0) { 12030 mAutofillHints = null; 12031 } else { 12032 mAutofillHints = autofillHints; 12033 } 12034 } 12035 12036 /** 12037 * @hide 12038 */ 12039 @TestApi setAutofilled(boolean isAutofilled, boolean hideHighlight)12040 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 12041 boolean wasChanged = isAutofilled != isAutofilled(); 12042 12043 if (wasChanged) { 12044 if (isAutofilled) { 12045 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 12046 } else { 12047 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 12048 } 12049 12050 if (hideHighlight) { 12051 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 12052 } else { 12053 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 12054 } 12055 12056 invalidate(); 12057 } 12058 } 12059 12060 /** 12061 * Set whether this view should have sound effects enabled for events such as 12062 * clicking and touching. 12063 * 12064 * <p>You may wish to disable sound effects for a view if you already play sounds, 12065 * for instance, a dial key that plays dtmf tones. 12066 * 12067 * @param soundEffectsEnabled whether sound effects are enabled for this view. 12068 * @see #isSoundEffectsEnabled() 12069 * @see #playSoundEffect(int) 12070 * @attr ref android.R.styleable#View_soundEffectsEnabled 12071 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)12072 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 12073 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 12074 } 12075 12076 /** 12077 * @return whether this view should have sound effects enabled for events such as 12078 * clicking and touching. 12079 * 12080 * @see #setSoundEffectsEnabled(boolean) 12081 * @see #playSoundEffect(int) 12082 * @attr ref android.R.styleable#View_soundEffectsEnabled 12083 */ 12084 @ViewDebug.ExportedProperty 12085 @InspectableProperty isSoundEffectsEnabled()12086 public boolean isSoundEffectsEnabled() { 12087 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 12088 } 12089 12090 /** 12091 * Set whether this view should have haptic feedback for events such as 12092 * long presses. 12093 * 12094 * <p>You may wish to disable haptic feedback if your view already controls 12095 * its own haptic feedback. 12096 * 12097 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 12098 * @see #isHapticFeedbackEnabled() 12099 * @see #performHapticFeedback(int) 12100 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 12101 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)12102 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 12103 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 12104 } 12105 12106 /** 12107 * @return whether this view should have haptic feedback enabled for events 12108 * long presses. 12109 * 12110 * @see #setHapticFeedbackEnabled(boolean) 12111 * @see #performHapticFeedback(int) 12112 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 12113 */ 12114 @ViewDebug.ExportedProperty 12115 @InspectableProperty isHapticFeedbackEnabled()12116 public boolean isHapticFeedbackEnabled() { 12117 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 12118 } 12119 12120 /** 12121 * Returns the layout direction for this view. 12122 * 12123 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 12124 * {@link #LAYOUT_DIRECTION_RTL}, 12125 * {@link #LAYOUT_DIRECTION_INHERIT} or 12126 * {@link #LAYOUT_DIRECTION_LOCALE}. 12127 * 12128 * @attr ref android.R.styleable#View_layoutDirection 12129 * 12130 * @hide 12131 */ 12132 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12133 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 12134 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 12135 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 12136 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 12137 }) 12138 @InspectableProperty(hasAttributeId = false, enumMapping = { 12139 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12140 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 12141 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 12142 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 12143 }) 12144 @LayoutDir getRawLayoutDirection()12145 public int getRawLayoutDirection() { 12146 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 12147 } 12148 12149 /** 12150 * Set the layout direction for this view. This will propagate a reset of layout direction 12151 * resolution to the view's children and resolve layout direction for this view. 12152 * 12153 * @param layoutDirection the layout direction to set. Should be one of: 12154 * 12155 * {@link #LAYOUT_DIRECTION_LTR}, 12156 * {@link #LAYOUT_DIRECTION_RTL}, 12157 * {@link #LAYOUT_DIRECTION_INHERIT}, 12158 * {@link #LAYOUT_DIRECTION_LOCALE}. 12159 * 12160 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 12161 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 12162 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 12163 * 12164 * @attr ref android.R.styleable#View_layoutDirection 12165 */ 12166 @RemotableViewMethod setLayoutDirection(@ayoutDir int layoutDirection)12167 public void setLayoutDirection(@LayoutDir int layoutDirection) { 12168 if (getRawLayoutDirection() != layoutDirection) { 12169 // Reset the current layout direction and the resolved one 12170 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 12171 resetRtlProperties(); 12172 // Set the new layout direction (filtered) 12173 mPrivateFlags2 |= 12174 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 12175 // We need to resolve all RTL properties as they all depend on layout direction 12176 resolveRtlPropertiesIfNeeded(); 12177 requestLayout(); 12178 invalidate(true); 12179 } 12180 } 12181 12182 /** 12183 * Returns the resolved layout direction for this view. 12184 * 12185 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 12186 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 12187 * 12188 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 12189 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 12190 * 12191 * @attr ref android.R.styleable#View_layoutDirection 12192 */ 12193 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12194 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 12195 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 12196 }) 12197 @InspectableProperty(enumMapping = { 12198 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12199 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 12200 }) 12201 @ResolvedLayoutDir getLayoutDirection()12202 public int getLayoutDirection() { 12203 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 12204 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 12205 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 12206 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 12207 } 12208 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 12209 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 12210 } 12211 12212 /** 12213 * Indicates whether or not this view's layout is right-to-left. This is resolved from 12214 * layout attribute and/or the inherited value from the parent 12215 * 12216 * @return true if the layout is right-to-left. 12217 * 12218 * @hide 12219 */ 12220 @ViewDebug.ExportedProperty(category = "layout") 12221 @UnsupportedAppUsage isLayoutRtl()12222 public boolean isLayoutRtl() { 12223 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 12224 } 12225 12226 /** 12227 * Indicates whether the view is currently tracking transient state that the 12228 * app should not need to concern itself with saving and restoring, but that 12229 * the framework should take special note to preserve when possible. 12230 * 12231 * <p>A view with transient state cannot be trivially rebound from an external 12232 * data source, such as an adapter binding item views in a list. This may be 12233 * because the view is performing an animation, tracking user selection 12234 * of content, or similar.</p> 12235 * 12236 * @return true if the view has transient state 12237 */ 12238 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()12239 public boolean hasTransientState() { 12240 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 12241 } 12242 12243 /** 12244 * Set whether this view is currently tracking transient state that the 12245 * framework should attempt to preserve when possible. This flag is reference counted, 12246 * so every call to setHasTransientState(true) should be paired with a later call 12247 * to setHasTransientState(false). 12248 * 12249 * <p>A view with transient state cannot be trivially rebound from an external 12250 * data source, such as an adapter binding item views in a list. This may be 12251 * because the view is performing an animation, tracking user selection 12252 * of content, or similar.</p> 12253 * 12254 * @param hasTransientState true if this view has transient state 12255 */ setHasTransientState(boolean hasTransientState)12256 public void setHasTransientState(boolean hasTransientState) { 12257 final boolean oldHasTransientState = hasTransientState(); 12258 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 12259 mTransientStateCount - 1; 12260 if (mTransientStateCount < 0) { 12261 mTransientStateCount = 0; 12262 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 12263 "unmatched pair of setHasTransientState calls"); 12264 } else if ((hasTransientState && mTransientStateCount == 1) || 12265 (!hasTransientState && mTransientStateCount == 0)) { 12266 // update flag if we've just incremented up from 0 or decremented down to 0 12267 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 12268 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 12269 final boolean newHasTransientState = hasTransientState(); 12270 if (mParent != null && newHasTransientState != oldHasTransientState) { 12271 try { 12272 mParent.childHasTransientStateChanged(this, newHasTransientState); 12273 } catch (AbstractMethodError e) { 12274 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 12275 " does not fully implement ViewParent", e); 12276 } 12277 } 12278 } 12279 } 12280 12281 /** 12282 * Set the view is tracking translation transient state. This flag is used to check if the view 12283 * need to call setHasTransientState(false) to reset transient state that set when starting 12284 * translation. 12285 * 12286 * @param hasTranslationTransientState true if this view has translation transient state 12287 * @hide 12288 */ setHasTranslationTransientState(boolean hasTranslationTransientState)12289 public void setHasTranslationTransientState(boolean hasTranslationTransientState) { 12290 if (hasTranslationTransientState) { 12291 mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12292 } else { 12293 mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12294 } 12295 } 12296 12297 /** 12298 * @hide 12299 */ hasTranslationTransientState()12300 public boolean hasTranslationTransientState() { 12301 return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) 12302 == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 12303 } 12304 12305 /** 12306 * Returns true if this view is currently attached to a window. 12307 */ isAttachedToWindow()12308 public boolean isAttachedToWindow() { 12309 return mAttachInfo != null; 12310 } 12311 12312 /** 12313 * Returns true if this view has been through at least one layout since it 12314 * was last attached to or detached from a window. 12315 */ isLaidOut()12316 public boolean isLaidOut() { 12317 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 12318 } 12319 12320 /** 12321 * @return {@code true} if laid-out and not about to do another layout. 12322 */ isLayoutValid()12323 boolean isLayoutValid() { 12324 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 12325 } 12326 12327 /** 12328 * If this view doesn't do any drawing on its own, set this flag to 12329 * allow further optimizations. By default, this flag is not set on 12330 * View, but could be set on some View subclasses such as ViewGroup. 12331 * 12332 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 12333 * you should clear this flag. 12334 * 12335 * @param willNotDraw whether or not this View draw on its own 12336 */ setWillNotDraw(boolean willNotDraw)12337 public void setWillNotDraw(boolean willNotDraw) { 12338 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 12339 } 12340 12341 /** 12342 * Returns whether or not this View draws on its own. 12343 * 12344 * @return true if this view has nothing to draw, false otherwise 12345 */ 12346 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()12347 public boolean willNotDraw() { 12348 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 12349 } 12350 12351 /** 12352 * When a View's drawing cache is enabled, drawing is redirected to an 12353 * offscreen bitmap. Some views, like an ImageView, must be able to 12354 * bypass this mechanism if they already draw a single bitmap, to avoid 12355 * unnecessary usage of the memory. 12356 * 12357 * @param willNotCacheDrawing true if this view does not cache its 12358 * drawing, false otherwise 12359 * 12360 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12361 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12362 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12363 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12364 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12365 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12366 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12367 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12368 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12369 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12370 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12371 * reports or unit testing the {@link PixelCopy} API is recommended. 12372 */ 12373 @Deprecated setWillNotCacheDrawing(boolean willNotCacheDrawing)12374 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 12375 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 12376 } 12377 12378 /** 12379 * Returns whether or not this View can cache its drawing or not. 12380 * 12381 * @return true if this view does not cache its drawing, false otherwise 12382 * 12383 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12384 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12385 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12386 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12387 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12388 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12389 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12390 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12391 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12392 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12393 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12394 * reports or unit testing the {@link PixelCopy} API is recommended. 12395 */ 12396 @ViewDebug.ExportedProperty(category = "drawing") 12397 @Deprecated willNotCacheDrawing()12398 public boolean willNotCacheDrawing() { 12399 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 12400 } 12401 12402 /** 12403 * Indicates whether this view reacts to click events or not. 12404 * 12405 * @return true if the view is clickable, false otherwise 12406 * 12407 * @see #setClickable(boolean) 12408 * @attr ref android.R.styleable#View_clickable 12409 */ 12410 @ViewDebug.ExportedProperty 12411 @InspectableProperty isClickable()12412 public boolean isClickable() { 12413 return (mViewFlags & CLICKABLE) == CLICKABLE; 12414 } 12415 12416 /** 12417 * Enables or disables click events for this view. When a view 12418 * is clickable it will change its state to "pressed" on every click. 12419 * Subclasses should set the view clickable to visually react to 12420 * user's clicks. 12421 * 12422 * @param clickable true to make the view clickable, false otherwise 12423 * 12424 * @see #isClickable() 12425 * @attr ref android.R.styleable#View_clickable 12426 */ setClickable(boolean clickable)12427 public void setClickable(boolean clickable) { 12428 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 12429 } 12430 12431 /** 12432 * Enables or disables click events for this view when disabled. 12433 * 12434 * @param clickableWhenDisabled true to make the view clickable, false otherwise 12435 * 12436 * @attr ref android.R.styleable#View_allowClickWhenDisabled 12437 */ setAllowClickWhenDisabled(boolean clickableWhenDisabled)12438 public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { 12439 if (clickableWhenDisabled) { 12440 mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 12441 } else { 12442 mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 12443 } 12444 } 12445 12446 /** 12447 * Indicates whether this view reacts to long click events or not. 12448 * 12449 * @return true if the view is long clickable, false otherwise 12450 * 12451 * @see #setLongClickable(boolean) 12452 * @attr ref android.R.styleable#View_longClickable 12453 */ 12454 @InspectableProperty isLongClickable()12455 public boolean isLongClickable() { 12456 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12457 } 12458 12459 /** 12460 * Enables or disables long click events for this view. When a view is long 12461 * clickable it reacts to the user holding down the button for a longer 12462 * duration than a tap. This event can either launch the listener or a 12463 * context menu. 12464 * 12465 * @param longClickable true to make the view long clickable, false otherwise 12466 * @see #isLongClickable() 12467 * @attr ref android.R.styleable#View_longClickable 12468 */ setLongClickable(boolean longClickable)12469 public void setLongClickable(boolean longClickable) { 12470 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 12471 } 12472 12473 /** 12474 * Indicates whether this view reacts to context clicks or not. 12475 * 12476 * @return true if the view is context clickable, false otherwise 12477 * @see #setContextClickable(boolean) 12478 * @attr ref android.R.styleable#View_contextClickable 12479 */ 12480 @InspectableProperty isContextClickable()12481 public boolean isContextClickable() { 12482 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12483 } 12484 12485 /** 12486 * Enables or disables context clicking for this view. This event can launch the listener. 12487 * 12488 * @param contextClickable true to make the view react to a context click, false otherwise 12489 * @see #isContextClickable() 12490 * @attr ref android.R.styleable#View_contextClickable 12491 */ setContextClickable(boolean contextClickable)12492 public void setContextClickable(boolean contextClickable) { 12493 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 12494 } 12495 12496 /** 12497 * Sets the pressed state for this view and provides a touch coordinate for 12498 * animation hinting. 12499 * 12500 * @param pressed Pass true to set the View's internal state to "pressed", 12501 * or false to reverts the View's internal state from a 12502 * previously set "pressed" state. 12503 * @param x The x coordinate of the touch that caused the press 12504 * @param y The y coordinate of the touch that caused the press 12505 */ setPressed(boolean pressed, float x, float y)12506 private void setPressed(boolean pressed, float x, float y) { 12507 if (pressed) { 12508 drawableHotspotChanged(x, y); 12509 } 12510 12511 setPressed(pressed); 12512 } 12513 12514 /** 12515 * Sets the pressed state for this view. 12516 * 12517 * @see #isClickable() 12518 * @see #setClickable(boolean) 12519 * 12520 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 12521 * the View's internal state from a previously set "pressed" state. 12522 */ setPressed(boolean pressed)12523 public void setPressed(boolean pressed) { 12524 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 12525 12526 if (pressed) { 12527 mPrivateFlags |= PFLAG_PRESSED; 12528 } else { 12529 mPrivateFlags &= ~PFLAG_PRESSED; 12530 } 12531 12532 if (needsRefresh) { 12533 refreshDrawableState(); 12534 } 12535 dispatchSetPressed(pressed); 12536 } 12537 12538 /** 12539 * Dispatch setPressed to all of this View's children. 12540 * 12541 * @see #setPressed(boolean) 12542 * 12543 * @param pressed The new pressed state 12544 */ dispatchSetPressed(boolean pressed)12545 protected void dispatchSetPressed(boolean pressed) { 12546 } 12547 12548 /** 12549 * Indicates whether the view is currently in pressed state. Unless 12550 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 12551 * the pressed state. 12552 * 12553 * @see #setPressed(boolean) 12554 * @see #isClickable() 12555 * @see #setClickable(boolean) 12556 * 12557 * @return true if the view is currently pressed, false otherwise 12558 */ 12559 @ViewDebug.ExportedProperty 12560 @InspectableProperty(hasAttributeId = false) isPressed()12561 public boolean isPressed() { 12562 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 12563 } 12564 12565 /** 12566 * @hide 12567 * Indicates whether this view will participate in data collection through 12568 * {@link ViewStructure}. If true, it will not provide any data 12569 * for itself or its children. If false, the normal data collection will be allowed. 12570 * 12571 * @return Returns false if assist data collection is not blocked, else true. 12572 * 12573 * @see #setAssistBlocked(boolean) 12574 * @attr ref android.R.styleable#View_assistBlocked 12575 */ isAssistBlocked()12576 public boolean isAssistBlocked() { 12577 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 12578 } 12579 12580 /** 12581 * @hide 12582 * Controls whether assist data collection from this view and its children is enabled 12583 * (that is, whether {@link #onProvideStructure} and 12584 * {@link #onProvideVirtualStructure} will be called). The default value is false, 12585 * allowing normal assist collection. Setting this to false will disable assist collection. 12586 * 12587 * @param enabled Set to true to <em>disable</em> assist data collection, or false 12588 * (the default) to allow it. 12589 * 12590 * @see #isAssistBlocked() 12591 * @see #onProvideStructure 12592 * @see #onProvideVirtualStructure 12593 * @attr ref android.R.styleable#View_assistBlocked 12594 */ 12595 @UnsupportedAppUsage setAssistBlocked(boolean enabled)12596 public void setAssistBlocked(boolean enabled) { 12597 if (enabled) { 12598 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 12599 } else { 12600 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 12601 } 12602 } 12603 12604 /** 12605 * Indicates whether this view will save its state (that is, 12606 * whether its {@link #onSaveInstanceState} method will be called). 12607 * 12608 * @return Returns true if the view state saving is enabled, else false. 12609 * 12610 * @see #setSaveEnabled(boolean) 12611 * @attr ref android.R.styleable#View_saveEnabled 12612 */ 12613 @InspectableProperty isSaveEnabled()12614 public boolean isSaveEnabled() { 12615 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 12616 } 12617 12618 /** 12619 * Controls whether the saving of this view's state is 12620 * enabled (that is, whether its {@link #onSaveInstanceState} method 12621 * will be called). Note that even if freezing is enabled, the 12622 * view still must have an id assigned to it (via {@link #setId(int)}) 12623 * for its state to be saved. This flag can only disable the 12624 * saving of this view; any child views may still have their state saved. 12625 * 12626 * @param enabled Set to false to <em>disable</em> state saving, or true 12627 * (the default) to allow it. 12628 * 12629 * @see #isSaveEnabled() 12630 * @see #setId(int) 12631 * @see #onSaveInstanceState() 12632 * @attr ref android.R.styleable#View_saveEnabled 12633 */ setSaveEnabled(boolean enabled)12634 public void setSaveEnabled(boolean enabled) { 12635 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 12636 } 12637 12638 /** 12639 * Gets whether the framework should discard touches when the view's 12640 * window is obscured by another visible window. 12641 * Refer to the {@link View} security documentation for more details. 12642 * 12643 * @return True if touch filtering is enabled. 12644 * 12645 * @see #setFilterTouchesWhenObscured(boolean) 12646 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12647 */ 12648 @ViewDebug.ExportedProperty 12649 @InspectableProperty getFilterTouchesWhenObscured()12650 public boolean getFilterTouchesWhenObscured() { 12651 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 12652 } 12653 12654 /** 12655 * Sets whether the framework should discard touches when the view's 12656 * window is obscured by another visible window. 12657 * Refer to the {@link View} security documentation for more details. 12658 * 12659 * @param enabled True if touch filtering should be enabled. 12660 * 12661 * @see #getFilterTouchesWhenObscured 12662 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12663 */ setFilterTouchesWhenObscured(boolean enabled)12664 public void setFilterTouchesWhenObscured(boolean enabled) { 12665 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 12666 FILTER_TOUCHES_WHEN_OBSCURED); 12667 } 12668 12669 /** 12670 * Indicates whether the entire hierarchy under this view will save its 12671 * state when a state saving traversal occurs from its parent. The default 12672 * is true; if false, these views will not be saved unless 12673 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12674 * 12675 * @return Returns true if the view state saving from parent is enabled, else false. 12676 * 12677 * @see #setSaveFromParentEnabled(boolean) 12678 */ isSaveFromParentEnabled()12679 public boolean isSaveFromParentEnabled() { 12680 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 12681 } 12682 12683 /** 12684 * Controls whether the entire hierarchy under this view will save its 12685 * state when a state saving traversal occurs from its parent. The default 12686 * is true; if false, these views will not be saved unless 12687 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12688 * 12689 * @param enabled Set to false to <em>disable</em> state saving, or true 12690 * (the default) to allow it. 12691 * 12692 * @see #isSaveFromParentEnabled() 12693 * @see #setId(int) 12694 * @see #onSaveInstanceState() 12695 */ setSaveFromParentEnabled(boolean enabled)12696 public void setSaveFromParentEnabled(boolean enabled) { 12697 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 12698 } 12699 12700 12701 /** 12702 * Returns whether this View is currently able to take focus. 12703 * 12704 * @return True if this view can take focus, or false otherwise. 12705 */ 12706 @ViewDebug.ExportedProperty(category = "focus") isFocusable()12707 public final boolean isFocusable() { 12708 return FOCUSABLE == (mViewFlags & FOCUSABLE); 12709 } 12710 12711 /** 12712 * Returns the focusable setting for this view. 12713 * 12714 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 12715 * @attr ref android.R.styleable#View_focusable 12716 */ 12717 @ViewDebug.ExportedProperty(mapping = { 12718 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 12719 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 12720 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 12721 }, category = "focus") 12722 @InspectableProperty(enumMapping = { 12723 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 12724 @EnumEntry(value = FOCUSABLE, name = "true"), 12725 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 12726 }) 12727 @Focusable getFocusable()12728 public int getFocusable() { 12729 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 12730 } 12731 12732 /** 12733 * When a view is focusable, it may not want to take focus when in touch mode. 12734 * For example, a button would like focus when the user is navigating via a D-pad 12735 * so that the user can click on it, but once the user starts touching the screen, 12736 * the button shouldn't take focus 12737 * @return Whether the view is focusable in touch mode. 12738 * @attr ref android.R.styleable#View_focusableInTouchMode 12739 */ 12740 @ViewDebug.ExportedProperty(category = "focus") 12741 @InspectableProperty isFocusableInTouchMode()12742 public final boolean isFocusableInTouchMode() { 12743 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 12744 } 12745 12746 /** 12747 * Returns whether the view should be treated as a focusable unit by screen reader 12748 * accessibility tools. 12749 * @see #setScreenReaderFocusable(boolean) 12750 * 12751 * @return Whether the view should be treated as a focusable unit by screen reader. 12752 * 12753 * @attr ref android.R.styleable#View_screenReaderFocusable 12754 */ 12755 @InspectableProperty isScreenReaderFocusable()12756 public boolean isScreenReaderFocusable() { 12757 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 12758 } 12759 12760 /** 12761 * Sets whether this View should be a focusable element for screen readers 12762 * and include non-focusable Views from its subtree when providing feedback. 12763 * <p> 12764 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 12765 * but does not impact input focus behavior. 12766 * 12767 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 12768 * accessibility tools. 12769 * 12770 * @attr ref android.R.styleable#View_screenReaderFocusable 12771 */ setScreenReaderFocusable(boolean screenReaderFocusable)12772 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 12773 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 12774 } 12775 12776 /** 12777 * Gets whether this view is a heading for accessibility purposes. 12778 * 12779 * @return {@code true} if the view is a heading, {@code false} otherwise. 12780 * 12781 * @attr ref android.R.styleable#View_accessibilityHeading 12782 */ 12783 @InspectableProperty isAccessibilityHeading()12784 public boolean isAccessibilityHeading() { 12785 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 12786 } 12787 12788 /** 12789 * Set if view is a heading for a section of content for accessibility purposes. 12790 * 12791 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 12792 * 12793 * @attr ref android.R.styleable#View_accessibilityHeading 12794 */ setAccessibilityHeading(boolean isHeading)12795 public void setAccessibilityHeading(boolean isHeading) { 12796 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 12797 } 12798 updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue)12799 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 12800 int pflags3 = mPrivateFlags3; 12801 if (newValue) { 12802 pflags3 |= mask; 12803 } else { 12804 pflags3 &= ~mask; 12805 } 12806 12807 if (pflags3 != mPrivateFlags3) { 12808 mPrivateFlags3 = pflags3; 12809 notifyViewAccessibilityStateChangedIfNeeded( 12810 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12811 } 12812 } 12813 12814 /** 12815 * Find the nearest view in the specified direction that can take focus. 12816 * This does not actually give focus to that view. 12817 * 12818 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12819 * 12820 * @return The nearest focusable in the specified direction, or null if none 12821 * can be found. 12822 */ focusSearch(@ocusRealDirection int direction)12823 public View focusSearch(@FocusRealDirection int direction) { 12824 if (mParent != null) { 12825 return mParent.focusSearch(this, direction); 12826 } else { 12827 return null; 12828 } 12829 } 12830 12831 /** 12832 * Returns whether this View is a root of a keyboard navigation cluster. 12833 * 12834 * @return True if this view is a root of a cluster, or false otherwise. 12835 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12836 */ 12837 @ViewDebug.ExportedProperty(category = "focus") 12838 @InspectableProperty isKeyboardNavigationCluster()12839 public final boolean isKeyboardNavigationCluster() { 12840 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 12841 } 12842 12843 /** 12844 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 12845 * will be ignored. 12846 * 12847 * @return the keyboard navigation cluster that this view is in (can be this view) 12848 * or {@code null} if not in one 12849 */ findKeyboardNavigationCluster()12850 View findKeyboardNavigationCluster() { 12851 if (mParent instanceof View) { 12852 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 12853 if (cluster != null) { 12854 return cluster; 12855 } else if (isKeyboardNavigationCluster()) { 12856 return this; 12857 } 12858 } 12859 return null; 12860 } 12861 12862 /** 12863 * Set whether this view is a root of a keyboard navigation cluster. 12864 * 12865 * @param isCluster If true, this view is a root of a cluster. 12866 * 12867 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12868 */ setKeyboardNavigationCluster(boolean isCluster)12869 public void setKeyboardNavigationCluster(boolean isCluster) { 12870 if (isCluster) { 12871 mPrivateFlags3 |= PFLAG3_CLUSTER; 12872 } else { 12873 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 12874 } 12875 } 12876 12877 /** 12878 * Sets this View as the one which receives focus the next time cluster navigation jumps 12879 * to the cluster containing this View. This does NOT change focus even if the cluster 12880 * containing this view is current. 12881 * 12882 * @hide 12883 */ 12884 @TestApi setFocusedInCluster()12885 public final void setFocusedInCluster() { 12886 setFocusedInCluster(findKeyboardNavigationCluster()); 12887 } 12888 setFocusedInCluster(View cluster)12889 private void setFocusedInCluster(View cluster) { 12890 if (this instanceof ViewGroup) { 12891 ((ViewGroup) this).mFocusedInCluster = null; 12892 } 12893 if (cluster == this) { 12894 return; 12895 } 12896 ViewParent parent = mParent; 12897 View child = this; 12898 while (parent instanceof ViewGroup) { 12899 ((ViewGroup) parent).mFocusedInCluster = child; 12900 if (parent == cluster) { 12901 break; 12902 } 12903 child = (View) parent; 12904 parent = parent.getParent(); 12905 } 12906 } 12907 updateFocusedInCluster(View oldFocus, @FocusDirection int direction)12908 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 12909 if (oldFocus != null) { 12910 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 12911 View cluster = findKeyboardNavigationCluster(); 12912 if (oldCluster != cluster) { 12913 // Going from one cluster to another, so save last-focused. 12914 // This covers cluster jumps because they are always FOCUS_DOWN 12915 oldFocus.setFocusedInCluster(oldCluster); 12916 if (!(oldFocus.mParent instanceof ViewGroup)) { 12917 return; 12918 } 12919 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 12920 // This is a result of ordered navigation so consider navigation through 12921 // the previous cluster "complete" and clear its last-focused memory. 12922 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12923 } else if (oldFocus instanceof ViewGroup 12924 && ((ViewGroup) oldFocus).getDescendantFocusability() 12925 == ViewGroup.FOCUS_AFTER_DESCENDANTS 12926 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 12927 // This means oldFocus is not focusable since it obviously has a focusable 12928 // child (this). Don't restore focus to it in the future. 12929 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12930 } 12931 } 12932 } 12933 } 12934 12935 /** 12936 * Returns whether this View should receive focus when the focus is restored for the view 12937 * hierarchy containing this view. 12938 * <p> 12939 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12940 * window or serves as a target of cluster navigation. 12941 * 12942 * @see #restoreDefaultFocus() 12943 * 12944 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 12945 * @attr ref android.R.styleable#View_focusedByDefault 12946 */ 12947 @ViewDebug.ExportedProperty(category = "focus") 12948 @InspectableProperty isFocusedByDefault()12949 public final boolean isFocusedByDefault() { 12950 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 12951 } 12952 12953 /** 12954 * Sets whether this View should receive focus when the focus is restored for the view 12955 * hierarchy containing this view. 12956 * <p> 12957 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12958 * window or serves as a target of cluster navigation. 12959 * 12960 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 12961 * {@code false} otherwise. 12962 * 12963 * @see #restoreDefaultFocus() 12964 * 12965 * @attr ref android.R.styleable#View_focusedByDefault 12966 */ 12967 @RemotableViewMethod setFocusedByDefault(boolean isFocusedByDefault)12968 public void setFocusedByDefault(boolean isFocusedByDefault) { 12969 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 12970 return; 12971 } 12972 12973 if (isFocusedByDefault) { 12974 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 12975 } else { 12976 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 12977 } 12978 12979 if (mParent instanceof ViewGroup) { 12980 if (isFocusedByDefault) { 12981 ((ViewGroup) mParent).setDefaultFocus(this); 12982 } else { 12983 ((ViewGroup) mParent).clearDefaultFocus(this); 12984 } 12985 } 12986 } 12987 12988 /** 12989 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 12990 * 12991 * @return {@code true} if this view has default focus, {@code false} otherwise 12992 */ hasDefaultFocus()12993 boolean hasDefaultFocus() { 12994 return isFocusedByDefault(); 12995 } 12996 12997 /** 12998 * Find the nearest keyboard navigation cluster in the specified direction. 12999 * This does not actually give focus to that cluster. 13000 * 13001 * @param currentCluster The starting point of the search. Null means the current cluster is not 13002 * found yet 13003 * @param direction Direction to look 13004 * 13005 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 13006 * can be found 13007 */ keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)13008 public View keyboardNavigationClusterSearch(View currentCluster, 13009 @FocusDirection int direction) { 13010 if (isKeyboardNavigationCluster()) { 13011 currentCluster = this; 13012 } 13013 if (isRootNamespace()) { 13014 // Root namespace means we should consider ourselves the top of the 13015 // tree for group searching; otherwise we could be group searching 13016 // into other tabs. see LocalActivityManager and TabHost for more info. 13017 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 13018 this, currentCluster, direction); 13019 } else if (mParent != null) { 13020 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 13021 } 13022 return null; 13023 } 13024 13025 /** 13026 * This method is the last chance for the focused view and its ancestors to 13027 * respond to an arrow key. This is called when the focused view did not 13028 * consume the key internally, nor could the view system find a new view in 13029 * the requested direction to give focus to. 13030 * 13031 * @param focused The currently focused view. 13032 * @param direction The direction focus wants to move. One of FOCUS_UP, 13033 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 13034 * @return True if the this view consumed this unhandled move. 13035 */ dispatchUnhandledMove(View focused, @FocusRealDirection int direction)13036 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 13037 return false; 13038 } 13039 13040 /** 13041 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 13042 * have {@link android.R.attr#state_focused} defined in its background. 13043 * 13044 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 13045 * highlight, {@code false} otherwise. 13046 * 13047 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 13048 */ setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled)13049 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 13050 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 13051 } 13052 13053 /** 13054 13055 /** 13056 * Returns whether this View should use a default focus highlight when it gets focused but 13057 * doesn't have {@link android.R.attr#state_focused} defined in its background. 13058 * 13059 * @return True if this View should use a default focus highlight. 13060 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 13061 */ 13062 @ViewDebug.ExportedProperty(category = "focus") 13063 @InspectableProperty getDefaultFocusHighlightEnabled()13064 public final boolean getDefaultFocusHighlightEnabled() { 13065 return mDefaultFocusHighlightEnabled; 13066 } 13067 13068 /** 13069 * If a user manually specified the next view id for a particular direction, 13070 * use the root to look up the view. 13071 * @param root The root view of the hierarchy containing this view. 13072 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 13073 * or FOCUS_BACKWARD. 13074 * @return The user specified next view, or null if there is none. 13075 */ findUserSetNextFocus(View root, @FocusDirection int direction)13076 View findUserSetNextFocus(View root, @FocusDirection int direction) { 13077 switch (direction) { 13078 case FOCUS_LEFT: 13079 if (mNextFocusLeftId == View.NO_ID) return null; 13080 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 13081 case FOCUS_RIGHT: 13082 if (mNextFocusRightId == View.NO_ID) return null; 13083 return findViewInsideOutShouldExist(root, mNextFocusRightId); 13084 case FOCUS_UP: 13085 if (mNextFocusUpId == View.NO_ID) return null; 13086 return findViewInsideOutShouldExist(root, mNextFocusUpId); 13087 case FOCUS_DOWN: 13088 if (mNextFocusDownId == View.NO_ID) return null; 13089 return findViewInsideOutShouldExist(root, mNextFocusDownId); 13090 case FOCUS_FORWARD: 13091 if (mNextFocusForwardId == View.NO_ID) return null; 13092 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 13093 case FOCUS_BACKWARD: { 13094 if (mID == View.NO_ID) return null; 13095 final View rootView = root; 13096 final View startView = this; 13097 // Since we have forward links but no backward links, we need to find the view that 13098 // forward links to this view. We can't just find the view with the specified ID 13099 // because view IDs need not be unique throughout the tree. 13100 return root.findViewByPredicateInsideOut(startView, 13101 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 13102 == startView); 13103 } 13104 } 13105 return null; 13106 } 13107 13108 /** 13109 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 13110 * use the root to look up the view. 13111 * 13112 * @param root the root view of the hierarchy containing this view 13113 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 13114 * @return the user-specified next cluster, or {@code null} if there is none 13115 */ findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction)13116 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 13117 switch (direction) { 13118 case FOCUS_FORWARD: 13119 if (mNextClusterForwardId == View.NO_ID) return null; 13120 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 13121 case FOCUS_BACKWARD: { 13122 if (mID == View.NO_ID) return null; 13123 final int id = mID; 13124 return root.findViewByPredicateInsideOut(this, 13125 (Predicate<View>) t -> t.mNextClusterForwardId == id); 13126 } 13127 } 13128 return null; 13129 } 13130 findViewInsideOutShouldExist(View root, int id)13131 private View findViewInsideOutShouldExist(View root, int id) { 13132 return findViewInsideOutShouldExist(root, this, id); 13133 } 13134 findViewInsideOutShouldExist(View root, View start, int id)13135 private View findViewInsideOutShouldExist(View root, View start, int id) { 13136 if (mMatchIdPredicate == null) { 13137 mMatchIdPredicate = new MatchIdPredicate(); 13138 } 13139 mMatchIdPredicate.mId = id; 13140 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 13141 if (result == null) { 13142 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 13143 } 13144 return result; 13145 } 13146 13147 /** 13148 * Find and return all focusable views that are descendants of this view, 13149 * possibly including this view if it is focusable itself. 13150 * 13151 * @param direction The direction of the focus 13152 * @return A list of focusable views 13153 */ getFocusables(@ocusDirection int direction)13154 public ArrayList<View> getFocusables(@FocusDirection int direction) { 13155 ArrayList<View> result = new ArrayList<View>(24); 13156 addFocusables(result, direction); 13157 return result; 13158 } 13159 13160 /** 13161 * Add any focusable views that are descendants of this view (possibly 13162 * including this view if it is focusable itself) to views. If we are in touch mode, 13163 * only add views that are also focusable in touch mode. 13164 * 13165 * @param views Focusable views found so far 13166 * @param direction The direction of the focus 13167 */ addFocusables(ArrayList<View> views, @FocusDirection int direction)13168 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 13169 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 13170 } 13171 13172 /** 13173 * Adds any focusable views that are descendants of this view (possibly 13174 * including this view if it is focusable itself) to views. This method 13175 * adds all focusable views regardless if we are in touch mode or 13176 * only views focusable in touch mode if we are in touch mode or 13177 * only views that can take accessibility focus if accessibility is enabled 13178 * depending on the focusable mode parameter. 13179 * 13180 * @param views Focusable views found so far or null if all we are interested is 13181 * the number of focusables. 13182 * @param direction The direction of the focus. 13183 * @param focusableMode The type of focusables to be added. 13184 * 13185 * @see #FOCUSABLES_ALL 13186 * @see #FOCUSABLES_TOUCH_MODE 13187 */ addFocusables(ArrayList<View> views, @FocusDirection int direction, @FocusableMode int focusableMode)13188 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 13189 @FocusableMode int focusableMode) { 13190 if (views == null) { 13191 return; 13192 } 13193 if (!canTakeFocus()) { 13194 return; 13195 } 13196 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 13197 && !isFocusableInTouchMode()) { 13198 return; 13199 } 13200 views.add(this); 13201 } 13202 13203 /** 13204 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 13205 * including this view if it is a cluster root itself) to views. 13206 * 13207 * @param views Keyboard navigation cluster roots found so far 13208 * @param direction Direction to look 13209 */ addKeyboardNavigationClusters( @onNull Collection<View> views, int direction)13210 public void addKeyboardNavigationClusters( 13211 @NonNull Collection<View> views, 13212 int direction) { 13213 if (!isKeyboardNavigationCluster()) { 13214 return; 13215 } 13216 if (!hasFocusable()) { 13217 return; 13218 } 13219 views.add(this); 13220 } 13221 13222 /** 13223 * Finds the Views that contain given text. The containment is case insensitive. 13224 * The search is performed by either the text that the View renders or the content 13225 * description that describes the view for accessibility purposes and the view does 13226 * not render or both. Clients can specify how the search is to be performed via 13227 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 13228 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 13229 * 13230 * @param outViews The output list of matching Views. 13231 * @param searched The text to match against. 13232 * 13233 * @see #FIND_VIEWS_WITH_TEXT 13234 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 13235 * @see #setContentDescription(CharSequence) 13236 */ findViewsWithText(ArrayList<View> outViews, CharSequence searched, @FindViewFlags int flags)13237 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 13238 @FindViewFlags int flags) { 13239 if (getAccessibilityNodeProvider() != null) { 13240 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 13241 outViews.add(this); 13242 } 13243 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 13244 && (searched != null && searched.length() > 0) 13245 && (mContentDescription != null && mContentDescription.length() > 0)) { 13246 String searchedLowerCase = searched.toString().toLowerCase(); 13247 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 13248 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 13249 outViews.add(this); 13250 } 13251 } 13252 } 13253 13254 /** 13255 * Find and return all touchable views that are descendants of this view, 13256 * possibly including this view if it is touchable itself. 13257 * 13258 * @return A list of touchable views 13259 */ getTouchables()13260 public ArrayList<View> getTouchables() { 13261 ArrayList<View> result = new ArrayList<View>(); 13262 addTouchables(result); 13263 return result; 13264 } 13265 13266 /** 13267 * Add any touchable views that are descendants of this view (possibly 13268 * including this view if it is touchable itself) to views. 13269 * 13270 * @param views Touchable views found so far 13271 */ addTouchables(ArrayList<View> views)13272 public void addTouchables(ArrayList<View> views) { 13273 final int viewFlags = mViewFlags; 13274 13275 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 13276 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 13277 && (viewFlags & ENABLED_MASK) == ENABLED) { 13278 views.add(this); 13279 } 13280 } 13281 13282 /** 13283 * Returns whether this View is accessibility focused. 13284 * 13285 * @return True if this View is accessibility focused. 13286 */ 13287 @InspectableProperty(hasAttributeId = false) isAccessibilityFocused()13288 public boolean isAccessibilityFocused() { 13289 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 13290 } 13291 13292 /** 13293 * Call this to try to give accessibility focus to this view. 13294 * 13295 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 13296 * returns false or the view is no visible or the view already has accessibility 13297 * focus. 13298 * 13299 * See also {@link #focusSearch(int)}, which is what you call to say that you 13300 * have focus, and you want your parent to look for the next one. 13301 * 13302 * @return Whether this view actually took accessibility focus. 13303 * 13304 * @hide 13305 */ 13306 @UnsupportedAppUsage requestAccessibilityFocus()13307 public boolean requestAccessibilityFocus() { 13308 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 13309 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 13310 return false; 13311 } 13312 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 13313 return false; 13314 } 13315 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 13316 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 13317 ViewRootImpl viewRootImpl = getViewRootImpl(); 13318 if (viewRootImpl != null) { 13319 viewRootImpl.setAccessibilityFocus(this, null); 13320 } 13321 invalidate(); 13322 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 13323 return true; 13324 } 13325 return false; 13326 } 13327 13328 /** 13329 * Call this to try to clear accessibility focus of this view. 13330 * 13331 * See also {@link #focusSearch(int)}, which is what you call to say that you 13332 * have focus, and you want your parent to look for the next one. 13333 * 13334 * @hide 13335 */ 13336 @UnsupportedAppUsage clearAccessibilityFocus()13337 public void clearAccessibilityFocus() { 13338 clearAccessibilityFocusNoCallbacks(0); 13339 13340 // Clear the global reference of accessibility focus if this view or 13341 // any of its descendants had accessibility focus. This will NOT send 13342 // an event or update internal state if focus is cleared from a 13343 // descendant view, which may leave views in inconsistent states. 13344 final ViewRootImpl viewRootImpl = getViewRootImpl(); 13345 if (viewRootImpl != null) { 13346 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 13347 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13348 viewRootImpl.setAccessibilityFocus(null, null); 13349 } 13350 } 13351 } 13352 sendAccessibilityHoverEvent(int eventType)13353 private void sendAccessibilityHoverEvent(int eventType) { 13354 // Since we are not delivering to a client accessibility events from not 13355 // important views (unless the clinet request that) we need to fire the 13356 // event from the deepest view exposed to the client. As a consequence if 13357 // the user crosses a not exposed view the client will see enter and exit 13358 // of the exposed predecessor followed by and enter and exit of that same 13359 // predecessor when entering and exiting the not exposed descendant. This 13360 // is fine since the client has a clear idea which view is hovered at the 13361 // price of a couple more events being sent. This is a simple and 13362 // working solution. 13363 View source = this; 13364 while (true) { 13365 if (source.includeForAccessibility()) { 13366 source.sendAccessibilityEvent(eventType); 13367 return; 13368 } 13369 ViewParent parent = source.getParent(); 13370 if (parent instanceof View) { 13371 source = (View) parent; 13372 } else { 13373 return; 13374 } 13375 } 13376 } 13377 13378 /** 13379 * Clears accessibility focus without calling any callback methods 13380 * normally invoked in {@link #clearAccessibilityFocus()}. This method 13381 * is used separately from that one for clearing accessibility focus when 13382 * giving this focus to another view. 13383 * 13384 * @param action The action, if any, that led to focus being cleared. Set to 13385 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 13386 * the window. 13387 */ clearAccessibilityFocusNoCallbacks(int action)13388 void clearAccessibilityFocusNoCallbacks(int action) { 13389 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 13390 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 13391 invalidate(); 13392 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13393 AccessibilityEvent event = AccessibilityEvent.obtain( 13394 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 13395 event.setAction(action); 13396 if (mAccessibilityDelegate != null) { 13397 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 13398 } else { 13399 sendAccessibilityEventUnchecked(event); 13400 } 13401 } 13402 } 13403 } 13404 13405 /** 13406 * Call this to try to give focus to a specific view or to one of its 13407 * descendants. 13408 * 13409 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13410 * false), or if it can't be focused due to other conditions (not focusable in touch mode 13411 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 13412 * enabled, or has no size). 13413 * 13414 * See also {@link #focusSearch(int)}, which is what you call to say that you 13415 * have focus, and you want your parent to look for the next one. 13416 * 13417 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 13418 * {@link #FOCUS_DOWN} and <code>null</code>. 13419 * 13420 * @return Whether this view or one of its descendants actually took focus. 13421 */ requestFocus()13422 public final boolean requestFocus() { 13423 return requestFocus(View.FOCUS_DOWN); 13424 } 13425 13426 /** 13427 * This will request focus for whichever View was last focused within this 13428 * cluster before a focus-jump out of it. 13429 * 13430 * @hide 13431 */ 13432 @TestApi restoreFocusInCluster(@ocusRealDirection int direction)13433 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 13434 // Prioritize focusableByDefault over algorithmic focus selection. 13435 if (restoreDefaultFocus()) { 13436 return true; 13437 } 13438 return requestFocus(direction); 13439 } 13440 13441 /** 13442 * This will request focus for whichever View not in a cluster was last focused before a 13443 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 13444 * the "first" focusable view it finds. 13445 * 13446 * @hide 13447 */ 13448 @TestApi restoreFocusNotInCluster()13449 public boolean restoreFocusNotInCluster() { 13450 return requestFocus(View.FOCUS_DOWN); 13451 } 13452 13453 /** 13454 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 13455 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 13456 * 13457 * @return Whether this view or one of its descendants actually took focus 13458 */ restoreDefaultFocus()13459 public boolean restoreDefaultFocus() { 13460 return requestFocus(View.FOCUS_DOWN); 13461 } 13462 13463 /** 13464 * Call this to try to give focus to a specific view or to one of its 13465 * descendants and give it a hint about what direction focus is heading. 13466 * 13467 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13468 * false), or if it is focusable and it is not focusable in touch mode 13469 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13470 * 13471 * See also {@link #focusSearch(int)}, which is what you call to say that you 13472 * have focus, and you want your parent to look for the next one. 13473 * 13474 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 13475 * <code>null</code> set for the previously focused rectangle. 13476 * 13477 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13478 * @return Whether this view or one of its descendants actually took focus. 13479 */ requestFocus(int direction)13480 public final boolean requestFocus(int direction) { 13481 return requestFocus(direction, null); 13482 } 13483 13484 /** 13485 * Call this to try to give focus to a specific view or to one of its descendants 13486 * and give it hints about the direction and a specific rectangle that the focus 13487 * is coming from. The rectangle can help give larger views a finer grained hint 13488 * about where focus is coming from, and therefore, where to show selection, or 13489 * forward focus change internally. 13490 * 13491 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13492 * false), or if it is focusable and it is not focusable in touch mode 13493 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13494 * 13495 * A View will not take focus if it is not visible. 13496 * 13497 * A View will not take focus if one of its parents has 13498 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 13499 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 13500 * 13501 * See also {@link #focusSearch(int)}, which is what you call to say that you 13502 * have focus, and you want your parent to look for the next one. 13503 * 13504 * You may wish to override this method if your custom {@link View} has an internal 13505 * {@link View} that it wishes to forward the request to. 13506 * 13507 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13508 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 13509 * to give a finer grained hint about where focus is coming from. May be null 13510 * if there is no hint. 13511 * @return Whether this view or one of its descendants actually took focus. 13512 */ requestFocus(int direction, Rect previouslyFocusedRect)13513 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 13514 return requestFocusNoSearch(direction, previouslyFocusedRect); 13515 } 13516 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)13517 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 13518 // need to be focusable 13519 if (!canTakeFocus()) { 13520 return false; 13521 } 13522 13523 // need to be focusable in touch mode if in touch mode 13524 if (isInTouchMode() && 13525 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 13526 return false; 13527 } 13528 13529 // need to not have any parents blocking us 13530 if (hasAncestorThatBlocksDescendantFocus()) { 13531 return false; 13532 } 13533 13534 if (!isLayoutValid()) { 13535 mPrivateFlags |= PFLAG_WANTS_FOCUS; 13536 } else { 13537 clearParentsWantFocus(); 13538 } 13539 13540 handleFocusGainInternal(direction, previouslyFocusedRect); 13541 return true; 13542 } 13543 clearParentsWantFocus()13544 void clearParentsWantFocus() { 13545 if (mParent instanceof View) { 13546 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 13547 ((View) mParent).clearParentsWantFocus(); 13548 } 13549 } 13550 13551 /** 13552 * Call this to try to give focus to a specific view or to one of its descendants. This is a 13553 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 13554 * touch mode to request focus when they are touched. 13555 * 13556 * @return Whether this view or one of its descendants actually took focus. 13557 * 13558 * @see #isInTouchMode() 13559 * 13560 */ requestFocusFromTouch()13561 public final boolean requestFocusFromTouch() { 13562 // Leave touch mode if we need to 13563 if (isInTouchMode()) { 13564 ViewRootImpl viewRoot = getViewRootImpl(); 13565 if (viewRoot != null) { 13566 viewRoot.ensureTouchMode(false); 13567 } 13568 } 13569 return requestFocus(View.FOCUS_DOWN); 13570 } 13571 13572 /** 13573 * @return Whether any ancestor of this view blocks descendant focus. 13574 */ hasAncestorThatBlocksDescendantFocus()13575 private boolean hasAncestorThatBlocksDescendantFocus() { 13576 final boolean focusableInTouchMode = isFocusableInTouchMode(); 13577 ViewParent ancestor = mParent; 13578 while (ancestor instanceof ViewGroup) { 13579 final ViewGroup vgAncestor = (ViewGroup) ancestor; 13580 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 13581 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 13582 return true; 13583 } else { 13584 ancestor = vgAncestor.getParent(); 13585 } 13586 } 13587 return false; 13588 } 13589 13590 /** 13591 * Gets the mode for determining whether this View is important for accessibility. 13592 * A view is important for accessibility if it fires accessibility events and if it 13593 * is reported to accessibility services that query the screen. 13594 * 13595 * @return The mode for determining whether a view is important for accessibility, one 13596 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 13597 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 13598 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 13599 * 13600 * @attr ref android.R.styleable#View_importantForAccessibility 13601 * 13602 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13603 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13604 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13605 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13606 */ 13607 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 13608 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 13609 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 13610 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 13611 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13612 to = "noHideDescendants") 13613 }) 13614 @InspectableProperty(enumMapping = { 13615 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 13616 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 13617 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 13618 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13619 name = "noHideDescendants"), 13620 }) getImportantForAccessibility()13621 public int getImportantForAccessibility() { 13622 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 13623 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 13624 } 13625 13626 /** 13627 * Sets the live region mode for this view. This indicates to accessibility 13628 * services whether they should automatically notify the user about changes 13629 * to the view's content description or text, or to the content descriptions 13630 * or text of the view's children (where applicable). 13631 * <p> 13632 * For example, in a login screen with a TextView that displays an "incorrect 13633 * password" notification, that view should be marked as a live region with 13634 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13635 * <p> 13636 * To disable change notifications for this view, use 13637 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 13638 * mode for most views. 13639 * <p> 13640 * To indicate that the user should be notified of changes, use 13641 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13642 * <p> 13643 * If the view's changes should interrupt ongoing speech and notify the user 13644 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 13645 * 13646 * @param mode The live region mode for this view, one of: 13647 * <ul> 13648 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 13649 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 13650 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 13651 * </ul> 13652 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13653 */ setAccessibilityLiveRegion(int mode)13654 public void setAccessibilityLiveRegion(int mode) { 13655 if (mode != getAccessibilityLiveRegion()) { 13656 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13657 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 13658 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13659 notifyViewAccessibilityStateChangedIfNeeded( 13660 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13661 } 13662 } 13663 13664 /** 13665 * Gets the live region mode for this View. 13666 * 13667 * @return The live region mode for the view. 13668 * 13669 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13670 * 13671 * @see #setAccessibilityLiveRegion(int) 13672 */ 13673 @InspectableProperty(enumMapping = { 13674 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 13675 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 13676 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 13677 }) getAccessibilityLiveRegion()13678 public int getAccessibilityLiveRegion() { 13679 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 13680 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 13681 } 13682 13683 /** 13684 * Sets how to determine whether this view is important for accessibility 13685 * which is if it fires accessibility events and if it is reported to 13686 * accessibility services that query the screen. 13687 * 13688 * @param mode How to determine whether this view is important for accessibility. 13689 * 13690 * @attr ref android.R.styleable#View_importantForAccessibility 13691 * 13692 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13693 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13694 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13695 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13696 */ setImportantForAccessibility(int mode)13697 public void setImportantForAccessibility(int mode) { 13698 final int oldMode = getImportantForAccessibility(); 13699 if (mode != oldMode) { 13700 final boolean hideDescendants = 13701 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 13702 13703 // If this node or its descendants are no longer important, try to 13704 // clear accessibility focus. 13705 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 13706 final View focusHost = findAccessibilityFocusHost(hideDescendants); 13707 if (focusHost != null) { 13708 focusHost.clearAccessibilityFocus(); 13709 } 13710 } 13711 13712 // If we're moving between AUTO and another state, we might not need 13713 // to send a subtree changed notification. We'll store the computed 13714 // importance, since we'll need to check it later to make sure. 13715 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 13716 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 13717 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 13718 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13719 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 13720 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13721 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 13722 notifySubtreeAccessibilityStateChangedIfNeeded(); 13723 } else { 13724 notifyViewAccessibilityStateChangedIfNeeded( 13725 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13726 } 13727 } 13728 } 13729 13730 /** 13731 * Returns the view within this view's hierarchy that is hosting 13732 * accessibility focus. 13733 * 13734 * @param searchDescendants whether to search for focus in descendant views 13735 * @return the view hosting accessibility focus, or {@code null} 13736 */ findAccessibilityFocusHost(boolean searchDescendants)13737 private View findAccessibilityFocusHost(boolean searchDescendants) { 13738 if (isAccessibilityFocusedViewOrHost()) { 13739 return this; 13740 } 13741 13742 if (searchDescendants) { 13743 final ViewRootImpl viewRoot = getViewRootImpl(); 13744 if (viewRoot != null) { 13745 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 13746 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13747 return focusHost; 13748 } 13749 } 13750 } 13751 13752 return null; 13753 } 13754 13755 /** 13756 * Computes whether this view should be exposed for accessibility. In 13757 * general, views that are interactive or provide information are exposed 13758 * while views that serve only as containers are hidden. 13759 * <p> 13760 * If an ancestor of this view has importance 13761 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 13762 * returns <code>false</code>. 13763 * <p> 13764 * Otherwise, the value is computed according to the view's 13765 * {@link #getImportantForAccessibility()} value: 13766 * <ol> 13767 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 13768 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 13769 * </code> 13770 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 13771 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 13772 * view satisfies any of the following: 13773 * <ul> 13774 * <li>Is actionable, e.g. {@link #isClickable()}, 13775 * {@link #isLongClickable()}, or {@link #isFocusable()} 13776 * <li>Has an {@link AccessibilityDelegate} 13777 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 13778 * {@link OnKeyListener}, etc. 13779 * <li>Is an accessibility live region, e.g. 13780 * {@link #getAccessibilityLiveRegion()} is not 13781 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 13782 * </ul> 13783 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 13784 * </ol> 13785 * 13786 * @return Whether the view is exposed for accessibility. 13787 * @see #setImportantForAccessibility(int) 13788 * @see #getImportantForAccessibility() 13789 */ isImportantForAccessibility()13790 public boolean isImportantForAccessibility() { 13791 final int mode = getImportantForAccessibility(); 13792 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 13793 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13794 return false; 13795 } 13796 13797 // Check parent mode to ensure we're not hidden. 13798 ViewParent parent = mParent; 13799 while (parent instanceof View) { 13800 if (((View) parent).getImportantForAccessibility() 13801 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13802 return false; 13803 } 13804 parent = parent.getParent(); 13805 } 13806 13807 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 13808 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 13809 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 13810 || isAccessibilityPane(); 13811 } 13812 13813 /** 13814 * Gets the parent for accessibility purposes. Note that the parent for 13815 * accessibility is not necessary the immediate parent. It is the first 13816 * predecessor that is important for accessibility. 13817 * 13818 * @return The parent for accessibility purposes. 13819 */ getParentForAccessibility()13820 public ViewParent getParentForAccessibility() { 13821 if (mParent instanceof View) { 13822 View parentView = (View) mParent; 13823 if (parentView.includeForAccessibility()) { 13824 return mParent; 13825 } else { 13826 return mParent.getParentForAccessibility(); 13827 } 13828 } 13829 return null; 13830 } 13831 13832 /** @hide */ getSelfOrParentImportantForA11y()13833 View getSelfOrParentImportantForA11y() { 13834 if (isImportantForAccessibility()) return this; 13835 ViewParent parent = getParentForAccessibility(); 13836 if (parent instanceof View) return (View) parent; 13837 return null; 13838 } 13839 13840 /** 13841 * Adds the children of this View relevant for accessibility to the given list 13842 * as output. Since some Views are not important for accessibility the added 13843 * child views are not necessarily direct children of this view, rather they are 13844 * the first level of descendants important for accessibility. 13845 * 13846 * @param outChildren The output list that will receive children for accessibility. 13847 */ addChildrenForAccessibility(ArrayList<View> outChildren)13848 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 13849 13850 } 13851 13852 /** 13853 * Whether to regard this view for accessibility. A view is regarded for 13854 * accessibility if it is important for accessibility or the querying 13855 * accessibility service has explicitly requested that view not 13856 * important for accessibility are regarded. 13857 * 13858 * @return Whether to regard the view for accessibility. 13859 * 13860 * @hide 13861 */ 13862 @UnsupportedAppUsage includeForAccessibility()13863 public boolean includeForAccessibility() { 13864 if (mAttachInfo != null) { 13865 return (mAttachInfo.mAccessibilityFetchFlags 13866 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 13867 || isImportantForAccessibility(); 13868 } 13869 return false; 13870 } 13871 13872 /** 13873 * Returns whether the View is considered actionable from 13874 * accessibility perspective. Such view are important for 13875 * accessibility. 13876 * 13877 * @return True if the view is actionable for accessibility. 13878 * 13879 * @hide 13880 */ isActionableForAccessibility()13881 public boolean isActionableForAccessibility() { 13882 return (isClickable() || isLongClickable() || isFocusable()); 13883 } 13884 13885 /** 13886 * Returns whether the View has registered callbacks which makes it 13887 * important for accessibility. 13888 * 13889 * @return True if the view is actionable for accessibility. 13890 */ hasListenersForAccessibility()13891 private boolean hasListenersForAccessibility() { 13892 ListenerInfo info = getListenerInfo(); 13893 return mTouchDelegate != null || info.mOnKeyListener != null 13894 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 13895 || info.mOnHoverListener != null || info.mOnDragListener != null; 13896 } 13897 13898 /** 13899 * Notifies that the accessibility state of this view changed. The change 13900 * is local to this view and does not represent structural changes such 13901 * as children and parent. For example, the view became focusable. The 13902 * notification is at at most once every 13903 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13904 * to avoid unnecessary load to the system. Also once a view has a pending 13905 * notification this method is a NOP until the notification has been sent. 13906 * 13907 * @hide 13908 */ 13909 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) notifyViewAccessibilityStateChangedIfNeeded(int changeType)13910 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 13911 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13912 return; 13913 } 13914 13915 // Changes to views with a pane title count as window state changes, as the pane title 13916 // marks them as significant parts of the UI. 13917 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 13918 && isAccessibilityPane()) { 13919 // If the pane isn't visible, content changed events are sufficient unless we're 13920 // reporting that the view just disappeared 13921 if ((getVisibility() == VISIBLE) 13922 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 13923 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13924 onInitializeAccessibilityEvent(event); 13925 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 13926 event.setContentChangeTypes(changeType); 13927 event.setSource(this); 13928 onPopulateAccessibilityEvent(event); 13929 if (mParent != null) { 13930 try { 13931 mParent.requestSendAccessibilityEvent(this, event); 13932 } catch (AbstractMethodError e) { 13933 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 13934 + " does not fully implement ViewParent", e); 13935 } 13936 } 13937 return; 13938 } 13939 } 13940 13941 // If this is a live region, we should send a subtree change event 13942 // from this view immediately. Otherwise, we can let it propagate up. 13943 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 13944 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13945 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 13946 event.setContentChangeTypes(changeType); 13947 sendAccessibilityEventUnchecked(event); 13948 } else if (mParent != null) { 13949 try { 13950 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 13951 } catch (AbstractMethodError e) { 13952 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13953 " does not fully implement ViewParent", e); 13954 } 13955 } 13956 } 13957 13958 /** 13959 * Notifies that the accessibility state of this view changed. The change 13960 * is *not* local to this view and does represent structural changes such 13961 * as children and parent. For example, the view size changed. The 13962 * notification is at at most once every 13963 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13964 * to avoid unnecessary load to the system. Also once a view has a pending 13965 * notification this method is a NOP until the notification has been sent. 13966 * 13967 * @hide 13968 */ 13969 @UnsupportedAppUsage notifySubtreeAccessibilityStateChangedIfNeeded()13970 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 13971 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13972 return; 13973 } 13974 13975 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 13976 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 13977 if (mParent != null) { 13978 try { 13979 mParent.notifySubtreeAccessibilityStateChanged( 13980 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 13981 } catch (AbstractMethodError e) { 13982 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13983 " does not fully implement ViewParent", e); 13984 } 13985 } 13986 } 13987 } 13988 notifySubtreeAccessibilityStateChangedByParentIfNeeded()13989 private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { 13990 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 13991 return; 13992 } 13993 13994 final View sendA11yEventView = (View) getParentForAccessibility(); 13995 if (sendA11yEventView != null && sendA11yEventView.isShown()) { 13996 sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); 13997 } 13998 } 13999 14000 /** 14001 * Changes the visibility of this View without triggering any other changes. This should only 14002 * be used by animation frameworks, such as {@link android.transition.Transition}, where 14003 * visibility changes should not adjust focus or trigger a new layout. Application developers 14004 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 14005 * 14006 * <p>Only call this method when a temporary visibility must be applied during an 14007 * animation and the original visibility value is guaranteed to be reset after the 14008 * animation completes. Use {@link #setVisibility} in all other cases.</p> 14009 * 14010 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 14011 * @see #setVisibility(int) 14012 */ setTransitionVisibility(@isibility int visibility)14013 public void setTransitionVisibility(@Visibility int visibility) { 14014 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 14015 } 14016 14017 /** 14018 * Reset the flag indicating the accessibility state of the subtree rooted 14019 * at this view changed. 14020 */ resetSubtreeAccessibilityStateChanged()14021 void resetSubtreeAccessibilityStateChanged() { 14022 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 14023 } 14024 14025 /** 14026 * Report an accessibility action to this view's parents for delegated processing. 14027 * 14028 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 14029 * call this method to delegate an accessibility action to a supporting parent. If the parent 14030 * returns true from its 14031 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 14032 * method this method will return true to signify that the action was consumed.</p> 14033 * 14034 * <p>This method is useful for implementing nested scrolling child views. If 14035 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 14036 * a custom view implementation may invoke this method to allow a parent to consume the 14037 * scroll first. If this method returns true the custom view should skip its own scrolling 14038 * behavior.</p> 14039 * 14040 * @param action Accessibility action to delegate 14041 * @param arguments Optional action arguments 14042 * @return true if the action was consumed by a parent 14043 */ dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments)14044 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 14045 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 14046 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 14047 return true; 14048 } 14049 } 14050 return false; 14051 } 14052 14053 /** 14054 * Performs the specified accessibility action on the view. For 14055 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 14056 * <p> 14057 * If an {@link AccessibilityDelegate} has been specified via calling 14058 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 14059 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 14060 * is responsible for handling this call. 14061 * </p> 14062 * 14063 * <p>The default implementation will delegate 14064 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 14065 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 14066 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 14067 * 14068 * @param action The action to perform. 14069 * @param arguments Optional action arguments. 14070 * @return Whether the action was performed. 14071 */ performAccessibilityAction(int action, Bundle arguments)14072 public boolean performAccessibilityAction(int action, Bundle arguments) { 14073 if (mAccessibilityDelegate != null) { 14074 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 14075 } else { 14076 return performAccessibilityActionInternal(action, arguments); 14077 } 14078 } 14079 14080 /** 14081 * @see #performAccessibilityAction(int, Bundle) 14082 * 14083 * Note: Called from the default {@link AccessibilityDelegate}. 14084 * 14085 * @hide 14086 */ 14087 @UnsupportedAppUsage performAccessibilityActionInternal(int action, Bundle arguments)14088 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 14089 if (isNestedScrollingEnabled() 14090 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 14091 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 14092 || action == R.id.accessibilityActionScrollUp 14093 || action == R.id.accessibilityActionScrollLeft 14094 || action == R.id.accessibilityActionScrollDown 14095 || action == R.id.accessibilityActionScrollRight)) { 14096 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 14097 return true; 14098 } 14099 } 14100 14101 switch (action) { 14102 case AccessibilityNodeInfo.ACTION_CLICK: { 14103 if (isClickable()) { 14104 performClickInternal(); 14105 return true; 14106 } 14107 } break; 14108 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 14109 if (isLongClickable()) { 14110 performLongClick(); 14111 return true; 14112 } 14113 } break; 14114 case AccessibilityNodeInfo.ACTION_FOCUS: { 14115 if (!hasFocus()) { 14116 // Get out of touch mode since accessibility 14117 // wants to move focus around. 14118 getViewRootImpl().ensureTouchMode(false); 14119 return requestFocus(); 14120 } 14121 } break; 14122 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 14123 if (hasFocus()) { 14124 clearFocus(); 14125 return !isFocused(); 14126 } 14127 } break; 14128 case AccessibilityNodeInfo.ACTION_SELECT: { 14129 if (!isSelected()) { 14130 setSelected(true); 14131 return isSelected(); 14132 } 14133 } break; 14134 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 14135 if (isSelected()) { 14136 setSelected(false); 14137 return !isSelected(); 14138 } 14139 } break; 14140 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 14141 if (!isAccessibilityFocused()) { 14142 return requestAccessibilityFocus(); 14143 } 14144 } break; 14145 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 14146 if (isAccessibilityFocused()) { 14147 clearAccessibilityFocus(); 14148 return true; 14149 } 14150 } break; 14151 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 14152 if (arguments != null) { 14153 final int granularity = arguments.getInt( 14154 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 14155 final boolean extendSelection = arguments.getBoolean( 14156 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 14157 return traverseAtGranularity(granularity, true, extendSelection); 14158 } 14159 } break; 14160 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 14161 if (arguments != null) { 14162 final int granularity = arguments.getInt( 14163 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 14164 final boolean extendSelection = arguments.getBoolean( 14165 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 14166 return traverseAtGranularity(granularity, false, extendSelection); 14167 } 14168 } break; 14169 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 14170 CharSequence text = getIterableTextForAccessibility(); 14171 if (text == null) { 14172 return false; 14173 } 14174 final int start = (arguments != null) ? arguments.getInt( 14175 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 14176 final int end = (arguments != null) ? arguments.getInt( 14177 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 14178 // Only cursor position can be specified (selection length == 0) 14179 if ((getAccessibilitySelectionStart() != start 14180 || getAccessibilitySelectionEnd() != end) 14181 && (start == end)) { 14182 setAccessibilitySelection(start, end); 14183 notifyViewAccessibilityStateChangedIfNeeded( 14184 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14185 return true; 14186 } 14187 } break; 14188 case R.id.accessibilityActionShowOnScreen: { 14189 if (mAttachInfo != null) { 14190 final Rect r = mAttachInfo.mTmpInvalRect; 14191 getDrawingRect(r); 14192 return requestRectangleOnScreen(r, true); 14193 } 14194 } break; 14195 case R.id.accessibilityActionContextClick: { 14196 if (isContextClickable()) { 14197 performContextClick(); 14198 return true; 14199 } 14200 } break; 14201 case R.id.accessibilityActionShowTooltip: { 14202 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 14203 // Tooltip already showing 14204 return false; 14205 } 14206 return showLongClickTooltip(0, 0); 14207 } 14208 case R.id.accessibilityActionHideTooltip: { 14209 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 14210 // No tooltip showing 14211 return false; 14212 } 14213 hideTooltip(); 14214 return true; 14215 } 14216 } 14217 return false; 14218 } 14219 traverseAtGranularity(int granularity, boolean forward, boolean extendSelection)14220 private boolean traverseAtGranularity(int granularity, boolean forward, 14221 boolean extendSelection) { 14222 CharSequence text = getIterableTextForAccessibility(); 14223 if (text == null || text.length() == 0) { 14224 return false; 14225 } 14226 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 14227 if (iterator == null) { 14228 return false; 14229 } 14230 int current = getAccessibilitySelectionEnd(); 14231 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14232 current = forward ? 0 : text.length(); 14233 } 14234 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 14235 if (range == null) { 14236 return false; 14237 } 14238 final int segmentStart = range[0]; 14239 final int segmentEnd = range[1]; 14240 int selectionStart; 14241 int selectionEnd; 14242 if (extendSelection && isAccessibilitySelectionExtendable()) { 14243 selectionStart = getAccessibilitySelectionStart(); 14244 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14245 selectionStart = forward ? segmentStart : segmentEnd; 14246 } 14247 selectionEnd = forward ? segmentEnd : segmentStart; 14248 } else { 14249 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 14250 } 14251 setAccessibilitySelection(selectionStart, selectionEnd); 14252 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 14253 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 14254 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 14255 return true; 14256 } 14257 14258 /** 14259 * Gets the text reported for accessibility purposes. 14260 * 14261 * @return The accessibility text. 14262 * 14263 * @hide 14264 */ 14265 @UnsupportedAppUsage getIterableTextForAccessibility()14266 public CharSequence getIterableTextForAccessibility() { 14267 return getContentDescription(); 14268 } 14269 14270 /** 14271 * Gets whether accessibility selection can be extended. 14272 * 14273 * @return If selection is extensible. 14274 * 14275 * @hide 14276 */ isAccessibilitySelectionExtendable()14277 public boolean isAccessibilitySelectionExtendable() { 14278 return false; 14279 } 14280 14281 /** 14282 * @hide 14283 */ getAccessibilitySelectionStart()14284 public int getAccessibilitySelectionStart() { 14285 return mAccessibilityCursorPosition; 14286 } 14287 14288 /** 14289 * @hide 14290 */ getAccessibilitySelectionEnd()14291 public int getAccessibilitySelectionEnd() { 14292 return getAccessibilitySelectionStart(); 14293 } 14294 14295 /** 14296 * @hide 14297 */ setAccessibilitySelection(int start, int end)14298 public void setAccessibilitySelection(int start, int end) { 14299 if (start == end && end == mAccessibilityCursorPosition) { 14300 return; 14301 } 14302 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 14303 mAccessibilityCursorPosition = start; 14304 } else { 14305 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 14306 } 14307 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 14308 } 14309 sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex)14310 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 14311 int fromIndex, int toIndex) { 14312 if (mParent == null) { 14313 return; 14314 } 14315 AccessibilityEvent event = AccessibilityEvent.obtain( 14316 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 14317 onInitializeAccessibilityEvent(event); 14318 onPopulateAccessibilityEvent(event); 14319 event.setFromIndex(fromIndex); 14320 event.setToIndex(toIndex); 14321 event.setAction(action); 14322 event.setMovementGranularity(granularity); 14323 mParent.requestSendAccessibilityEvent(this, event); 14324 } 14325 14326 /** 14327 * @hide 14328 */ 14329 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getIteratorForGranularity(int granularity)14330 public TextSegmentIterator getIteratorForGranularity(int granularity) { 14331 switch (granularity) { 14332 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 14333 CharSequence text = getIterableTextForAccessibility(); 14334 if (text != null && text.length() > 0) { 14335 CharacterTextSegmentIterator iterator = 14336 CharacterTextSegmentIterator.getInstance( 14337 mContext.getResources().getConfiguration().locale); 14338 iterator.initialize(text.toString()); 14339 return iterator; 14340 } 14341 } break; 14342 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 14343 CharSequence text = getIterableTextForAccessibility(); 14344 if (text != null && text.length() > 0) { 14345 WordTextSegmentIterator iterator = 14346 WordTextSegmentIterator.getInstance( 14347 mContext.getResources().getConfiguration().locale); 14348 iterator.initialize(text.toString()); 14349 return iterator; 14350 } 14351 } break; 14352 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 14353 CharSequence text = getIterableTextForAccessibility(); 14354 if (text != null && text.length() > 0) { 14355 ParagraphTextSegmentIterator iterator = 14356 ParagraphTextSegmentIterator.getInstance(); 14357 iterator.initialize(text.toString()); 14358 return iterator; 14359 } 14360 } break; 14361 } 14362 return null; 14363 } 14364 14365 /** 14366 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 14367 * and {@link #onFinishTemporaryDetach()}. 14368 * 14369 * <p>This method always returns {@code true} when called directly or indirectly from 14370 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 14371 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 14372 * <ul> 14373 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 14374 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 14375 * </ul> 14376 * </p> 14377 * 14378 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 14379 * and {@link #onFinishTemporaryDetach()}. 14380 */ isTemporarilyDetached()14381 public final boolean isTemporarilyDetached() { 14382 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 14383 } 14384 14385 /** 14386 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 14387 * a container View. 14388 */ 14389 @CallSuper dispatchStartTemporaryDetach()14390 public void dispatchStartTemporaryDetach() { 14391 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 14392 notifyEnterOrExitForAutoFillIfNeeded(false); 14393 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 14394 onStartTemporaryDetach(); 14395 } 14396 14397 /** 14398 * This is called when a container is going to temporarily detach a child, with 14399 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 14400 * It will either be followed by {@link #onFinishTemporaryDetach()} or 14401 * {@link #onDetachedFromWindow()} when the container is done. 14402 */ onStartTemporaryDetach()14403 public void onStartTemporaryDetach() { 14404 removeUnsetPressCallback(); 14405 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 14406 } 14407 14408 /** 14409 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 14410 * a container View. 14411 */ 14412 @CallSuper dispatchFinishTemporaryDetach()14413 public void dispatchFinishTemporaryDetach() { 14414 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 14415 onFinishTemporaryDetach(); 14416 if (hasWindowFocus() && hasFocus()) { 14417 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14418 } 14419 notifyEnterOrExitForAutoFillIfNeeded(true); 14420 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 14421 } 14422 14423 /** 14424 * Called after {@link #onStartTemporaryDetach} when the container is done 14425 * changing the view. 14426 */ onFinishTemporaryDetach()14427 public void onFinishTemporaryDetach() { 14428 } 14429 14430 /** 14431 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 14432 * for this view's window. Returns null if the view is not currently attached 14433 * to the window. Normally you will not need to use this directly, but 14434 * just use the standard high-level event callbacks like 14435 * {@link #onKeyDown(int, KeyEvent)}. 14436 */ getKeyDispatcherState()14437 public KeyEvent.DispatcherState getKeyDispatcherState() { 14438 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 14439 } 14440 14441 /** 14442 * Dispatch a key event before it is processed by any input method 14443 * associated with the view hierarchy. This can be used to intercept 14444 * key events in special situations before the IME consumes them; a 14445 * typical example would be handling the BACK key to update the application's 14446 * UI instead of allowing the IME to see it and close itself. 14447 * 14448 * @param event The key event to be dispatched. 14449 * @return True if the event was handled, false otherwise. 14450 */ dispatchKeyEventPreIme(KeyEvent event)14451 public boolean dispatchKeyEventPreIme(KeyEvent event) { 14452 return onKeyPreIme(event.getKeyCode(), event); 14453 } 14454 14455 /** 14456 * Dispatch a key event to the next view on the focus path. This path runs 14457 * from the top of the view tree down to the currently focused view. If this 14458 * view has focus, it will dispatch to itself. Otherwise it will dispatch 14459 * the next node down the focus path. This method also fires any key 14460 * listeners. 14461 * 14462 * @param event The key event to be dispatched. 14463 * @return True if the event was handled, false otherwise. 14464 */ dispatchKeyEvent(KeyEvent event)14465 public boolean dispatchKeyEvent(KeyEvent event) { 14466 if (mInputEventConsistencyVerifier != null) { 14467 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 14468 } 14469 14470 // Give any attached key listener a first crack at the event. 14471 //noinspection SimplifiableIfStatement 14472 ListenerInfo li = mListenerInfo; 14473 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 14474 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 14475 return true; 14476 } 14477 14478 if (event.dispatch(this, mAttachInfo != null 14479 ? mAttachInfo.mKeyDispatchState : null, this)) { 14480 return true; 14481 } 14482 14483 if (mInputEventConsistencyVerifier != null) { 14484 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14485 } 14486 return false; 14487 } 14488 14489 /** 14490 * Dispatches a key shortcut event. 14491 * 14492 * @param event The key event to be dispatched. 14493 * @return True if the event was handled by the view, false otherwise. 14494 */ dispatchKeyShortcutEvent(KeyEvent event)14495 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 14496 return onKeyShortcut(event.getKeyCode(), event); 14497 } 14498 14499 /** 14500 * Pass the touch screen motion event down to the target view, or this 14501 * view if it is the target. 14502 * 14503 * @param event The motion event to be dispatched. 14504 * @return True if the event was handled by the view, false otherwise. 14505 */ dispatchTouchEvent(MotionEvent event)14506 public boolean dispatchTouchEvent(MotionEvent event) { 14507 // If the event should be handled by accessibility focus first. 14508 if (event.isTargetAccessibilityFocus()) { 14509 // We don't have focus or no virtual descendant has it, do not handle the event. 14510 if (!isAccessibilityFocusedViewOrHost()) { 14511 return false; 14512 } 14513 // We have focus and got the event, then use normal event dispatch. 14514 event.setTargetAccessibilityFocus(false); 14515 } 14516 boolean result = false; 14517 14518 if (mInputEventConsistencyVerifier != null) { 14519 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 14520 } 14521 14522 final int actionMasked = event.getActionMasked(); 14523 if (actionMasked == MotionEvent.ACTION_DOWN) { 14524 // Defensive cleanup for new gesture 14525 stopNestedScroll(); 14526 } 14527 14528 if (onFilterTouchEventForSecurity(event)) { 14529 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 14530 result = true; 14531 } 14532 //noinspection SimplifiableIfStatement 14533 ListenerInfo li = mListenerInfo; 14534 if (li != null && li.mOnTouchListener != null 14535 && (mViewFlags & ENABLED_MASK) == ENABLED 14536 && li.mOnTouchListener.onTouch(this, event)) { 14537 result = true; 14538 } 14539 14540 if (!result && onTouchEvent(event)) { 14541 result = true; 14542 } 14543 } 14544 14545 if (!result && mInputEventConsistencyVerifier != null) { 14546 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14547 } 14548 14549 // Clean up after nested scrolls if this is the end of a gesture; 14550 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 14551 // of the gesture. 14552 if (actionMasked == MotionEvent.ACTION_UP || 14553 actionMasked == MotionEvent.ACTION_CANCEL || 14554 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 14555 stopNestedScroll(); 14556 } 14557 14558 return result; 14559 } 14560 isAccessibilityFocusedViewOrHost()14561 boolean isAccessibilityFocusedViewOrHost() { 14562 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 14563 .getAccessibilityFocusedHost() == this); 14564 } 14565 14566 /** 14567 * Returns whether this view can receive pointer events. 14568 * 14569 * @return {@code true} if this view can receive pointer events. 14570 * @hide 14571 */ canReceivePointerEvents()14572 protected boolean canReceivePointerEvents() { 14573 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 14574 } 14575 14576 /** 14577 * Filter the touch event to apply security policies. 14578 * 14579 * @param event The motion event to be filtered. 14580 * @return True if the event should be dispatched, false if the event should be dropped. 14581 * 14582 * @see #getFilterTouchesWhenObscured 14583 */ onFilterTouchEventForSecurity(MotionEvent event)14584 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 14585 //noinspection RedundantIfStatement 14586 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 14587 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 14588 // Window is obscured, drop this touch. 14589 return false; 14590 } 14591 return true; 14592 } 14593 14594 /** 14595 * Pass a trackball motion event down to the focused view. 14596 * 14597 * @param event The motion event to be dispatched. 14598 * @return True if the event was handled by the view, false otherwise. 14599 */ dispatchTrackballEvent(MotionEvent event)14600 public boolean dispatchTrackballEvent(MotionEvent event) { 14601 if (mInputEventConsistencyVerifier != null) { 14602 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 14603 } 14604 14605 return onTrackballEvent(event); 14606 } 14607 14608 /** 14609 * Pass a captured pointer event down to the focused view. 14610 * 14611 * @param event The motion event to be dispatched. 14612 * @return True if the event was handled by the view, false otherwise. 14613 */ dispatchCapturedPointerEvent(MotionEvent event)14614 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 14615 if (!hasPointerCapture()) { 14616 return false; 14617 } 14618 //noinspection SimplifiableIfStatement 14619 ListenerInfo li = mListenerInfo; 14620 if (li != null && li.mOnCapturedPointerListener != null 14621 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 14622 return true; 14623 } 14624 return onCapturedPointerEvent(event); 14625 } 14626 14627 /** 14628 * Dispatch a generic motion event. 14629 * <p> 14630 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 14631 * are delivered to the view under the pointer. All other generic motion events are 14632 * delivered to the focused view. Hover events are handled specially and are delivered 14633 * to {@link #onHoverEvent(MotionEvent)}. 14634 * </p> 14635 * 14636 * @param event The motion event to be dispatched. 14637 * @return True if the event was handled by the view, false otherwise. 14638 */ dispatchGenericMotionEvent(MotionEvent event)14639 public boolean dispatchGenericMotionEvent(MotionEvent event) { 14640 if (mInputEventConsistencyVerifier != null) { 14641 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 14642 } 14643 14644 final int source = event.getSource(); 14645 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 14646 final int action = event.getAction(); 14647 if (action == MotionEvent.ACTION_HOVER_ENTER 14648 || action == MotionEvent.ACTION_HOVER_MOVE 14649 || action == MotionEvent.ACTION_HOVER_EXIT) { 14650 if (dispatchHoverEvent(event)) { 14651 return true; 14652 } 14653 } else if (dispatchGenericPointerEvent(event)) { 14654 return true; 14655 } 14656 } else if (dispatchGenericFocusedEvent(event)) { 14657 return true; 14658 } 14659 14660 if (dispatchGenericMotionEventInternal(event)) { 14661 return true; 14662 } 14663 14664 if (mInputEventConsistencyVerifier != null) { 14665 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14666 } 14667 return false; 14668 } 14669 dispatchGenericMotionEventInternal(MotionEvent event)14670 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 14671 //noinspection SimplifiableIfStatement 14672 ListenerInfo li = mListenerInfo; 14673 if (li != null && li.mOnGenericMotionListener != null 14674 && (mViewFlags & ENABLED_MASK) == ENABLED 14675 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 14676 return true; 14677 } 14678 14679 if (onGenericMotionEvent(event)) { 14680 return true; 14681 } 14682 14683 final int actionButton = event.getActionButton(); 14684 switch (event.getActionMasked()) { 14685 case MotionEvent.ACTION_BUTTON_PRESS: 14686 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 14687 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14688 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14689 if (performContextClick(event.getX(), event.getY())) { 14690 mInContextButtonPress = true; 14691 setPressed(true, event.getX(), event.getY()); 14692 removeTapCallback(); 14693 removeLongPressCallback(); 14694 return true; 14695 } 14696 } 14697 break; 14698 14699 case MotionEvent.ACTION_BUTTON_RELEASE: 14700 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14701 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14702 mInContextButtonPress = false; 14703 mIgnoreNextUpEvent = true; 14704 } 14705 break; 14706 } 14707 14708 if (mInputEventConsistencyVerifier != null) { 14709 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14710 } 14711 return false; 14712 } 14713 14714 /** 14715 * Dispatch a hover event. 14716 * <p> 14717 * Do not call this method directly. 14718 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14719 * </p> 14720 * 14721 * @param event The motion event to be dispatched. 14722 * @return True if the event was handled by the view, false otherwise. 14723 */ dispatchHoverEvent(MotionEvent event)14724 protected boolean dispatchHoverEvent(MotionEvent event) { 14725 ListenerInfo li = mListenerInfo; 14726 //noinspection SimplifiableIfStatement 14727 if (li != null && li.mOnHoverListener != null 14728 && (mViewFlags & ENABLED_MASK) == ENABLED 14729 && li.mOnHoverListener.onHover(this, event)) { 14730 return true; 14731 } 14732 14733 return onHoverEvent(event); 14734 } 14735 14736 /** 14737 * Returns true if the view has a child to which it has recently sent 14738 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 14739 * it does not have a hovered child, then it must be the innermost hovered view. 14740 * @hide 14741 */ hasHoveredChild()14742 protected boolean hasHoveredChild() { 14743 return false; 14744 } 14745 14746 /** 14747 * Returns true if the given point, in local coordinates, is inside the hovered child. 14748 * 14749 * @hide 14750 */ pointInHoveredChild(MotionEvent event)14751 protected boolean pointInHoveredChild(MotionEvent event) { 14752 return false; 14753 } 14754 14755 /** 14756 * Dispatch a generic motion event to the view under the first pointer. 14757 * <p> 14758 * Do not call this method directly. 14759 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14760 * </p> 14761 * 14762 * @param event The motion event to be dispatched. 14763 * @return True if the event was handled by the view, false otherwise. 14764 */ dispatchGenericPointerEvent(MotionEvent event)14765 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 14766 return false; 14767 } 14768 14769 /** 14770 * Dispatch a generic motion event to the currently focused view. 14771 * <p> 14772 * Do not call this method directly. 14773 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14774 * </p> 14775 * 14776 * @param event The motion event to be dispatched. 14777 * @return True if the event was handled by the view, false otherwise. 14778 */ dispatchGenericFocusedEvent(MotionEvent event)14779 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 14780 return false; 14781 } 14782 14783 /** 14784 * Dispatch a pointer event. 14785 * <p> 14786 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 14787 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 14788 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 14789 * and should not be expected to handle other pointing device features. 14790 * </p> 14791 * 14792 * @param event The motion event to be dispatched. 14793 * @return True if the event was handled by the view, false otherwise. 14794 * @hide 14795 */ 14796 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchPointerEvent(MotionEvent event)14797 public final boolean dispatchPointerEvent(MotionEvent event) { 14798 if (event.isTouchEvent()) { 14799 return dispatchTouchEvent(event); 14800 } else { 14801 return dispatchGenericMotionEvent(event); 14802 } 14803 } 14804 14805 /** 14806 * Called when the window containing this view gains or loses window focus. 14807 * ViewGroups should override to route to their children. 14808 * 14809 * @param hasFocus True if the window containing this view now has focus, 14810 * false otherwise. 14811 */ dispatchWindowFocusChanged(boolean hasFocus)14812 public void dispatchWindowFocusChanged(boolean hasFocus) { 14813 onWindowFocusChanged(hasFocus); 14814 } 14815 14816 /** 14817 * Called when the window containing this view gains or loses focus. Note 14818 * that this is separate from view focus: to receive key events, both 14819 * your view and its window must have focus. If a window is displayed 14820 * on top of yours that takes input focus, then your own window will lose 14821 * focus but the view focus will remain unchanged. 14822 * 14823 * @param hasWindowFocus True if the window containing this view now has 14824 * focus, false otherwise. 14825 */ onWindowFocusChanged(boolean hasWindowFocus)14826 public void onWindowFocusChanged(boolean hasWindowFocus) { 14827 if (!hasWindowFocus) { 14828 if (isPressed()) { 14829 setPressed(false); 14830 } 14831 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14832 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14833 notifyFocusChangeToImeFocusController(false /* hasFocus */); 14834 } 14835 removeLongPressCallback(); 14836 removeTapCallback(); 14837 onFocusLost(); 14838 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14839 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14840 } 14841 14842 refreshDrawableState(); 14843 } 14844 14845 /** 14846 * Returns true if this view is in a window that currently has window focus. 14847 * Note that this is not the same as the view itself having focus. 14848 * 14849 * @return True if this view is in a window that currently has window focus. 14850 */ hasWindowFocus()14851 public boolean hasWindowFocus() { 14852 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 14853 } 14854 14855 /** 14856 * @return {@code true} if this view is in a window that currently has IME focusable state. 14857 * @hide 14858 */ hasImeFocus()14859 public boolean hasImeFocus() { 14860 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 14861 } 14862 14863 /** 14864 * Dispatch a view visibility change down the view hierarchy. 14865 * ViewGroups should override to route to their children. 14866 * @param changedView The view whose visibility changed. Could be 'this' or 14867 * an ancestor view. 14868 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 14869 * {@link #INVISIBLE} or {@link #GONE}. 14870 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)14871 protected void dispatchVisibilityChanged(@NonNull View changedView, 14872 @Visibility int visibility) { 14873 onVisibilityChanged(changedView, visibility); 14874 } 14875 14876 /** 14877 * Called when the visibility of the view or an ancestor of the view has 14878 * changed. 14879 * 14880 * @param changedView The view whose visibility changed. May be 14881 * {@code this} or an ancestor view. 14882 * @param visibility The new visibility, one of {@link #VISIBLE}, 14883 * {@link #INVISIBLE} or {@link #GONE}. 14884 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)14885 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 14886 } 14887 14888 /** 14889 * Dispatch a hint about whether this view is displayed. For instance, when 14890 * a View moves out of the screen, it might receives a display hint indicating 14891 * the view is not displayed. Applications should not <em>rely</em> on this hint 14892 * as there is no guarantee that they will receive one. 14893 * 14894 * @param hint A hint about whether or not this view is displayed: 14895 * {@link #VISIBLE} or {@link #INVISIBLE}. 14896 */ dispatchDisplayHint(@isibility int hint)14897 public void dispatchDisplayHint(@Visibility int hint) { 14898 onDisplayHint(hint); 14899 } 14900 14901 /** 14902 * Gives this view a hint about whether is displayed or not. For instance, when 14903 * a View moves out of the screen, it might receives a display hint indicating 14904 * the view is not displayed. Applications should not <em>rely</em> on this hint 14905 * as there is no guarantee that they will receive one. 14906 * 14907 * @param hint A hint about whether or not this view is displayed: 14908 * {@link #VISIBLE} or {@link #INVISIBLE}. 14909 */ onDisplayHint(@isibility int hint)14910 protected void onDisplayHint(@Visibility int hint) { 14911 } 14912 14913 /** 14914 * Dispatch a window visibility change down the view hierarchy. 14915 * ViewGroups should override to route to their children. 14916 * 14917 * @param visibility The new visibility of the window. 14918 * 14919 * @see #onWindowVisibilityChanged(int) 14920 */ dispatchWindowVisibilityChanged(@isibility int visibility)14921 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 14922 onWindowVisibilityChanged(visibility); 14923 } 14924 14925 /** 14926 * Called when the window containing has change its visibility 14927 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 14928 * that this tells you whether or not your window is being made visible 14929 * to the window manager; this does <em>not</em> tell you whether or not 14930 * your window is obscured by other windows on the screen, even if it 14931 * is itself visible. 14932 * 14933 * @param visibility The new visibility of the window. 14934 */ onWindowVisibilityChanged(@isibility int visibility)14935 protected void onWindowVisibilityChanged(@Visibility int visibility) { 14936 if (visibility == VISIBLE) { 14937 initialAwakenScrollBars(); 14938 } 14939 } 14940 14941 /** 14942 * @return true if this view and all ancestors are visible as of the last 14943 * {@link #onVisibilityAggregated(boolean)} call. 14944 */ isAggregatedVisible()14945 boolean isAggregatedVisible() { 14946 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 14947 } 14948 14949 /** 14950 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 14951 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 14952 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 14953 * 14954 * @param isVisible true if this view's visibility to the user is uninterrupted by its 14955 * ancestors or by window visibility 14956 * @return true if this view is visible to the user, not counting clipping or overlapping 14957 */ dispatchVisibilityAggregated(boolean isVisible)14958 boolean dispatchVisibilityAggregated(boolean isVisible) { 14959 final boolean thisVisible = getVisibility() == VISIBLE; 14960 // If we're not visible but something is telling us we are, ignore it. 14961 if (thisVisible || !isVisible) { 14962 onVisibilityAggregated(isVisible); 14963 } 14964 return thisVisible && isVisible; 14965 } 14966 14967 /** 14968 * Called when the user-visibility of this View is potentially affected by a change 14969 * to this view itself, an ancestor view or the window this view is attached to. 14970 * 14971 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 14972 * and this view's window is also visible 14973 */ 14974 @CallSuper onVisibilityAggregated(boolean isVisible)14975 public void onVisibilityAggregated(boolean isVisible) { 14976 // Update our internal visibility tracking so we can detect changes 14977 boolean oldVisible = isAggregatedVisible(); 14978 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 14979 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 14980 if (isVisible && mAttachInfo != null) { 14981 initialAwakenScrollBars(); 14982 } 14983 14984 final Drawable dr = mBackground; 14985 if (dr != null && isVisible != dr.isVisible()) { 14986 dr.setVisible(isVisible, false); 14987 } 14988 final Drawable hl = mDefaultFocusHighlight; 14989 if (hl != null && isVisible != hl.isVisible()) { 14990 hl.setVisible(isVisible, false); 14991 } 14992 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 14993 if (fg != null && isVisible != fg.isVisible()) { 14994 fg.setVisible(isVisible, false); 14995 } 14996 14997 if (isAutofillable()) { 14998 AutofillManager afm = getAutofillManager(); 14999 15000 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 15001 if (mVisibilityChangeForAutofillHandler != null) { 15002 mVisibilityChangeForAutofillHandler.removeMessages(0); 15003 } 15004 15005 // If the view is in the background but still part of the hierarchy this is called 15006 // with isVisible=false. Hence visibility==false requires further checks 15007 if (isVisible) { 15008 afm.notifyViewVisibilityChanged(this, true); 15009 } else { 15010 if (mVisibilityChangeForAutofillHandler == null) { 15011 mVisibilityChangeForAutofillHandler = 15012 new VisibilityChangeForAutofillHandler(afm, this); 15013 } 15014 // Let current operation (e.g. removal of the view from the hierarchy) 15015 // finish before checking state 15016 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 15017 } 15018 } 15019 } 15020 15021 if (isVisible != oldVisible) { 15022 if (isAccessibilityPane()) { 15023 notifyViewAccessibilityStateChangedIfNeeded(isVisible 15024 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 15025 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 15026 } 15027 15028 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 15029 15030 if (!getSystemGestureExclusionRects().isEmpty()) { 15031 postUpdateSystemGestureExclusionRects(); 15032 } 15033 } 15034 } 15035 15036 /** 15037 * Returns the current visibility of the window this view is attached to 15038 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 15039 * 15040 * @return Returns the current visibility of the view's window. 15041 */ 15042 @Visibility getWindowVisibility()15043 public int getWindowVisibility() { 15044 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 15045 } 15046 15047 /** 15048 * Retrieve the overall visible display size in which the window this view is 15049 * attached to has been positioned in. This takes into account screen 15050 * decorations above the window, for both cases where the window itself 15051 * is being position inside of them or the window is being placed under 15052 * then and covered insets are used for the window to position its content 15053 * inside. In effect, this tells you the available area where content can 15054 * be placed and remain visible to users. 15055 * 15056 * @param outRect Filled in with the visible display frame. If the view 15057 * is not attached to a window, this is simply the raw display size. 15058 */ getWindowVisibleDisplayFrame(Rect outRect)15059 public void getWindowVisibleDisplayFrame(Rect outRect) { 15060 if (mAttachInfo != null) { 15061 mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); 15062 return; 15063 } 15064 // The view is not attached to a display so we don't have a context. 15065 // Make a best guess about the display size. 15066 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 15067 d.getRectSize(outRect); 15068 } 15069 15070 /** 15071 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 15072 * is currently in without any insets. 15073 * 15074 * @hide 15075 */ 15076 @UnsupportedAppUsage getWindowDisplayFrame(Rect outRect)15077 public void getWindowDisplayFrame(Rect outRect) { 15078 if (mAttachInfo != null) { 15079 mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); 15080 return; 15081 } 15082 // The view is not attached to a display so we don't have a context. 15083 // Make a best guess about the display size. 15084 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 15085 d.getRectSize(outRect); 15086 } 15087 15088 /** 15089 * Dispatch a notification about a resource configuration change down 15090 * the view hierarchy. 15091 * ViewGroups should override to route to their children. 15092 * 15093 * @param newConfig The new resource configuration. 15094 * 15095 * @see #onConfigurationChanged(android.content.res.Configuration) 15096 */ dispatchConfigurationChanged(Configuration newConfig)15097 public void dispatchConfigurationChanged(Configuration newConfig) { 15098 onConfigurationChanged(newConfig); 15099 } 15100 15101 /** 15102 * Called when the current configuration of the resources being used 15103 * by the application have changed. You can use this to decide when 15104 * to reload resources that can changed based on orientation and other 15105 * configuration characteristics. You only need to use this if you are 15106 * not relying on the normal {@link android.app.Activity} mechanism of 15107 * recreating the activity instance upon a configuration change. 15108 * 15109 * @param newConfig The new resource configuration. 15110 */ onConfigurationChanged(Configuration newConfig)15111 protected void onConfigurationChanged(Configuration newConfig) { 15112 } 15113 15114 /** 15115 * Private function to aggregate all per-view attributes in to the view 15116 * root. 15117 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)15118 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 15119 performCollectViewAttributes(attachInfo, visibility); 15120 } 15121 performCollectViewAttributes(AttachInfo attachInfo, int visibility)15122 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 15123 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 15124 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 15125 attachInfo.mKeepScreenOn = true; 15126 } 15127 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 15128 ListenerInfo li = mListenerInfo; 15129 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 15130 attachInfo.mHasSystemUiListeners = true; 15131 } 15132 } 15133 } 15134 needGlobalAttributesUpdate(boolean force)15135 void needGlobalAttributesUpdate(boolean force) { 15136 final AttachInfo ai = mAttachInfo; 15137 if (ai != null && !ai.mRecomputeGlobalAttributes) { 15138 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 15139 || ai.mHasSystemUiListeners) { 15140 ai.mRecomputeGlobalAttributes = true; 15141 } 15142 } 15143 } 15144 15145 /** 15146 * Returns whether the device is currently in touch mode. Touch mode is entered 15147 * once the user begins interacting with the device by touch, and affects various 15148 * things like whether focus is always visible to the user. 15149 * 15150 * @return Whether the device is in touch mode. 15151 */ 15152 @ViewDebug.ExportedProperty isInTouchMode()15153 public boolean isInTouchMode() { 15154 if (mAttachInfo != null) { 15155 return mAttachInfo.mInTouchMode; 15156 } else { 15157 return ViewRootImpl.isInTouchMode(); 15158 } 15159 } 15160 15161 /** 15162 * Returns the context the view is running in, through which it can 15163 * access the current theme, resources, etc. 15164 * 15165 * @return The view's Context. 15166 */ 15167 @ViewDebug.CapturedViewProperty 15168 @UiContext getContext()15169 public final Context getContext() { 15170 return mContext; 15171 } 15172 15173 /** 15174 * Handle a key event before it is processed by any input method 15175 * associated with the view hierarchy. This can be used to intercept 15176 * key events in special situations before the IME consumes them; a 15177 * typical example would be handling the BACK key to update the application's 15178 * UI instead of allowing the IME to see it and close itself. 15179 * 15180 * @param keyCode The value in event.getKeyCode(). 15181 * @param event Description of the key event. 15182 * @return If you handled the event, return true. If you want to allow the 15183 * event to be handled by the next receiver, return false. 15184 */ onKeyPreIme(int keyCode, KeyEvent event)15185 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 15186 return false; 15187 } 15188 15189 /** 15190 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 15191 * KeyEvent.Callback.onKeyDown()}: perform press of the view 15192 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 15193 * is released, if the view is enabled and clickable. 15194 * <p> 15195 * Key presses in software keyboards will generally NOT trigger this 15196 * listener, although some may elect to do so in some situations. Do not 15197 * rely on this to catch software key presses. 15198 * 15199 * @param keyCode a key code that represents the button pressed, from 15200 * {@link android.view.KeyEvent} 15201 * @param event the KeyEvent object that defines the button action 15202 */ onKeyDown(int keyCode, KeyEvent event)15203 public boolean onKeyDown(int keyCode, KeyEvent event) { 15204 if (KeyEvent.isConfirmKey(keyCode)) { 15205 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15206 return true; 15207 } 15208 15209 if (event.getRepeatCount() == 0) { 15210 // Long clickable items don't necessarily have to be clickable. 15211 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 15212 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 15213 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 15214 // For the purposes of menu anchoring and drawable hotspots, 15215 // key events are considered to be at the center of the view. 15216 final float x = getWidth() / 2f; 15217 final float y = getHeight() / 2f; 15218 if (clickable) { 15219 setPressed(true, x, y); 15220 } 15221 checkForLongClick( 15222 ViewConfiguration.getLongPressTimeout(), 15223 x, 15224 y, 15225 // This is not a touch gesture -- do not classify it as one. 15226 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 15227 return true; 15228 } 15229 } 15230 } 15231 15232 return false; 15233 } 15234 15235 /** 15236 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 15237 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 15238 * the event). 15239 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15240 * although some may elect to do so in some situations. Do not rely on this to 15241 * catch software key presses. 15242 */ onKeyLongPress(int keyCode, KeyEvent event)15243 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 15244 return false; 15245 } 15246 15247 /** 15248 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 15249 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 15250 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 15251 * or {@link KeyEvent#KEYCODE_SPACE} is released. 15252 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15253 * although some may elect to do so in some situations. Do not rely on this to 15254 * catch software key presses. 15255 * 15256 * @param keyCode A key code that represents the button pressed, from 15257 * {@link android.view.KeyEvent}. 15258 * @param event The KeyEvent object that defines the button action. 15259 */ onKeyUp(int keyCode, KeyEvent event)15260 public boolean onKeyUp(int keyCode, KeyEvent event) { 15261 if (KeyEvent.isConfirmKey(keyCode)) { 15262 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15263 return true; 15264 } 15265 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 15266 setPressed(false); 15267 15268 if (!mHasPerformedLongPress) { 15269 // This is a tap, so remove the longpress check 15270 removeLongPressCallback(); 15271 if (!event.isCanceled()) { 15272 return performClickInternal(); 15273 } 15274 } 15275 } 15276 } 15277 return false; 15278 } 15279 15280 /** 15281 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 15282 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 15283 * the event). 15284 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15285 * although some may elect to do so in some situations. Do not rely on this to 15286 * catch software key presses. 15287 * 15288 * @param keyCode A key code that represents the button pressed, from 15289 * {@link android.view.KeyEvent}. 15290 * @param repeatCount The number of times the action was made. 15291 * @param event The KeyEvent object that defines the button action. 15292 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)15293 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 15294 return false; 15295 } 15296 15297 /** 15298 * Called on the focused view when a key shortcut event is not handled. 15299 * Override this method to implement local key shortcuts for the View. 15300 * Key shortcuts can also be implemented by setting the 15301 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 15302 * 15303 * @param keyCode The value in event.getKeyCode(). 15304 * @param event Description of the key event. 15305 * @return If you handled the event, return true. If you want to allow the 15306 * event to be handled by the next receiver, return false. 15307 */ onKeyShortcut(int keyCode, KeyEvent event)15308 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 15309 return false; 15310 } 15311 15312 /** 15313 * Check whether the called view is a text editor, in which case it 15314 * would make sense to automatically display a soft input window for 15315 * it. Subclasses should override this if they implement 15316 * {@link #onCreateInputConnection(EditorInfo)} to return true if 15317 * a call on that method would return a non-null InputConnection, and 15318 * they are really a first-class editor that the user would normally 15319 * start typing on when the go into a window containing your view. 15320 * 15321 * <p>The default implementation always returns false. This does 15322 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 15323 * will not be called or the user can not otherwise perform edits on your 15324 * view; it is just a hint to the system that this is not the primary 15325 * purpose of this view. 15326 * 15327 * @return Returns true if this view is a text editor, else false. 15328 */ onCheckIsTextEditor()15329 public boolean onCheckIsTextEditor() { 15330 return false; 15331 } 15332 15333 /** 15334 * Create a new InputConnection for an InputMethod to interact 15335 * with the view. The default implementation returns null, since it doesn't 15336 * support input methods. You can override this to implement such support. 15337 * This is only needed for views that take focus and text input. 15338 * 15339 * <p>When implementing this, you probably also want to implement 15340 * {@link #onCheckIsTextEditor()} to indicate you will return a 15341 * non-null InputConnection.</p> 15342 * 15343 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 15344 * object correctly and in its entirety, so that the connected IME can rely 15345 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 15346 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 15347 * must be filled in with the correct cursor position for IMEs to work correctly 15348 * with your application.</p> 15349 * 15350 * @param outAttrs Fill in with attribute information about the connection. 15351 */ onCreateInputConnection(EditorInfo outAttrs)15352 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 15353 return null; 15354 } 15355 15356 /** 15357 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 15358 * that the system has successfully initialized an {@link InputConnection} and it is ready for 15359 * use. 15360 * 15361 * <p>The default implementation does nothing, since a view doesn't support input methods by 15362 * default (see {@link #onCreateInputConnection}). 15363 * 15364 * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, 15365 * after it's been fully initialized by the system. 15366 * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. 15367 * @param handler The dedicated {@link Handler} on which IPC method calls from input methods 15368 * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If 15369 * that method returns null, this parameter will be null also. 15370 * 15371 * @hide 15372 */ onInputConnectionOpenedInternal(@onNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler)15373 public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, 15374 @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} 15375 15376 /** 15377 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 15378 * that the {@link InputConnection} has been closed. 15379 * 15380 * <p>The default implementation does nothing, since a view doesn't support input methods by 15381 * default (see {@link #onCreateInputConnection}). 15382 * 15383 * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when 15384 * the {@link InputConnection} is closed or the connection is not valid and managed by 15385 * {@link com.android.server.inputmethod.InputMethodManagerService}. 15386 * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. 15387 * 15388 * @hide 15389 */ onInputConnectionClosedInternal()15390 public void onInputConnectionClosedInternal() {} 15391 15392 /** 15393 * Called by the {@link android.view.inputmethod.InputMethodManager} 15394 * when a view who is not the current 15395 * input connection target is trying to make a call on the manager. The 15396 * default implementation returns false; you can override this to return 15397 * true for certain views if you are performing InputConnection proxying 15398 * to them. 15399 * @param view The View that is making the InputMethodManager call. 15400 * @return Return true to allow the call, false to reject. 15401 */ checkInputConnectionProxy(View view)15402 public boolean checkInputConnectionProxy(View view) { 15403 return false; 15404 } 15405 15406 /** 15407 * Show the context menu for this view. It is not safe to hold on to the 15408 * menu after returning from this method. 15409 * 15410 * You should normally not overload this method. Overload 15411 * {@link #onCreateContextMenu(ContextMenu)} or define an 15412 * {@link OnCreateContextMenuListener} to add items to the context menu. 15413 * 15414 * @param menu The context menu to populate 15415 */ createContextMenu(ContextMenu menu)15416 public void createContextMenu(ContextMenu menu) { 15417 ContextMenuInfo menuInfo = getContextMenuInfo(); 15418 15419 // Sets the current menu info so all items added to menu will have 15420 // my extra info set. 15421 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 15422 15423 onCreateContextMenu(menu); 15424 ListenerInfo li = mListenerInfo; 15425 if (li != null && li.mOnCreateContextMenuListener != null) { 15426 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 15427 } 15428 15429 // Clear the extra information so subsequent items that aren't mine don't 15430 // have my extra info. 15431 ((MenuBuilder)menu).setCurrentMenuInfo(null); 15432 15433 if (mParent != null) { 15434 mParent.createContextMenu(menu); 15435 } 15436 } 15437 15438 /** 15439 * Views should implement this if they have extra information to associate 15440 * with the context menu. The return result is supplied as a parameter to 15441 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 15442 * callback. 15443 * 15444 * @return Extra information about the item for which the context menu 15445 * should be shown. This information will vary across different 15446 * subclasses of View. 15447 */ getContextMenuInfo()15448 protected ContextMenuInfo getContextMenuInfo() { 15449 return null; 15450 } 15451 15452 /** 15453 * Views should implement this if the view itself is going to add items to 15454 * the context menu. 15455 * 15456 * @param menu the context menu to populate 15457 */ onCreateContextMenu(ContextMenu menu)15458 protected void onCreateContextMenu(ContextMenu menu) { 15459 } 15460 15461 /** 15462 * Implement this method to handle trackball motion events. The 15463 * <em>relative</em> movement of the trackball since the last event 15464 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 15465 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 15466 * that a movement of 1 corresponds to the user pressing one DPAD key (so 15467 * they will often be fractional values, representing the more fine-grained 15468 * movement information available from a trackball). 15469 * 15470 * @param event The motion event. 15471 * @return True if the event was handled, false otherwise. 15472 */ onTrackballEvent(MotionEvent event)15473 public boolean onTrackballEvent(MotionEvent event) { 15474 return false; 15475 } 15476 15477 /** 15478 * Implement this method to handle generic motion events. 15479 * <p> 15480 * Generic motion events describe joystick movements, mouse hovers, track pad 15481 * touches, scroll wheel movements and other input events. The 15482 * {@link MotionEvent#getSource() source} of the motion event specifies 15483 * the class of input that was received. Implementations of this method 15484 * must examine the bits in the source before processing the event. 15485 * The following code example shows how this is done. 15486 * </p><p> 15487 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 15488 * are delivered to the view under the pointer. All other generic motion events are 15489 * delivered to the focused view. 15490 * </p> 15491 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 15492 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 15493 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 15494 * // process the joystick movement... 15495 * return true; 15496 * } 15497 * } 15498 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 15499 * switch (event.getAction()) { 15500 * case MotionEvent.ACTION_HOVER_MOVE: 15501 * // process the mouse hover movement... 15502 * return true; 15503 * case MotionEvent.ACTION_SCROLL: 15504 * // process the scroll wheel movement... 15505 * return true; 15506 * } 15507 * } 15508 * return super.onGenericMotionEvent(event); 15509 * }</pre> 15510 * 15511 * @param event The generic motion event being processed. 15512 * @return True if the event was handled, false otherwise. 15513 */ onGenericMotionEvent(MotionEvent event)15514 public boolean onGenericMotionEvent(MotionEvent event) { 15515 return false; 15516 } 15517 15518 /** 15519 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 15520 * <p> 15521 * This method is dispatching hover events to the delegate target to support explore by touch. 15522 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 15523 * the delegate target according to the pointer and the touch area of the delegate while touch 15524 * exploration enabled. 15525 * </p> 15526 * 15527 * @param event The motion event dispatch to the delegate target. 15528 * @return True if the event was handled, false otherwise. 15529 * 15530 * @see #onHoverEvent 15531 */ dispatchTouchExplorationHoverEvent(MotionEvent event)15532 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 15533 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 15534 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 15535 return false; 15536 } 15537 15538 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 15539 final int action = event.getActionMasked(); 15540 boolean pointInDelegateRegion = false; 15541 boolean handled = false; 15542 15543 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 15544 for (int i = 0; i < info.getRegionCount(); i++) { 15545 Region r = info.getRegionAt(i); 15546 if (r.contains((int) event.getX(), (int) event.getY())) { 15547 pointInDelegateRegion = true; 15548 } 15549 } 15550 15551 // Explore by touch should dispatch events to children under the pointer first if any 15552 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 15553 // hover events but receive accessibility focus, it should also not delegate to these 15554 // views when hovered. 15555 if (!oldHoveringTouchDelegate) { 15556 if ((action == MotionEvent.ACTION_HOVER_ENTER 15557 || action == MotionEvent.ACTION_HOVER_MOVE) 15558 && !pointInHoveredChild(event) 15559 && pointInDelegateRegion) { 15560 mHoveringTouchDelegate = true; 15561 } 15562 } else { 15563 if (action == MotionEvent.ACTION_HOVER_EXIT 15564 || (action == MotionEvent.ACTION_HOVER_MOVE 15565 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 15566 mHoveringTouchDelegate = false; 15567 } 15568 } 15569 switch (action) { 15570 case MotionEvent.ACTION_HOVER_MOVE: 15571 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15572 // Inside bounds, dispatch as is. 15573 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 15574 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15575 // Moving inbound, synthesize hover enter. 15576 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 15577 ? event : MotionEvent.obtainNoHistory(event); 15578 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 15579 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15580 eventNoHistory.setAction(action); 15581 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15582 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 15583 // Moving outbound, synthesize hover exit. 15584 final boolean hoverExitPending = event.isHoverExitPending(); 15585 event.setHoverExitPending(true); 15586 mTouchDelegate.onTouchExplorationHoverEvent(event); 15587 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 15588 ? event : MotionEvent.obtainNoHistory(event); 15589 eventNoHistory.setHoverExitPending(hoverExitPending); 15590 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 15591 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15592 } // else: outside bounds, do nothing. 15593 break; 15594 case MotionEvent.ACTION_HOVER_ENTER: 15595 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15596 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 15597 } 15598 break; 15599 case MotionEvent.ACTION_HOVER_EXIT: 15600 if (oldHoveringTouchDelegate) { 15601 mTouchDelegate.onTouchExplorationHoverEvent(event); 15602 } 15603 break; 15604 } 15605 return handled; 15606 } 15607 15608 /** 15609 * Implement this method to handle hover events. 15610 * <p> 15611 * This method is called whenever a pointer is hovering into, over, or out of the 15612 * bounds of a view and the view is not currently being touched. 15613 * Hover events are represented as pointer events with action 15614 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 15615 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 15616 * </p> 15617 * <ul> 15618 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 15619 * when the pointer enters the bounds of the view.</li> 15620 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 15621 * when the pointer has already entered the bounds of the view and has moved.</li> 15622 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 15623 * when the pointer has exited the bounds of the view or when the pointer is 15624 * about to go down due to a button click, tap, or similar user action that 15625 * causes the view to be touched.</li> 15626 * </ul> 15627 * <p> 15628 * The view should implement this method to return true to indicate that it is 15629 * handling the hover event, such as by changing its drawable state. 15630 * </p><p> 15631 * The default implementation calls {@link #setHovered} to update the hovered state 15632 * of the view when a hover enter or hover exit event is received, if the view 15633 * is enabled and is clickable. The default implementation also sends hover 15634 * accessibility events. 15635 * </p> 15636 * 15637 * @param event The motion event that describes the hover. 15638 * @return True if the view handled the hover event. 15639 * 15640 * @see #isHovered 15641 * @see #setHovered 15642 * @see #onHoverChanged 15643 */ onHoverEvent(MotionEvent event)15644 public boolean onHoverEvent(MotionEvent event) { 15645 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 15646 return true; 15647 } 15648 15649 // The root view may receive hover (or touch) events that are outside the bounds of 15650 // the window. This code ensures that we only send accessibility events for 15651 // hovers that are actually within the bounds of the root view. 15652 final int action = event.getActionMasked(); 15653 if (!mSendingHoverAccessibilityEvents) { 15654 if ((action == MotionEvent.ACTION_HOVER_ENTER 15655 || action == MotionEvent.ACTION_HOVER_MOVE) 15656 && !hasHoveredChild() 15657 && pointInView(event.getX(), event.getY())) { 15658 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 15659 mSendingHoverAccessibilityEvents = true; 15660 } 15661 } else { 15662 if (action == MotionEvent.ACTION_HOVER_EXIT 15663 || (action == MotionEvent.ACTION_HOVER_MOVE 15664 && !pointInView(event.getX(), event.getY()))) { 15665 mSendingHoverAccessibilityEvents = false; 15666 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 15667 } 15668 } 15669 15670 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 15671 && event.isFromSource(InputDevice.SOURCE_MOUSE) 15672 && isOnScrollbar(event.getX(), event.getY())) { 15673 awakenScrollBars(); 15674 } 15675 15676 // If we consider ourself hoverable, or if we we're already hovered, 15677 // handle changing state in response to ENTER and EXIT events. 15678 if (isHoverable() || isHovered()) { 15679 switch (action) { 15680 case MotionEvent.ACTION_HOVER_ENTER: 15681 setHovered(true); 15682 break; 15683 case MotionEvent.ACTION_HOVER_EXIT: 15684 setHovered(false); 15685 break; 15686 } 15687 15688 // Dispatch the event to onGenericMotionEvent before returning true. 15689 // This is to provide compatibility with existing applications that 15690 // handled HOVER_MOVE events in onGenericMotionEvent and that would 15691 // break because of the new default handling for hoverable views 15692 // in onHoverEvent. 15693 // Note that onGenericMotionEvent will be called by default when 15694 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 15695 dispatchGenericMotionEventInternal(event); 15696 // The event was already handled by calling setHovered(), so always 15697 // return true. 15698 return true; 15699 } 15700 15701 return false; 15702 } 15703 15704 /** 15705 * Returns true if the view should handle {@link #onHoverEvent} 15706 * by calling {@link #setHovered} to change its hovered state. 15707 * 15708 * @return True if the view is hoverable. 15709 */ isHoverable()15710 private boolean isHoverable() { 15711 final int viewFlags = mViewFlags; 15712 if ((viewFlags & ENABLED_MASK) == DISABLED) { 15713 return false; 15714 } 15715 15716 return (viewFlags & CLICKABLE) == CLICKABLE 15717 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 15718 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15719 } 15720 15721 /** 15722 * Returns true if the view is currently hovered. 15723 * 15724 * @return True if the view is currently hovered. 15725 * 15726 * @see #setHovered 15727 * @see #onHoverChanged 15728 */ 15729 @ViewDebug.ExportedProperty isHovered()15730 public boolean isHovered() { 15731 return (mPrivateFlags & PFLAG_HOVERED) != 0; 15732 } 15733 15734 /** 15735 * Sets whether the view is currently hovered. 15736 * <p> 15737 * Calling this method also changes the drawable state of the view. This 15738 * enables the view to react to hover by using different drawable resources 15739 * to change its appearance. 15740 * </p><p> 15741 * The {@link #onHoverChanged} method is called when the hovered state changes. 15742 * </p> 15743 * 15744 * @param hovered True if the view is hovered. 15745 * 15746 * @see #isHovered 15747 * @see #onHoverChanged 15748 */ setHovered(boolean hovered)15749 public void setHovered(boolean hovered) { 15750 if (hovered) { 15751 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 15752 mPrivateFlags |= PFLAG_HOVERED; 15753 refreshDrawableState(); 15754 onHoverChanged(true); 15755 } 15756 } else { 15757 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 15758 mPrivateFlags &= ~PFLAG_HOVERED; 15759 refreshDrawableState(); 15760 onHoverChanged(false); 15761 } 15762 } 15763 } 15764 15765 /** 15766 * Implement this method to handle hover state changes. 15767 * <p> 15768 * This method is called whenever the hover state changes as a result of a 15769 * call to {@link #setHovered}. 15770 * </p> 15771 * 15772 * @param hovered The current hover state, as returned by {@link #isHovered}. 15773 * 15774 * @see #isHovered 15775 * @see #setHovered 15776 */ onHoverChanged(boolean hovered)15777 public void onHoverChanged(boolean hovered) { 15778 } 15779 15780 /** 15781 * Handles scroll bar dragging by mouse input. 15782 * 15783 * @hide 15784 * @param event The motion event. 15785 * 15786 * @return true if the event was handled as a scroll bar dragging, false otherwise. 15787 */ handleScrollBarDragging(MotionEvent event)15788 protected boolean handleScrollBarDragging(MotionEvent event) { 15789 if (mScrollCache == null) { 15790 return false; 15791 } 15792 final float x = event.getX(); 15793 final float y = event.getY(); 15794 final int action = event.getAction(); 15795 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 15796 && action != MotionEvent.ACTION_DOWN) 15797 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 15798 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 15799 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15800 return false; 15801 } 15802 15803 switch (action) { 15804 case MotionEvent.ACTION_MOVE: 15805 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 15806 return false; 15807 } 15808 if (mScrollCache.mScrollBarDraggingState 15809 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 15810 final Rect bounds = mScrollCache.mScrollBarBounds; 15811 getVerticalScrollBarBounds(bounds, null); 15812 final int range = computeVerticalScrollRange(); 15813 final int offset = computeVerticalScrollOffset(); 15814 final int extent = computeVerticalScrollExtent(); 15815 15816 final int thumbLength = ScrollBarUtils.getThumbLength( 15817 bounds.height(), bounds.width(), extent, range); 15818 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15819 bounds.height(), thumbLength, extent, range, offset); 15820 15821 final float diff = y - mScrollCache.mScrollBarDraggingPos; 15822 final float maxThumbOffset = bounds.height() - thumbLength; 15823 final float newThumbOffset = 15824 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15825 final int height = getHeight(); 15826 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15827 && height > 0 && extent > 0) { 15828 final int newY = Math.round((range - extent) 15829 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 15830 if (newY != getScrollY()) { 15831 mScrollCache.mScrollBarDraggingPos = y; 15832 setScrollY(newY); 15833 } 15834 } 15835 return true; 15836 } 15837 if (mScrollCache.mScrollBarDraggingState 15838 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 15839 final Rect bounds = mScrollCache.mScrollBarBounds; 15840 getHorizontalScrollBarBounds(bounds, null); 15841 final int range = computeHorizontalScrollRange(); 15842 final int offset = computeHorizontalScrollOffset(); 15843 final int extent = computeHorizontalScrollExtent(); 15844 15845 final int thumbLength = ScrollBarUtils.getThumbLength( 15846 bounds.width(), bounds.height(), extent, range); 15847 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15848 bounds.width(), thumbLength, extent, range, offset); 15849 15850 final float diff = x - mScrollCache.mScrollBarDraggingPos; 15851 final float maxThumbOffset = bounds.width() - thumbLength; 15852 final float newThumbOffset = 15853 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15854 final int width = getWidth(); 15855 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15856 && width > 0 && extent > 0) { 15857 final int newX = Math.round((range - extent) 15858 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 15859 if (newX != getScrollX()) { 15860 mScrollCache.mScrollBarDraggingPos = x; 15861 setScrollX(newX); 15862 } 15863 } 15864 return true; 15865 } 15866 case MotionEvent.ACTION_DOWN: 15867 if (mScrollCache.state == ScrollabilityCache.OFF) { 15868 return false; 15869 } 15870 if (isOnVerticalScrollbarThumb(x, y)) { 15871 mScrollCache.mScrollBarDraggingState = 15872 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 15873 mScrollCache.mScrollBarDraggingPos = y; 15874 return true; 15875 } 15876 if (isOnHorizontalScrollbarThumb(x, y)) { 15877 mScrollCache.mScrollBarDraggingState = 15878 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 15879 mScrollCache.mScrollBarDraggingPos = x; 15880 return true; 15881 } 15882 } 15883 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15884 return false; 15885 } 15886 15887 /** 15888 * Implement this method to handle touch screen motion events. 15889 * <p> 15890 * If this method is used to detect click actions, it is recommended that 15891 * the actions be performed by implementing and calling 15892 * {@link #performClick()}. This will ensure consistent system behavior, 15893 * including: 15894 * <ul> 15895 * <li>obeying click sound preferences 15896 * <li>dispatching OnClickListener calls 15897 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 15898 * accessibility features are enabled 15899 * </ul> 15900 * 15901 * @param event The motion event. 15902 * @return True if the event was handled, false otherwise. 15903 */ onTouchEvent(MotionEvent event)15904 public boolean onTouchEvent(MotionEvent event) { 15905 final float x = event.getX(); 15906 final float y = event.getY(); 15907 final int viewFlags = mViewFlags; 15908 final int action = event.getAction(); 15909 15910 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 15911 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 15912 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15913 15914 if ((viewFlags & ENABLED_MASK) == DISABLED 15915 && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { 15916 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 15917 setPressed(false); 15918 } 15919 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15920 // A disabled view that is clickable still consumes the touch 15921 // events, it just doesn't respond to them. 15922 return clickable; 15923 } 15924 if (mTouchDelegate != null) { 15925 if (mTouchDelegate.onTouchEvent(event)) { 15926 return true; 15927 } 15928 } 15929 15930 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 15931 switch (action) { 15932 case MotionEvent.ACTION_UP: 15933 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15934 if ((viewFlags & TOOLTIP) == TOOLTIP) { 15935 handleTooltipUp(); 15936 } 15937 if (!clickable) { 15938 removeTapCallback(); 15939 removeLongPressCallback(); 15940 mInContextButtonPress = false; 15941 mHasPerformedLongPress = false; 15942 mIgnoreNextUpEvent = false; 15943 break; 15944 } 15945 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 15946 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 15947 // take focus if we don't have it already and we should in 15948 // touch mode. 15949 boolean focusTaken = false; 15950 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 15951 focusTaken = requestFocus(); 15952 } 15953 15954 if (prepressed) { 15955 // The button is being released before we actually 15956 // showed it as pressed. Make it show the pressed 15957 // state now (before scheduling the click) to ensure 15958 // the user sees it. 15959 setPressed(true, x, y); 15960 } 15961 15962 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 15963 // This is a tap, so remove the longpress check 15964 removeLongPressCallback(); 15965 15966 // Only perform take click actions if we were in the pressed state 15967 if (!focusTaken) { 15968 // Use a Runnable and post this rather than calling 15969 // performClick directly. This lets other visual state 15970 // of the view update before click actions start. 15971 if (mPerformClick == null) { 15972 mPerformClick = new PerformClick(); 15973 } 15974 if (!post(mPerformClick)) { 15975 performClickInternal(); 15976 } 15977 } 15978 } 15979 15980 if (mUnsetPressedState == null) { 15981 mUnsetPressedState = new UnsetPressedState(); 15982 } 15983 15984 if (prepressed) { 15985 postDelayed(mUnsetPressedState, 15986 ViewConfiguration.getPressedStateDuration()); 15987 } else if (!post(mUnsetPressedState)) { 15988 // If the post failed, unpress right now 15989 mUnsetPressedState.run(); 15990 } 15991 15992 removeTapCallback(); 15993 } 15994 mIgnoreNextUpEvent = false; 15995 break; 15996 15997 case MotionEvent.ACTION_DOWN: 15998 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 15999 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 16000 } 16001 mHasPerformedLongPress = false; 16002 16003 if (!clickable) { 16004 checkForLongClick( 16005 ViewConfiguration.getLongPressTimeout(), 16006 x, 16007 y, 16008 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16009 break; 16010 } 16011 16012 if (performButtonActionOnTouchDown(event)) { 16013 break; 16014 } 16015 16016 // Walk up the hierarchy to determine if we're inside a scrolling container. 16017 boolean isInScrollingContainer = isInScrollingContainer(); 16018 16019 // For views inside a scrolling container, delay the pressed feedback for 16020 // a short period in case this is a scroll. 16021 if (isInScrollingContainer) { 16022 mPrivateFlags |= PFLAG_PREPRESSED; 16023 if (mPendingCheckForTap == null) { 16024 mPendingCheckForTap = new CheckForTap(); 16025 } 16026 mPendingCheckForTap.x = event.getX(); 16027 mPendingCheckForTap.y = event.getY(); 16028 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 16029 } else { 16030 // Not inside a scrolling container, so show the feedback right away 16031 setPressed(true, x, y); 16032 checkForLongClick( 16033 ViewConfiguration.getLongPressTimeout(), 16034 x, 16035 y, 16036 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16037 } 16038 break; 16039 16040 case MotionEvent.ACTION_CANCEL: 16041 if (clickable) { 16042 setPressed(false); 16043 } 16044 removeTapCallback(); 16045 removeLongPressCallback(); 16046 mInContextButtonPress = false; 16047 mHasPerformedLongPress = false; 16048 mIgnoreNextUpEvent = false; 16049 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16050 break; 16051 16052 case MotionEvent.ACTION_MOVE: 16053 if (clickable) { 16054 drawableHotspotChanged(x, y); 16055 } 16056 16057 final int motionClassification = event.getClassification(); 16058 final boolean ambiguousGesture = 16059 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 16060 int touchSlop = mTouchSlop; 16061 if (ambiguousGesture && hasPendingLongPressCallback()) { 16062 if (!pointInView(x, y, touchSlop)) { 16063 // The default action here is to cancel long press. But instead, we 16064 // just extend the timeout here, in case the classification 16065 // stays ambiguous. 16066 removeLongPressCallback(); 16067 long delay = (long) (ViewConfiguration.getLongPressTimeout() 16068 * mAmbiguousGestureMultiplier); 16069 // Subtract the time already spent 16070 delay -= event.getEventTime() - event.getDownTime(); 16071 checkForLongClick( 16072 delay, 16073 x, 16074 y, 16075 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 16076 } 16077 touchSlop *= mAmbiguousGestureMultiplier; 16078 } 16079 16080 // Be lenient about moving outside of buttons 16081 if (!pointInView(x, y, touchSlop)) { 16082 // Outside button 16083 // Remove any future long press/tap checks 16084 removeTapCallback(); 16085 removeLongPressCallback(); 16086 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 16087 setPressed(false); 16088 } 16089 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16090 } 16091 16092 final boolean deepPress = 16093 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 16094 if (deepPress && hasPendingLongPressCallback()) { 16095 // process the long click action immediately 16096 removeLongPressCallback(); 16097 checkForLongClick( 16098 0 /* send immediately */, 16099 x, 16100 y, 16101 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 16102 } 16103 16104 break; 16105 } 16106 16107 return true; 16108 } 16109 16110 return false; 16111 } 16112 16113 /** 16114 * @hide 16115 */ 16116 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isInScrollingContainer()16117 public boolean isInScrollingContainer() { 16118 ViewParent p = getParent(); 16119 while (p != null && p instanceof ViewGroup) { 16120 if (((ViewGroup) p).shouldDelayChildPressedState()) { 16121 return true; 16122 } 16123 p = p.getParent(); 16124 } 16125 return false; 16126 } 16127 16128 /** 16129 * Remove the longpress detection timer. 16130 */ removeLongPressCallback()16131 private void removeLongPressCallback() { 16132 if (mPendingCheckForLongPress != null) { 16133 removeCallbacks(mPendingCheckForLongPress); 16134 } 16135 } 16136 16137 /** 16138 * Return true if the long press callback is scheduled to run sometime in the future. 16139 * Return false if there is no scheduled long press callback at the moment. 16140 */ hasPendingLongPressCallback()16141 private boolean hasPendingLongPressCallback() { 16142 if (mPendingCheckForLongPress == null) { 16143 return false; 16144 } 16145 final AttachInfo attachInfo = mAttachInfo; 16146 if (attachInfo == null) { 16147 return false; 16148 } 16149 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 16150 } 16151 16152 /** 16153 * Remove the pending click action 16154 */ 16155 @UnsupportedAppUsage removePerformClickCallback()16156 private void removePerformClickCallback() { 16157 if (mPerformClick != null) { 16158 removeCallbacks(mPerformClick); 16159 } 16160 } 16161 16162 /** 16163 * Remove the prepress detection timer. 16164 */ removeUnsetPressCallback()16165 private void removeUnsetPressCallback() { 16166 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 16167 setPressed(false); 16168 removeCallbacks(mUnsetPressedState); 16169 } 16170 } 16171 16172 /** 16173 * Remove the tap detection timer. 16174 */ removeTapCallback()16175 private void removeTapCallback() { 16176 if (mPendingCheckForTap != null) { 16177 mPrivateFlags &= ~PFLAG_PREPRESSED; 16178 removeCallbacks(mPendingCheckForTap); 16179 } 16180 } 16181 16182 /** 16183 * Cancels a pending long press. Your subclass can use this if you 16184 * want the context menu to come up if the user presses and holds 16185 * at the same place, but you don't want it to come up if they press 16186 * and then move around enough to cause scrolling. 16187 */ cancelLongPress()16188 public void cancelLongPress() { 16189 removeLongPressCallback(); 16190 16191 /* 16192 * The prepressed state handled by the tap callback is a display 16193 * construct, but the tap callback will post a long press callback 16194 * less its own timeout. Remove it here. 16195 */ 16196 removeTapCallback(); 16197 } 16198 16199 /** 16200 * Sets the TouchDelegate for this View. 16201 */ setTouchDelegate(TouchDelegate delegate)16202 public void setTouchDelegate(TouchDelegate delegate) { 16203 mTouchDelegate = delegate; 16204 } 16205 16206 /** 16207 * Gets the TouchDelegate for this View. 16208 */ getTouchDelegate()16209 public TouchDelegate getTouchDelegate() { 16210 return mTouchDelegate; 16211 } 16212 16213 /** 16214 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 16215 * 16216 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 16217 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 16218 * available. This method should only be called for touch events. 16219 * 16220 * <p class="note">This API is not intended for most applications. Buffered dispatch 16221 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 16222 * streams will not improve your input latency. Side effects include: increased latency, 16223 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 16224 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 16225 * you.</p> 16226 * 16227 * To receive unbuffered events for arbitrary input device source classes, use 16228 * {@link #requestUnbufferedDispatch(int)}, 16229 * 16230 * @see View#requestUnbufferedDispatch(int) 16231 */ requestUnbufferedDispatch(MotionEvent event)16232 public final void requestUnbufferedDispatch(MotionEvent event) { 16233 final int action = event.getAction(); 16234 if (mAttachInfo == null 16235 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 16236 || !event.isTouchEvent()) { 16237 return; 16238 } 16239 mAttachInfo.mUnbufferedDispatchRequested = true; 16240 } 16241 16242 /** 16243 * Request unbuffered dispatch of the given event source class to this view. 16244 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 16245 * automatically terminate, and allows the specification of arbitrary input source classes. 16246 * 16247 * @param source The combined input source class to request unbuffered dispatch for. All 16248 * events coming from these source classes will not be buffered. Set to 16249 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 16250 * 16251 * @see View#requestUnbufferedDispatch(MotionEvent) 16252 */ requestUnbufferedDispatch(@nputSourceClass int source)16253 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 16254 if (mUnbufferedInputSource == source) { 16255 return; 16256 } 16257 mUnbufferedInputSource = source; 16258 if (mParent != null) { 16259 mParent.onDescendantUnbufferedRequested(); 16260 } 16261 } 16262 hasSize()16263 private boolean hasSize() { 16264 return (mBottom > mTop) && (mRight > mLeft); 16265 } 16266 canTakeFocus()16267 private boolean canTakeFocus() { 16268 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 16269 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 16270 && ((mViewFlags & ENABLED_MASK) == ENABLED) 16271 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 16272 } 16273 16274 /** 16275 * Set flags controlling behavior of this view. 16276 * 16277 * @param flags Constant indicating the value which should be set 16278 * @param mask Constant indicating the bit range that should be changed 16279 */ 16280 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)16281 void setFlags(int flags, int mask) { 16282 final boolean accessibilityEnabled = 16283 AccessibilityManager.getInstance(mContext).isEnabled(); 16284 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 16285 16286 int old = mViewFlags; 16287 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 16288 16289 int changed = mViewFlags ^ old; 16290 if (changed == 0) { 16291 return; 16292 } 16293 int privateFlags = mPrivateFlags; 16294 boolean shouldNotifyFocusableAvailable = false; 16295 16296 // If focusable is auto, update the FOCUSABLE bit. 16297 int focusableChangedByAuto = 0; 16298 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 16299 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 16300 // Heuristic only takes into account whether view is clickable. 16301 final int newFocus; 16302 if ((mViewFlags & CLICKABLE) != 0) { 16303 newFocus = FOCUSABLE; 16304 } else { 16305 newFocus = NOT_FOCUSABLE; 16306 } 16307 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 16308 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 16309 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 16310 } 16311 16312 /* Check if the FOCUSABLE bit has changed */ 16313 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 16314 if (((old & FOCUSABLE) == FOCUSABLE) 16315 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 16316 /* Give up focus if we are no longer focusable */ 16317 clearFocus(); 16318 if (mParent instanceof ViewGroup) { 16319 ((ViewGroup) mParent).clearFocusedInCluster(); 16320 } 16321 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 16322 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 16323 /* 16324 * Tell the view system that we are now available to take focus 16325 * if no one else already has it. 16326 */ 16327 if (mParent != null) { 16328 ViewRootImpl viewRootImpl = getViewRootImpl(); 16329 if (!sAutoFocusableOffUIThreadWontNotifyParents 16330 || focusableChangedByAuto == 0 16331 || viewRootImpl == null 16332 || viewRootImpl.mThread == Thread.currentThread()) { 16333 shouldNotifyFocusableAvailable = canTakeFocus(); 16334 } 16335 } 16336 } 16337 } 16338 16339 final int newVisibility = flags & VISIBILITY_MASK; 16340 if (newVisibility == VISIBLE) { 16341 if ((changed & VISIBILITY_MASK) != 0) { 16342 /* 16343 * If this view is becoming visible, invalidate it in case it changed while 16344 * it was not visible. Marking it drawn ensures that the invalidation will 16345 * go through. 16346 */ 16347 mPrivateFlags |= PFLAG_DRAWN; 16348 invalidate(true); 16349 16350 needGlobalAttributesUpdate(true); 16351 16352 // a view becoming visible is worth notifying the parent about in case nothing has 16353 // focus. Even if this specific view isn't focusable, it may contain something that 16354 // is, so let the root view try to give this focus if nothing else does. 16355 shouldNotifyFocusableAvailable = hasSize(); 16356 } 16357 } 16358 16359 if ((changed & ENABLED_MASK) != 0) { 16360 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 16361 // a view becoming enabled should notify the parent as long as the view is also 16362 // visible and the parent wasn't already notified by becoming visible during this 16363 // setFlags invocation. 16364 shouldNotifyFocusableAvailable = canTakeFocus(); 16365 } else { 16366 if (isFocused()) clearFocus(); 16367 } 16368 } 16369 16370 if (shouldNotifyFocusableAvailable && mParent != null) { 16371 mParent.focusableViewAvailable(this); 16372 } 16373 16374 /* Check if the GONE bit has changed */ 16375 if ((changed & GONE) != 0) { 16376 needGlobalAttributesUpdate(false); 16377 requestLayout(); 16378 16379 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 16380 if (hasFocus()) { 16381 clearFocus(); 16382 if (mParent instanceof ViewGroup) { 16383 ((ViewGroup) mParent).clearFocusedInCluster(); 16384 } 16385 } 16386 clearAccessibilityFocus(); 16387 destroyDrawingCache(); 16388 if (mParent instanceof View) { 16389 // GONE views noop invalidation, so invalidate the parent 16390 ((View) mParent).invalidate(true); 16391 } 16392 // Mark the view drawn to ensure that it gets invalidated properly the next 16393 // time it is visible and gets invalidated 16394 mPrivateFlags |= PFLAG_DRAWN; 16395 } 16396 if (mAttachInfo != null) { 16397 mAttachInfo.mViewVisibilityChanged = true; 16398 } 16399 } 16400 16401 /* Check if the VISIBLE bit has changed */ 16402 if ((changed & INVISIBLE) != 0) { 16403 needGlobalAttributesUpdate(false); 16404 /* 16405 * If this view is becoming invisible, set the DRAWN flag so that 16406 * the next invalidate() will not be skipped. 16407 */ 16408 mPrivateFlags |= PFLAG_DRAWN; 16409 16410 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 16411 // root view becoming invisible shouldn't clear focus and accessibility focus 16412 if (getRootView() != this) { 16413 if (hasFocus()) { 16414 clearFocus(); 16415 if (mParent instanceof ViewGroup) { 16416 ((ViewGroup) mParent).clearFocusedInCluster(); 16417 } 16418 } 16419 clearAccessibilityFocus(); 16420 } 16421 } 16422 if (mAttachInfo != null) { 16423 mAttachInfo.mViewVisibilityChanged = true; 16424 } 16425 } 16426 16427 if ((changed & VISIBILITY_MASK) != 0) { 16428 // If the view is invisible, cleanup its display list to free up resources 16429 if (newVisibility != VISIBLE && mAttachInfo != null) { 16430 cleanupDraw(); 16431 } 16432 16433 if (mParent instanceof ViewGroup) { 16434 ViewGroup parent = (ViewGroup) mParent; 16435 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 16436 newVisibility); 16437 parent.invalidate(true); 16438 } else if (mParent != null) { 16439 mParent.invalidateChild(this, null); 16440 } 16441 16442 if (mAttachInfo != null) { 16443 dispatchVisibilityChanged(this, newVisibility); 16444 16445 // Aggregated visibility changes are dispatched to attached views 16446 // in visible windows where the parent is currently shown/drawn 16447 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 16448 // discounting clipping or overlapping. This makes it a good place 16449 // to change animation states. 16450 if (mParent != null && getWindowVisibility() == VISIBLE && 16451 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 16452 dispatchVisibilityAggregated(newVisibility == VISIBLE); 16453 } 16454 // If this view is invisible from visible, then sending the A11y event by its 16455 // parent which is shown and has the accessibility important. 16456 if ((old & VISIBILITY_MASK) == VISIBLE) { 16457 notifySubtreeAccessibilityStateChangedByParentIfNeeded(); 16458 } else { 16459 notifySubtreeAccessibilityStateChangedIfNeeded(); 16460 } 16461 } 16462 } 16463 16464 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 16465 destroyDrawingCache(); 16466 } 16467 16468 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 16469 destroyDrawingCache(); 16470 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16471 invalidateParentCaches(); 16472 } 16473 16474 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 16475 destroyDrawingCache(); 16476 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16477 } 16478 16479 if ((changed & DRAW_MASK) != 0) { 16480 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 16481 if (mBackground != null 16482 || mDefaultFocusHighlight != null 16483 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 16484 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 16485 } else { 16486 mPrivateFlags |= PFLAG_SKIP_DRAW; 16487 } 16488 } else { 16489 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 16490 } 16491 requestLayout(); 16492 invalidate(true); 16493 } 16494 16495 if ((changed & KEEP_SCREEN_ON) != 0) { 16496 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 16497 mParent.recomputeViewAttributes(this); 16498 } 16499 } 16500 16501 if (accessibilityEnabled) { 16502 // If we're an accessibility pane and the visibility changed, we already have sent 16503 // a state change, so we really don't need to report other changes. 16504 if (isAccessibilityPane()) { 16505 changed &= ~VISIBILITY_MASK; 16506 } 16507 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 16508 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 16509 || (changed & CONTEXT_CLICKABLE) != 0) { 16510 if (oldIncludeForAccessibility != includeForAccessibility()) { 16511 notifySubtreeAccessibilityStateChangedIfNeeded(); 16512 } else { 16513 notifyViewAccessibilityStateChangedIfNeeded( 16514 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16515 } 16516 } else if ((changed & ENABLED_MASK) != 0) { 16517 notifyViewAccessibilityStateChangedIfNeeded( 16518 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16519 } 16520 } 16521 } 16522 16523 /** 16524 * Change the view's z order in the tree, so it's on top of other sibling 16525 * views. This ordering change may affect layout, if the parent container 16526 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 16527 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 16528 * method should be followed by calls to {@link #requestLayout()} and 16529 * {@link View#invalidate()} on the view's parent to force the parent to redraw 16530 * with the new child ordering. 16531 * 16532 * @see ViewGroup#bringChildToFront(View) 16533 */ bringToFront()16534 public void bringToFront() { 16535 if (mParent != null) { 16536 mParent.bringChildToFront(this); 16537 } 16538 } 16539 16540 /** 16541 * This is called in response to an internal scroll in this view (i.e., the 16542 * view scrolled its own contents). This is typically as a result of 16543 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 16544 * called. 16545 * 16546 * @param l Current horizontal scroll origin. 16547 * @param t Current vertical scroll origin. 16548 * @param oldl Previous horizontal scroll origin. 16549 * @param oldt Previous vertical scroll origin. 16550 */ onScrollChanged(int l, int t, int oldl, int oldt)16551 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 16552 notifySubtreeAccessibilityStateChangedIfNeeded(); 16553 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 16554 16555 mBackgroundSizeChanged = true; 16556 mDefaultFocusHighlightSizeChanged = true; 16557 if (mForegroundInfo != null) { 16558 mForegroundInfo.mBoundsChanged = true; 16559 } 16560 16561 final AttachInfo ai = mAttachInfo; 16562 if (ai != null) { 16563 ai.mViewScrollChanged = true; 16564 } 16565 16566 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 16567 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 16568 } 16569 } 16570 16571 /** 16572 * Interface definition for a callback to be invoked when the scroll 16573 * X or Y positions of a view change. 16574 * <p> 16575 * <b>Note:</b> Some views handle scrolling independently from View and may 16576 * have their own separate listeners for scroll-type events. For example, 16577 * {@link android.widget.ListView ListView} allows clients to register an 16578 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 16579 * to listen for changes in list scroll position. 16580 * 16581 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 16582 */ 16583 public interface OnScrollChangeListener { 16584 /** 16585 * Called when the scroll position of a view changes. 16586 * 16587 * @param v The view whose scroll position has changed. 16588 * @param scrollX Current horizontal scroll origin. 16589 * @param scrollY Current vertical scroll origin. 16590 * @param oldScrollX Previous horizontal scroll origin. 16591 * @param oldScrollY Previous vertical scroll origin. 16592 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)16593 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 16594 } 16595 16596 /** 16597 * Interface definition for a callback to be invoked when the layout bounds of a view 16598 * changes due to layout processing. 16599 */ 16600 public interface OnLayoutChangeListener { 16601 /** 16602 * Called when the layout bounds of a view changes due to layout processing. 16603 * 16604 * @param v The view whose bounds have changed. 16605 * @param left The new value of the view's left property. 16606 * @param top The new value of the view's top property. 16607 * @param right The new value of the view's right property. 16608 * @param bottom The new value of the view's bottom property. 16609 * @param oldLeft The previous value of the view's left property. 16610 * @param oldTop The previous value of the view's top property. 16611 * @param oldRight The previous value of the view's right property. 16612 * @param oldBottom The previous value of the view's bottom property. 16613 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)16614 void onLayoutChange(View v, int left, int top, int right, int bottom, 16615 int oldLeft, int oldTop, int oldRight, int oldBottom); 16616 } 16617 16618 /** 16619 * This is called during layout when the size of this view has changed. If 16620 * you were just added to the view hierarchy, you're called with the old 16621 * values of 0. 16622 * 16623 * @param w Current width of this view. 16624 * @param h Current height of this view. 16625 * @param oldw Old width of this view. 16626 * @param oldh Old height of this view. 16627 */ onSizeChanged(int w, int h, int oldw, int oldh)16628 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 16629 } 16630 16631 /** 16632 * Called by draw to draw the child views. This may be overridden 16633 * by derived classes to gain control just before its children are drawn 16634 * (but after its own view has been drawn). 16635 * @param canvas the canvas on which to draw the view 16636 */ dispatchDraw(Canvas canvas)16637 protected void dispatchDraw(Canvas canvas) { 16638 16639 } 16640 16641 /** 16642 * Gets the parent of this view. Note that the parent is a 16643 * ViewParent and not necessarily a View. 16644 * 16645 * @return Parent of this view. 16646 */ getParent()16647 public final ViewParent getParent() { 16648 return mParent; 16649 } 16650 16651 /** 16652 * Set the horizontal scrolled position of your view. This will cause a call to 16653 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16654 * invalidated. 16655 * @param value the x position to scroll to 16656 */ setScrollX(int value)16657 public void setScrollX(int value) { 16658 scrollTo(value, mScrollY); 16659 } 16660 16661 /** 16662 * Set the vertical scrolled position of your view. This will cause a call to 16663 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16664 * invalidated. 16665 * @param value the y position to scroll to 16666 */ setScrollY(int value)16667 public void setScrollY(int value) { 16668 scrollTo(mScrollX, value); 16669 } 16670 16671 /** 16672 * Return the scrolled left position of this view. This is the left edge of 16673 * the displayed part of your view. You do not need to draw any pixels 16674 * farther left, since those are outside of the frame of your view on 16675 * screen. 16676 * 16677 * @return The left edge of the displayed part of your view, in pixels. 16678 */ 16679 @InspectableProperty getScrollX()16680 public final int getScrollX() { 16681 return mScrollX; 16682 } 16683 16684 /** 16685 * Return the scrolled top position of this view. This is the top edge of 16686 * the displayed part of your view. You do not need to draw any pixels above 16687 * it, since those are outside of the frame of your view on screen. 16688 * 16689 * @return The top edge of the displayed part of your view, in pixels. 16690 */ 16691 @InspectableProperty getScrollY()16692 public final int getScrollY() { 16693 return mScrollY; 16694 } 16695 16696 /** 16697 * Return the width of your view. 16698 * 16699 * @return The width of your view, in pixels. 16700 */ 16701 @ViewDebug.ExportedProperty(category = "layout") getWidth()16702 public final int getWidth() { 16703 return mRight - mLeft; 16704 } 16705 16706 /** 16707 * Return the height of your view. 16708 * 16709 * @return The height of your view, in pixels. 16710 */ 16711 @ViewDebug.ExportedProperty(category = "layout") getHeight()16712 public final int getHeight() { 16713 return mBottom - mTop; 16714 } 16715 16716 /** 16717 * Return the visible drawing bounds of your view. Fills in the output 16718 * rectangle with the values from getScrollX(), getScrollY(), 16719 * getWidth(), and getHeight(). These bounds do not account for any 16720 * transformation properties currently set on the view, such as 16721 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 16722 * 16723 * @param outRect The (scrolled) drawing bounds of the view. 16724 */ getDrawingRect(Rect outRect)16725 public void getDrawingRect(Rect outRect) { 16726 outRect.left = mScrollX; 16727 outRect.top = mScrollY; 16728 outRect.right = mScrollX + (mRight - mLeft); 16729 outRect.bottom = mScrollY + (mBottom - mTop); 16730 } 16731 16732 /** 16733 * Like {@link #getMeasuredWidthAndState()}, but only returns the 16734 * raw width component (that is the result is masked by 16735 * {@link #MEASURED_SIZE_MASK}). 16736 * 16737 * @return The raw measured width of this view. 16738 */ getMeasuredWidth()16739 public final int getMeasuredWidth() { 16740 return mMeasuredWidth & MEASURED_SIZE_MASK; 16741 } 16742 16743 /** 16744 * Return the full width measurement information for this view as computed 16745 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16746 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16747 * This should be used during measurement and layout calculations only. Use 16748 * {@link #getWidth()} to see how wide a view is after layout. 16749 * 16750 * @return The measured width of this view as a bit mask. 16751 */ 16752 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16753 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16754 name = "MEASURED_STATE_TOO_SMALL"), 16755 }) getMeasuredWidthAndState()16756 public final int getMeasuredWidthAndState() { 16757 return mMeasuredWidth; 16758 } 16759 16760 /** 16761 * Like {@link #getMeasuredHeightAndState()}, but only returns the 16762 * raw height component (that is the result is masked by 16763 * {@link #MEASURED_SIZE_MASK}). 16764 * 16765 * @return The raw measured height of this view. 16766 */ getMeasuredHeight()16767 public final int getMeasuredHeight() { 16768 return mMeasuredHeight & MEASURED_SIZE_MASK; 16769 } 16770 16771 /** 16772 * Return the full height measurement information for this view as computed 16773 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16774 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16775 * This should be used during measurement and layout calculations only. Use 16776 * {@link #getHeight()} to see how high a view is after layout. 16777 * 16778 * @return The measured height of this view as a bit mask. 16779 */ 16780 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16781 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16782 name = "MEASURED_STATE_TOO_SMALL"), 16783 }) getMeasuredHeightAndState()16784 public final int getMeasuredHeightAndState() { 16785 return mMeasuredHeight; 16786 } 16787 16788 /** 16789 * Return only the state bits of {@link #getMeasuredWidthAndState()} 16790 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 16791 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 16792 * and the height component is at the shifted bits 16793 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 16794 */ getMeasuredState()16795 public final int getMeasuredState() { 16796 return (mMeasuredWidth&MEASURED_STATE_MASK) 16797 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 16798 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 16799 } 16800 16801 /** 16802 * The transform matrix of this view, which is calculated based on the current 16803 * rotation, scale, and pivot properties. 16804 * 16805 * @see #getRotation() 16806 * @see #getScaleX() 16807 * @see #getScaleY() 16808 * @see #getPivotX() 16809 * @see #getPivotY() 16810 * @return The current transform matrix for the view 16811 */ getMatrix()16812 public Matrix getMatrix() { 16813 ensureTransformationInfo(); 16814 final Matrix matrix = mTransformationInfo.mMatrix; 16815 mRenderNode.getMatrix(matrix); 16816 return matrix; 16817 } 16818 16819 /** 16820 * Returns true if the transform matrix is the identity matrix. 16821 * Recomputes the matrix if necessary. 16822 * 16823 * @return True if the transform matrix is the identity matrix, false otherwise. 16824 * @hide 16825 */ 16826 @UnsupportedAppUsage hasIdentityMatrix()16827 public final boolean hasIdentityMatrix() { 16828 return mRenderNode.hasIdentityMatrix(); 16829 } 16830 16831 @UnsupportedAppUsage ensureTransformationInfo()16832 void ensureTransformationInfo() { 16833 if (mTransformationInfo == null) { 16834 mTransformationInfo = new TransformationInfo(); 16835 } 16836 } 16837 16838 /** 16839 * Utility method to retrieve the inverse of the current mMatrix property. 16840 * We cache the matrix to avoid recalculating it when transform properties 16841 * have not changed. 16842 * 16843 * @return The inverse of the current matrix of this view. 16844 * @hide 16845 */ 16846 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getInverseMatrix()16847 public final Matrix getInverseMatrix() { 16848 ensureTransformationInfo(); 16849 if (mTransformationInfo.mInverseMatrix == null) { 16850 mTransformationInfo.mInverseMatrix = new Matrix(); 16851 } 16852 final Matrix matrix = mTransformationInfo.mInverseMatrix; 16853 mRenderNode.getInverseMatrix(matrix); 16854 return matrix; 16855 } 16856 16857 /** 16858 * Gets the distance along the Z axis from the camera to this view. 16859 * 16860 * @see #setCameraDistance(float) 16861 * 16862 * @return The distance along the Z axis. 16863 */ getCameraDistance()16864 public float getCameraDistance() { 16865 final float dpi = mResources.getDisplayMetrics().densityDpi; 16866 return mRenderNode.getCameraDistance() * dpi; 16867 } 16868 16869 /** 16870 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 16871 * views are drawn) from the camera to this view. The camera's distance 16872 * affects 3D transformations, for instance rotations around the X and Y 16873 * axis. If the rotationX or rotationY properties are changed and this view is 16874 * large (more than half the size of the screen), it is recommended to always 16875 * use a camera distance that's greater than the height (X axis rotation) or 16876 * the width (Y axis rotation) of this view.</p> 16877 * 16878 * <p>The distance of the camera from the view plane can have an affect on the 16879 * perspective distortion of the view when it is rotated around the x or y axis. 16880 * For example, a large distance will result in a large viewing angle, and there 16881 * will not be much perspective distortion of the view as it rotates. A short 16882 * distance may cause much more perspective distortion upon rotation, and can 16883 * also result in some drawing artifacts if the rotated view ends up partially 16884 * behind the camera (which is why the recommendation is to use a distance at 16885 * least as far as the size of the view, if the view is to be rotated.)</p> 16886 * 16887 * <p>The distance is expressed in "depth pixels." The default distance depends 16888 * on the screen density. For instance, on a medium density display, the 16889 * default distance is 1280. On a high density display, the default distance 16890 * is 1920.</p> 16891 * 16892 * <p>If you want to specify a distance that leads to visually consistent 16893 * results across various densities, use the following formula:</p> 16894 * <pre> 16895 * float scale = context.getResources().getDisplayMetrics().density; 16896 * view.setCameraDistance(distance * scale); 16897 * </pre> 16898 * 16899 * <p>The density scale factor of a high density display is 1.5, 16900 * and 1920 = 1280 * 1.5.</p> 16901 * 16902 * @param distance The distance in "depth pixels", if negative the opposite 16903 * value is used 16904 * 16905 * @see #setRotationX(float) 16906 * @see #setRotationY(float) 16907 */ setCameraDistance(float distance)16908 public void setCameraDistance(float distance) { 16909 final float dpi = mResources.getDisplayMetrics().densityDpi; 16910 16911 invalidateViewProperty(true, false); 16912 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 16913 invalidateViewProperty(false, false); 16914 16915 invalidateParentIfNeededAndWasQuickRejected(); 16916 } 16917 16918 /** 16919 * The degrees that the view is rotated around the pivot point. 16920 * 16921 * @see #setRotation(float) 16922 * @see #getPivotX() 16923 * @see #getPivotY() 16924 * 16925 * @return The degrees of rotation. 16926 */ 16927 @ViewDebug.ExportedProperty(category = "drawing") 16928 @InspectableProperty getRotation()16929 public float getRotation() { 16930 return mRenderNode.getRotationZ(); 16931 } 16932 16933 /** 16934 * Sets the degrees that the view is rotated around the pivot point. Increasing values 16935 * result in clockwise rotation. 16936 * 16937 * @param rotation The degrees of rotation. 16938 * 16939 * @see #getRotation() 16940 * @see #getPivotX() 16941 * @see #getPivotY() 16942 * @see #setRotationX(float) 16943 * @see #setRotationY(float) 16944 * 16945 * @attr ref android.R.styleable#View_rotation 16946 */ 16947 @RemotableViewMethod setRotation(float rotation)16948 public void setRotation(float rotation) { 16949 if (rotation != getRotation()) { 16950 // Double-invalidation is necessary to capture view's old and new areas 16951 invalidateViewProperty(true, false); 16952 mRenderNode.setRotationZ(rotation); 16953 invalidateViewProperty(false, true); 16954 16955 invalidateParentIfNeededAndWasQuickRejected(); 16956 notifySubtreeAccessibilityStateChangedIfNeeded(); 16957 } 16958 } 16959 16960 /** 16961 * The degrees that the view is rotated around the vertical axis through the pivot point. 16962 * 16963 * @see #getPivotX() 16964 * @see #getPivotY() 16965 * @see #setRotationY(float) 16966 * 16967 * @return The degrees of Y rotation. 16968 */ 16969 @ViewDebug.ExportedProperty(category = "drawing") 16970 @InspectableProperty getRotationY()16971 public float getRotationY() { 16972 return mRenderNode.getRotationY(); 16973 } 16974 16975 /** 16976 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 16977 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 16978 * down the y axis. 16979 * 16980 * When rotating large views, it is recommended to adjust the camera distance 16981 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 16982 * 16983 * @param rotationY The degrees of Y rotation. 16984 * 16985 * @see #getRotationY() 16986 * @see #getPivotX() 16987 * @see #getPivotY() 16988 * @see #setRotation(float) 16989 * @see #setRotationX(float) 16990 * @see #setCameraDistance(float) 16991 * 16992 * @attr ref android.R.styleable#View_rotationY 16993 */ 16994 @RemotableViewMethod setRotationY(float rotationY)16995 public void setRotationY(float rotationY) { 16996 if (rotationY != getRotationY()) { 16997 invalidateViewProperty(true, false); 16998 mRenderNode.setRotationY(rotationY); 16999 invalidateViewProperty(false, true); 17000 17001 invalidateParentIfNeededAndWasQuickRejected(); 17002 notifySubtreeAccessibilityStateChangedIfNeeded(); 17003 } 17004 } 17005 17006 /** 17007 * The degrees that the view is rotated around the horizontal axis through the pivot point. 17008 * 17009 * @see #getPivotX() 17010 * @see #getPivotY() 17011 * @see #setRotationX(float) 17012 * 17013 * @return The degrees of X rotation. 17014 */ 17015 @ViewDebug.ExportedProperty(category = "drawing") 17016 @InspectableProperty getRotationX()17017 public float getRotationX() { 17018 return mRenderNode.getRotationX(); 17019 } 17020 17021 /** 17022 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 17023 * Increasing values result in clockwise rotation from the viewpoint of looking down the 17024 * x axis. 17025 * 17026 * When rotating large views, it is recommended to adjust the camera distance 17027 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 17028 * 17029 * @param rotationX The degrees of X rotation. 17030 * 17031 * @see #getRotationX() 17032 * @see #getPivotX() 17033 * @see #getPivotY() 17034 * @see #setRotation(float) 17035 * @see #setRotationY(float) 17036 * @see #setCameraDistance(float) 17037 * 17038 * @attr ref android.R.styleable#View_rotationX 17039 */ 17040 @RemotableViewMethod setRotationX(float rotationX)17041 public void setRotationX(float rotationX) { 17042 if (rotationX != getRotationX()) { 17043 invalidateViewProperty(true, false); 17044 mRenderNode.setRotationX(rotationX); 17045 invalidateViewProperty(false, true); 17046 17047 invalidateParentIfNeededAndWasQuickRejected(); 17048 notifySubtreeAccessibilityStateChangedIfNeeded(); 17049 } 17050 } 17051 17052 /** 17053 * The amount that the view is scaled in x around the pivot point, as a proportion of 17054 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 17055 * 17056 * <p>By default, this is 1.0f. 17057 * 17058 * @see #getPivotX() 17059 * @see #getPivotY() 17060 * @return The scaling factor. 17061 */ 17062 @ViewDebug.ExportedProperty(category = "drawing") 17063 @InspectableProperty getScaleX()17064 public float getScaleX() { 17065 return mRenderNode.getScaleX(); 17066 } 17067 17068 /** 17069 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 17070 * the view's unscaled width. A value of 1 means that no scaling is applied. 17071 * 17072 * @param scaleX The scaling factor. 17073 * @see #getPivotX() 17074 * @see #getPivotY() 17075 * 17076 * @attr ref android.R.styleable#View_scaleX 17077 */ 17078 @RemotableViewMethod setScaleX(float scaleX)17079 public void setScaleX(float scaleX) { 17080 if (scaleX != getScaleX()) { 17081 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 17082 invalidateViewProperty(true, false); 17083 mRenderNode.setScaleX(scaleX); 17084 invalidateViewProperty(false, true); 17085 17086 invalidateParentIfNeededAndWasQuickRejected(); 17087 notifySubtreeAccessibilityStateChangedIfNeeded(); 17088 } 17089 } 17090 17091 /** 17092 * The amount that the view is scaled in y around the pivot point, as a proportion of 17093 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 17094 * 17095 * <p>By default, this is 1.0f. 17096 * 17097 * @see #getPivotX() 17098 * @see #getPivotY() 17099 * @return The scaling factor. 17100 */ 17101 @ViewDebug.ExportedProperty(category = "drawing") 17102 @InspectableProperty getScaleY()17103 public float getScaleY() { 17104 return mRenderNode.getScaleY(); 17105 } 17106 17107 /** 17108 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 17109 * the view's unscaled width. A value of 1 means that no scaling is applied. 17110 * 17111 * @param scaleY The scaling factor. 17112 * @see #getPivotX() 17113 * @see #getPivotY() 17114 * 17115 * @attr ref android.R.styleable#View_scaleY 17116 */ 17117 @RemotableViewMethod setScaleY(float scaleY)17118 public void setScaleY(float scaleY) { 17119 if (scaleY != getScaleY()) { 17120 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 17121 invalidateViewProperty(true, false); 17122 mRenderNode.setScaleY(scaleY); 17123 invalidateViewProperty(false, true); 17124 17125 invalidateParentIfNeededAndWasQuickRejected(); 17126 notifySubtreeAccessibilityStateChangedIfNeeded(); 17127 } 17128 } 17129 17130 /** 17131 * The x location of the point around which the view is {@link #setRotation(float) rotated} 17132 * and {@link #setScaleX(float) scaled}. 17133 * 17134 * @see #getRotation() 17135 * @see #getScaleX() 17136 * @see #getScaleY() 17137 * @see #getPivotY() 17138 * @return The x location of the pivot point. 17139 * 17140 * @attr ref android.R.styleable#View_transformPivotX 17141 */ 17142 @ViewDebug.ExportedProperty(category = "drawing") 17143 @InspectableProperty(name = "transformPivotX") getPivotX()17144 public float getPivotX() { 17145 return mRenderNode.getPivotX(); 17146 } 17147 17148 /** 17149 * Sets the x location of the point around which the view is 17150 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 17151 * By default, the pivot point is centered on the object. 17152 * Setting this property disables this behavior and causes the view to use only the 17153 * explicitly set pivotX and pivotY values. 17154 * 17155 * @param pivotX The x location of the pivot point. 17156 * @see #getRotation() 17157 * @see #getScaleX() 17158 * @see #getScaleY() 17159 * @see #getPivotY() 17160 * 17161 * @attr ref android.R.styleable#View_transformPivotX 17162 */ 17163 @RemotableViewMethod setPivotX(float pivotX)17164 public void setPivotX(float pivotX) { 17165 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 17166 invalidateViewProperty(true, false); 17167 mRenderNode.setPivotX(pivotX); 17168 invalidateViewProperty(false, true); 17169 17170 invalidateParentIfNeededAndWasQuickRejected(); 17171 } 17172 } 17173 17174 /** 17175 * The y location of the point around which the view is {@link #setRotation(float) rotated} 17176 * and {@link #setScaleY(float) scaled}. 17177 * 17178 * @see #getRotation() 17179 * @see #getScaleX() 17180 * @see #getScaleY() 17181 * @see #getPivotY() 17182 * @return The y location of the pivot point. 17183 * 17184 * @attr ref android.R.styleable#View_transformPivotY 17185 */ 17186 @ViewDebug.ExportedProperty(category = "drawing") 17187 @InspectableProperty(name = "transformPivotY") getPivotY()17188 public float getPivotY() { 17189 return mRenderNode.getPivotY(); 17190 } 17191 17192 /** 17193 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 17194 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 17195 * Setting this property disables this behavior and causes the view to use only the 17196 * explicitly set pivotX and pivotY values. 17197 * 17198 * @param pivotY The y location of the pivot point. 17199 * @see #getRotation() 17200 * @see #getScaleX() 17201 * @see #getScaleY() 17202 * @see #getPivotY() 17203 * 17204 * @attr ref android.R.styleable#View_transformPivotY 17205 */ 17206 @RemotableViewMethod setPivotY(float pivotY)17207 public void setPivotY(float pivotY) { 17208 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 17209 invalidateViewProperty(true, false); 17210 mRenderNode.setPivotY(pivotY); 17211 invalidateViewProperty(false, true); 17212 17213 invalidateParentIfNeededAndWasQuickRejected(); 17214 } 17215 } 17216 17217 /** 17218 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 17219 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 17220 * of the view. 17221 * 17222 * @return True if a pivot has been set, false if the default pivot is being used 17223 */ isPivotSet()17224 public boolean isPivotSet() { 17225 return mRenderNode.isPivotExplicitlySet(); 17226 } 17227 17228 /** 17229 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 17230 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 17231 * and the pivot used for rotation will return to default of being centered on the view. 17232 */ resetPivot()17233 public void resetPivot() { 17234 if (mRenderNode.resetPivot()) { 17235 invalidateViewProperty(false, false); 17236 } 17237 } 17238 17239 /** 17240 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 17241 * completely transparent and 1 means the view is completely opaque. 17242 * 17243 * <p>By default this is 1.0f. 17244 * @return The opacity of the view. 17245 */ 17246 @ViewDebug.ExportedProperty(category = "drawing") 17247 @InspectableProperty getAlpha()17248 public float getAlpha() { 17249 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 17250 } 17251 17252 /** 17253 * Sets the behavior for overlapping rendering for this view (see {@link 17254 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 17255 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 17256 * providing the value which is then used internally. That is, when {@link 17257 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 17258 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 17259 * instead. 17260 * 17261 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 17262 * instead of that returned by {@link #hasOverlappingRendering()}. 17263 * 17264 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 17265 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)17266 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 17267 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 17268 if (hasOverlappingRendering) { 17269 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17270 } else { 17271 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17272 } 17273 } 17274 17275 /** 17276 * Returns the value for overlapping rendering that is used internally. This is either 17277 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 17278 * the return value of {@link #hasOverlappingRendering()}, otherwise. 17279 * 17280 * @return The value for overlapping rendering being used internally. 17281 */ getHasOverlappingRendering()17282 public final boolean getHasOverlappingRendering() { 17283 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 17284 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 17285 hasOverlappingRendering(); 17286 } 17287 17288 /** 17289 * Returns whether this View has content which overlaps. 17290 * 17291 * <p>This function, intended to be overridden by specific View types, is an optimization when 17292 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 17293 * an offscreen buffer and then composited into place, which can be expensive. If the view has 17294 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 17295 * directly. An example of overlapping rendering is a TextView with a background image, such as 17296 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 17297 * ImageView with only the foreground image. The default implementation returns true; subclasses 17298 * should override if they have cases which can be optimized.</p> 17299 * 17300 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 17301 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 17302 * 17303 * @return true if the content in this view might overlap, false otherwise. 17304 */ 17305 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()17306 public boolean hasOverlappingRendering() { 17307 return true; 17308 } 17309 17310 /** 17311 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 17312 * completely transparent and 1 means the view is completely opaque. 17313 * 17314 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 17315 * can have significant performance implications, especially for large views. It is best to use 17316 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 17317 * 17318 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 17319 * strongly recommended for performance reasons to either override 17320 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 17321 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 17322 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 17323 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 17324 * of rendering cost, even for simple or small views. Starting with 17325 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 17326 * applied to the view at the rendering level.</p> 17327 * 17328 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 17329 * responsible for applying the opacity itself.</p> 17330 * 17331 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 17332 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 17333 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 17334 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 17335 * 17336 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 17337 * value will clip a View to its bounds, unless the View returns <code>false</code> from 17338 * {@link #hasOverlappingRendering}.</p> 17339 * 17340 * @param alpha The opacity of the view. 17341 * 17342 * @see #hasOverlappingRendering() 17343 * @see #setLayerType(int, android.graphics.Paint) 17344 * 17345 * @attr ref android.R.styleable#View_alpha 17346 */ 17347 @RemotableViewMethod setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)17348 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 17349 ensureTransformationInfo(); 17350 if (mTransformationInfo.mAlpha != alpha) { 17351 setAlphaInternal(alpha); 17352 if (onSetAlpha((int) (alpha * 255))) { 17353 mPrivateFlags |= PFLAG_ALPHA_SET; 17354 // subclass is handling alpha - don't optimize rendering cache invalidation 17355 invalidateParentCaches(); 17356 invalidate(true); 17357 } else { 17358 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17359 invalidateViewProperty(true, false); 17360 mRenderNode.setAlpha(getFinalAlpha()); 17361 } 17362 } 17363 } 17364 17365 /** 17366 * Faster version of setAlpha() which performs the same steps except there are 17367 * no calls to invalidate(). The caller of this function should perform proper invalidation 17368 * on the parent and this object. The return value indicates whether the subclass handles 17369 * alpha (the return value for onSetAlpha()). 17370 * 17371 * @param alpha The new value for the alpha property 17372 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 17373 * the new value for the alpha property is different from the old value 17374 */ 17375 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)17376 boolean setAlphaNoInvalidation(float alpha) { 17377 ensureTransformationInfo(); 17378 if (mTransformationInfo.mAlpha != alpha) { 17379 setAlphaInternal(alpha); 17380 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 17381 if (subclassHandlesAlpha) { 17382 mPrivateFlags |= PFLAG_ALPHA_SET; 17383 return true; 17384 } else { 17385 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17386 mRenderNode.setAlpha(getFinalAlpha()); 17387 } 17388 } 17389 return false; 17390 } 17391 setAlphaInternal(float alpha)17392 void setAlphaInternal(float alpha) { 17393 float oldAlpha = mTransformationInfo.mAlpha; 17394 mTransformationInfo.mAlpha = alpha; 17395 // Report visibility changes, which can affect children, to accessibility 17396 if ((alpha == 0) ^ (oldAlpha == 0)) { 17397 notifySubtreeAccessibilityStateChangedIfNeeded(); 17398 } 17399 } 17400 17401 /** 17402 * This property is intended only for use by the Fade transition, which animates it 17403 * to produce a visual translucency that does not side-effect (or get affected by) 17404 * the real alpha property. This value is composited with the other alpha value 17405 * (and the AlphaAnimation value, when that is present) to produce a final visual 17406 * translucency result, which is what is passed into the DisplayList. 17407 */ setTransitionAlpha(float alpha)17408 public void setTransitionAlpha(float alpha) { 17409 ensureTransformationInfo(); 17410 if (mTransformationInfo.mTransitionAlpha != alpha) { 17411 mTransformationInfo.mTransitionAlpha = alpha; 17412 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17413 invalidateViewProperty(true, false); 17414 mRenderNode.setAlpha(getFinalAlpha()); 17415 } 17416 } 17417 17418 /** 17419 * Calculates the visual alpha of this view, which is a combination of the actual 17420 * alpha value and the transitionAlpha value (if set). 17421 */ getFinalAlpha()17422 private float getFinalAlpha() { 17423 if (mTransformationInfo != null) { 17424 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 17425 } 17426 return 1; 17427 } 17428 17429 /** 17430 * This property is intended only for use by the Fade transition, which animates 17431 * it to produce a visual translucency that does not side-effect (or get affected 17432 * by) the real alpha property. This value is composited with the other alpha 17433 * value (and the AlphaAnimation value, when that is present) to produce a final 17434 * visual translucency result, which is what is passed into the DisplayList. 17435 */ 17436 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()17437 public float getTransitionAlpha() { 17438 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 17439 } 17440 17441 /** 17442 * Sets whether or not to allow force dark to apply to this view. 17443 * 17444 * Setting this to false will disable the auto-dark feature on everything this view 17445 * draws, including any descendants. 17446 * 17447 * Setting this to true will allow this view to be automatically made dark, however 17448 * a value of 'true' will not override any 'false' value in its parent chain nor will 17449 * it prevent any 'false' in any of its children. 17450 * 17451 * The default behavior of force dark is also influenced by the Theme's 17452 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 17453 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 17454 * 17455 * @param allow Whether or not to allow force dark. 17456 */ setForceDarkAllowed(boolean allow)17457 public void setForceDarkAllowed(boolean allow) { 17458 if (mRenderNode.setForceDarkAllowed(allow)) { 17459 // Currently toggling force-dark requires a new display list push to apply 17460 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 17461 invalidate(); 17462 } 17463 } 17464 17465 /** 17466 * See {@link #setForceDarkAllowed(boolean)} 17467 * 17468 * @return true if force dark is allowed (default), false if it is disabled 17469 */ 17470 @ViewDebug.ExportedProperty(category = "drawing") 17471 @InspectableProperty isForceDarkAllowed()17472 public boolean isForceDarkAllowed() { 17473 return mRenderNode.isForceDarkAllowed(); 17474 } 17475 17476 /** 17477 * Top position of this view relative to its parent. 17478 * 17479 * @return The top of this view, in pixels. 17480 */ 17481 @ViewDebug.CapturedViewProperty getTop()17482 public final int getTop() { 17483 return mTop; 17484 } 17485 17486 /** 17487 * Sets the top position of this view relative to its parent. This method is meant to be called 17488 * by the layout system and should not generally be called otherwise, because the property 17489 * may be changed at any time by the layout. 17490 * 17491 * @param top The top of this view, in pixels. 17492 */ setTop(int top)17493 public final void setTop(int top) { 17494 if (top != mTop) { 17495 final boolean matrixIsIdentity = hasIdentityMatrix(); 17496 if (matrixIsIdentity) { 17497 if (mAttachInfo != null) { 17498 int minTop; 17499 int yLoc; 17500 if (top < mTop) { 17501 minTop = top; 17502 yLoc = top - mTop; 17503 } else { 17504 minTop = mTop; 17505 yLoc = 0; 17506 } 17507 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 17508 } 17509 } else { 17510 // Double-invalidation is necessary to capture view's old and new areas 17511 invalidate(true); 17512 } 17513 17514 int width = mRight - mLeft; 17515 int oldHeight = mBottom - mTop; 17516 17517 mTop = top; 17518 mRenderNode.setTop(mTop); 17519 17520 sizeChange(width, mBottom - mTop, width, oldHeight); 17521 17522 if (!matrixIsIdentity) { 17523 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17524 invalidate(true); 17525 } 17526 mBackgroundSizeChanged = true; 17527 mDefaultFocusHighlightSizeChanged = true; 17528 if (mForegroundInfo != null) { 17529 mForegroundInfo.mBoundsChanged = true; 17530 } 17531 invalidateParentIfNeeded(); 17532 } 17533 } 17534 17535 /** 17536 * Bottom position of this view relative to its parent. 17537 * 17538 * @return The bottom of this view, in pixels. 17539 */ 17540 @ViewDebug.CapturedViewProperty getBottom()17541 public final int getBottom() { 17542 return mBottom; 17543 } 17544 17545 /** 17546 * True if this view has changed since the last time being drawn. 17547 * 17548 * @return The dirty state of this view. 17549 */ isDirty()17550 public boolean isDirty() { 17551 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 17552 } 17553 17554 /** 17555 * Sets the bottom position of this view relative to its parent. This method is meant to be 17556 * called by the layout system and should not generally be called otherwise, because the 17557 * property may be changed at any time by the layout. 17558 * 17559 * @param bottom The bottom of this view, in pixels. 17560 */ setBottom(int bottom)17561 public final void setBottom(int bottom) { 17562 if (bottom != mBottom) { 17563 final boolean matrixIsIdentity = hasIdentityMatrix(); 17564 if (matrixIsIdentity) { 17565 if (mAttachInfo != null) { 17566 int maxBottom; 17567 if (bottom < mBottom) { 17568 maxBottom = mBottom; 17569 } else { 17570 maxBottom = bottom; 17571 } 17572 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 17573 } 17574 } else { 17575 // Double-invalidation is necessary to capture view's old and new areas 17576 invalidate(true); 17577 } 17578 17579 int width = mRight - mLeft; 17580 int oldHeight = mBottom - mTop; 17581 17582 mBottom = bottom; 17583 mRenderNode.setBottom(mBottom); 17584 17585 sizeChange(width, mBottom - mTop, width, oldHeight); 17586 17587 if (!matrixIsIdentity) { 17588 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17589 invalidate(true); 17590 } 17591 mBackgroundSizeChanged = true; 17592 mDefaultFocusHighlightSizeChanged = true; 17593 if (mForegroundInfo != null) { 17594 mForegroundInfo.mBoundsChanged = true; 17595 } 17596 invalidateParentIfNeeded(); 17597 } 17598 } 17599 17600 /** 17601 * Left position of this view relative to its parent. 17602 * 17603 * @return The left edge of this view, in pixels. 17604 */ 17605 @ViewDebug.CapturedViewProperty getLeft()17606 public final int getLeft() { 17607 return mLeft; 17608 } 17609 17610 /** 17611 * Sets the left position of this view relative to its parent. This method is meant to be called 17612 * by the layout system and should not generally be called otherwise, because the property 17613 * may be changed at any time by the layout. 17614 * 17615 * @param left The left of this view, in pixels. 17616 */ setLeft(int left)17617 public final void setLeft(int left) { 17618 if (left != mLeft) { 17619 final boolean matrixIsIdentity = hasIdentityMatrix(); 17620 if (matrixIsIdentity) { 17621 if (mAttachInfo != null) { 17622 int minLeft; 17623 int xLoc; 17624 if (left < mLeft) { 17625 minLeft = left; 17626 xLoc = left - mLeft; 17627 } else { 17628 minLeft = mLeft; 17629 xLoc = 0; 17630 } 17631 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 17632 } 17633 } else { 17634 // Double-invalidation is necessary to capture view's old and new areas 17635 invalidate(true); 17636 } 17637 17638 int oldWidth = mRight - mLeft; 17639 int height = mBottom - mTop; 17640 17641 mLeft = left; 17642 mRenderNode.setLeft(left); 17643 17644 sizeChange(mRight - mLeft, height, oldWidth, height); 17645 17646 if (!matrixIsIdentity) { 17647 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17648 invalidate(true); 17649 } 17650 mBackgroundSizeChanged = true; 17651 mDefaultFocusHighlightSizeChanged = true; 17652 if (mForegroundInfo != null) { 17653 mForegroundInfo.mBoundsChanged = true; 17654 } 17655 invalidateParentIfNeeded(); 17656 } 17657 } 17658 17659 /** 17660 * Right position of this view relative to its parent. 17661 * 17662 * @return The right edge of this view, in pixels. 17663 */ 17664 @ViewDebug.CapturedViewProperty getRight()17665 public final int getRight() { 17666 return mRight; 17667 } 17668 17669 /** 17670 * Sets the right position of this view relative to its parent. This method is meant to be called 17671 * by the layout system and should not generally be called otherwise, because the property 17672 * may be changed at any time by the layout. 17673 * 17674 * @param right The right of this view, in pixels. 17675 */ setRight(int right)17676 public final void setRight(int right) { 17677 if (right != mRight) { 17678 final boolean matrixIsIdentity = hasIdentityMatrix(); 17679 if (matrixIsIdentity) { 17680 if (mAttachInfo != null) { 17681 int maxRight; 17682 if (right < mRight) { 17683 maxRight = mRight; 17684 } else { 17685 maxRight = right; 17686 } 17687 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 17688 } 17689 } else { 17690 // Double-invalidation is necessary to capture view's old and new areas 17691 invalidate(true); 17692 } 17693 17694 int oldWidth = mRight - mLeft; 17695 int height = mBottom - mTop; 17696 17697 mRight = right; 17698 mRenderNode.setRight(mRight); 17699 17700 sizeChange(mRight - mLeft, height, oldWidth, height); 17701 17702 if (!matrixIsIdentity) { 17703 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17704 invalidate(true); 17705 } 17706 mBackgroundSizeChanged = true; 17707 mDefaultFocusHighlightSizeChanged = true; 17708 if (mForegroundInfo != null) { 17709 mForegroundInfo.mBoundsChanged = true; 17710 } 17711 invalidateParentIfNeeded(); 17712 } 17713 } 17714 sanitizeFloatPropertyValue(float value, String propertyName)17715 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 17716 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 17717 } 17718 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)17719 private static float sanitizeFloatPropertyValue(float value, String propertyName, 17720 float min, float max) { 17721 // The expected "nothing bad happened" path 17722 if (value >= min && value <= max) return value; 17723 17724 if (value < min || value == Float.NEGATIVE_INFINITY) { 17725 if (sThrowOnInvalidFloatProperties) { 17726 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17727 + value + ", the value must be >= " + min); 17728 } 17729 return min; 17730 } 17731 17732 if (value > max || value == Float.POSITIVE_INFINITY) { 17733 if (sThrowOnInvalidFloatProperties) { 17734 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17735 + value + ", the value must be <= " + max); 17736 } 17737 return max; 17738 } 17739 17740 if (Float.isNaN(value)) { 17741 if (sThrowOnInvalidFloatProperties) { 17742 throw new IllegalArgumentException( 17743 "Cannot set '" + propertyName + "' to Float.NaN"); 17744 } 17745 return 0; // Unclear which direction this NaN went so... 0? 17746 } 17747 17748 // Shouldn't be possible to reach this. 17749 throw new IllegalStateException("How do you get here?? " + value); 17750 } 17751 17752 /** 17753 * The visual x position of this view, in pixels. This is equivalent to the 17754 * {@link #setTranslationX(float) translationX} property plus the current 17755 * {@link #getLeft() left} property. 17756 * 17757 * @return The visual x position of this view, in pixels. 17758 */ 17759 @ViewDebug.ExportedProperty(category = "drawing") getX()17760 public float getX() { 17761 return mLeft + getTranslationX(); 17762 } 17763 17764 /** 17765 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 17766 * {@link #setTranslationX(float) translationX} property to be the difference between 17767 * the x value passed in and the current {@link #getLeft() left} property. 17768 * 17769 * @param x The visual x position of this view, in pixels. 17770 */ setX(float x)17771 public void setX(float x) { 17772 setTranslationX(x - mLeft); 17773 } 17774 17775 /** 17776 * The visual y position of this view, in pixels. This is equivalent to the 17777 * {@link #setTranslationY(float) translationY} property plus the current 17778 * {@link #getTop() top} property. 17779 * 17780 * @return The visual y position of this view, in pixels. 17781 */ 17782 @ViewDebug.ExportedProperty(category = "drawing") getY()17783 public float getY() { 17784 return mTop + getTranslationY(); 17785 } 17786 17787 /** 17788 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 17789 * {@link #setTranslationY(float) translationY} property to be the difference between 17790 * the y value passed in and the current {@link #getTop() top} property. 17791 * 17792 * @param y The visual y position of this view, in pixels. 17793 */ setY(float y)17794 public void setY(float y) { 17795 setTranslationY(y - mTop); 17796 } 17797 17798 /** 17799 * The visual z position of this view, in pixels. This is equivalent to the 17800 * {@link #setTranslationZ(float) translationZ} property plus the current 17801 * {@link #getElevation() elevation} property. 17802 * 17803 * @return The visual z position of this view, in pixels. 17804 */ 17805 @ViewDebug.ExportedProperty(category = "drawing") getZ()17806 public float getZ() { 17807 return getElevation() + getTranslationZ(); 17808 } 17809 17810 /** 17811 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 17812 * {@link #setTranslationZ(float) translationZ} property to be the difference between 17813 * the z value passed in and the current {@link #getElevation() elevation} property. 17814 * 17815 * @param z The visual z position of this view, in pixels. 17816 */ setZ(float z)17817 public void setZ(float z) { 17818 setTranslationZ(z - getElevation()); 17819 } 17820 17821 /** 17822 * The base elevation of this view relative to its parent, in pixels. 17823 * 17824 * @return The base depth position of the view, in pixels. 17825 */ 17826 @ViewDebug.ExportedProperty(category = "drawing") 17827 @InspectableProperty getElevation()17828 public float getElevation() { 17829 return mRenderNode.getElevation(); 17830 } 17831 17832 /** 17833 * Sets the base elevation of this view, in pixels. 17834 * 17835 * @attr ref android.R.styleable#View_elevation 17836 */ 17837 @RemotableViewMethod setElevation(float elevation)17838 public void setElevation(float elevation) { 17839 if (elevation != getElevation()) { 17840 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 17841 invalidateViewProperty(true, false); 17842 mRenderNode.setElevation(elevation); 17843 invalidateViewProperty(false, true); 17844 17845 invalidateParentIfNeededAndWasQuickRejected(); 17846 } 17847 } 17848 17849 /** 17850 * The horizontal location of this view relative to its {@link #getLeft() left} position. 17851 * This position is post-layout, in addition to wherever the object's 17852 * layout placed it. 17853 * 17854 * @return The horizontal position of this view relative to its left position, in pixels. 17855 */ 17856 @ViewDebug.ExportedProperty(category = "drawing") 17857 @InspectableProperty getTranslationX()17858 public float getTranslationX() { 17859 return mRenderNode.getTranslationX(); 17860 } 17861 17862 /** 17863 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 17864 * This effectively positions the object post-layout, in addition to wherever the object's 17865 * layout placed it. 17866 * 17867 * @param translationX The horizontal position of this view relative to its left position, 17868 * in pixels. 17869 * 17870 * @attr ref android.R.styleable#View_translationX 17871 */ 17872 @RemotableViewMethod setTranslationX(float translationX)17873 public void setTranslationX(float translationX) { 17874 if (translationX != getTranslationX()) { 17875 invalidateViewProperty(true, false); 17876 mRenderNode.setTranslationX(translationX); 17877 invalidateViewProperty(false, true); 17878 17879 invalidateParentIfNeededAndWasQuickRejected(); 17880 notifySubtreeAccessibilityStateChangedIfNeeded(); 17881 } 17882 } 17883 17884 /** 17885 * The vertical location of this view relative to its {@link #getTop() top} position. 17886 * This position is post-layout, in addition to wherever the object's 17887 * layout placed it. 17888 * 17889 * @return The vertical position of this view relative to its top position, 17890 * in pixels. 17891 */ 17892 @ViewDebug.ExportedProperty(category = "drawing") 17893 @InspectableProperty getTranslationY()17894 public float getTranslationY() { 17895 return mRenderNode.getTranslationY(); 17896 } 17897 17898 /** 17899 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 17900 * This effectively positions the object post-layout, in addition to wherever the object's 17901 * layout placed it. 17902 * 17903 * @param translationY The vertical position of this view relative to its top position, 17904 * in pixels. 17905 * 17906 * @attr ref android.R.styleable#View_translationY 17907 */ 17908 @RemotableViewMethod setTranslationY(float translationY)17909 public void setTranslationY(float translationY) { 17910 if (translationY != getTranslationY()) { 17911 invalidateViewProperty(true, false); 17912 mRenderNode.setTranslationY(translationY); 17913 invalidateViewProperty(false, true); 17914 17915 invalidateParentIfNeededAndWasQuickRejected(); 17916 notifySubtreeAccessibilityStateChangedIfNeeded(); 17917 } 17918 } 17919 17920 /** 17921 * The depth location of this view relative to its {@link #getElevation() elevation}. 17922 * 17923 * @return The depth of this view relative to its elevation. 17924 */ 17925 @ViewDebug.ExportedProperty(category = "drawing") 17926 @InspectableProperty getTranslationZ()17927 public float getTranslationZ() { 17928 return mRenderNode.getTranslationZ(); 17929 } 17930 17931 /** 17932 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 17933 * 17934 * @attr ref android.R.styleable#View_translationZ 17935 */ 17936 @RemotableViewMethod setTranslationZ(float translationZ)17937 public void setTranslationZ(float translationZ) { 17938 if (translationZ != getTranslationZ()) { 17939 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 17940 invalidateViewProperty(true, false); 17941 mRenderNode.setTranslationZ(translationZ); 17942 invalidateViewProperty(false, true); 17943 17944 invalidateParentIfNeededAndWasQuickRejected(); 17945 } 17946 } 17947 17948 /** 17949 * Changes the transformation matrix on the view. This is used in animation frameworks, 17950 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 17951 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 17952 * Application developers should use transformation methods like {@link #setRotation(float)}, 17953 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 17954 * and {@link #setTranslationY(float)} (float)}} instead. 17955 * 17956 * @param matrix The matrix, null indicates that the matrix should be cleared. 17957 * @see #getAnimationMatrix() 17958 */ setAnimationMatrix(@ullable Matrix matrix)17959 public void setAnimationMatrix(@Nullable Matrix matrix) { 17960 invalidateViewProperty(true, false); 17961 mRenderNode.setAnimationMatrix(matrix); 17962 invalidateViewProperty(false, true); 17963 17964 invalidateParentIfNeededAndWasQuickRejected(); 17965 } 17966 17967 /** 17968 * Return the current transformation matrix of the view. This is used in animation frameworks, 17969 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 17970 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 17971 * Application developers should use transformation methods like {@link #setRotation(float)}, 17972 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 17973 * and {@link #setTranslationY(float)} (float)}} instead. 17974 * 17975 * @return the Matrix, null indicates there is no transformation 17976 * @see #setAnimationMatrix(Matrix) 17977 */ 17978 @Nullable getAnimationMatrix()17979 public Matrix getAnimationMatrix() { 17980 return mRenderNode.getAnimationMatrix(); 17981 } 17982 17983 /** 17984 * Returns the current StateListAnimator if exists. 17985 * 17986 * @return StateListAnimator or null if it does not exists 17987 * @see #setStateListAnimator(android.animation.StateListAnimator) 17988 */ 17989 @InspectableProperty getStateListAnimator()17990 public StateListAnimator getStateListAnimator() { 17991 return mStateListAnimator; 17992 } 17993 17994 /** 17995 * Attaches the provided StateListAnimator to this View. 17996 * <p> 17997 * Any previously attached StateListAnimator will be detached. 17998 * 17999 * @param stateListAnimator The StateListAnimator to update the view 18000 * @see android.animation.StateListAnimator 18001 */ setStateListAnimator(StateListAnimator stateListAnimator)18002 public void setStateListAnimator(StateListAnimator stateListAnimator) { 18003 if (mStateListAnimator == stateListAnimator) { 18004 return; 18005 } 18006 if (mStateListAnimator != null) { 18007 mStateListAnimator.setTarget(null); 18008 } 18009 mStateListAnimator = stateListAnimator; 18010 if (stateListAnimator != null) { 18011 stateListAnimator.setTarget(this); 18012 if (isAttachedToWindow()) { 18013 stateListAnimator.setState(getDrawableState()); 18014 } 18015 } 18016 } 18017 18018 /** 18019 * Returns whether the Outline should be used to clip the contents of the View. 18020 * <p> 18021 * Note that this flag will only be respected if the View's Outline returns true from 18022 * {@link Outline#canClip()}. 18023 * 18024 * @see #setOutlineProvider(ViewOutlineProvider) 18025 * @see #setClipToOutline(boolean) 18026 */ getClipToOutline()18027 public final boolean getClipToOutline() { 18028 return mRenderNode.getClipToOutline(); 18029 } 18030 18031 /** 18032 * Sets whether the View's Outline should be used to clip the contents of the View. 18033 * <p> 18034 * Only a single non-rectangular clip can be applied on a View at any time. 18035 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 18036 * circular reveal} animation take priority over Outline clipping, and 18037 * child Outline clipping takes priority over Outline clipping done by a 18038 * parent. 18039 * <p> 18040 * Note that this flag will only be respected if the View's Outline returns true from 18041 * {@link Outline#canClip()}. 18042 * 18043 * @see #setOutlineProvider(ViewOutlineProvider) 18044 * @see #getClipToOutline() 18045 * 18046 * @attr ref android.R.styleable#View_clipToOutline 18047 */ 18048 @RemotableViewMethod setClipToOutline(boolean clipToOutline)18049 public void setClipToOutline(boolean clipToOutline) { 18050 damageInParent(); 18051 if (getClipToOutline() != clipToOutline) { 18052 mRenderNode.setClipToOutline(clipToOutline); 18053 } 18054 } 18055 18056 // correspond to the enum values of View_outlineProvider 18057 private static final int PROVIDER_BACKGROUND = 0; 18058 private static final int PROVIDER_NONE = 1; 18059 private static final int PROVIDER_BOUNDS = 2; 18060 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)18061 private void setOutlineProviderFromAttribute(int providerInt) { 18062 switch (providerInt) { 18063 case PROVIDER_BACKGROUND: 18064 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 18065 break; 18066 case PROVIDER_NONE: 18067 setOutlineProvider(null); 18068 break; 18069 case PROVIDER_BOUNDS: 18070 setOutlineProvider(ViewOutlineProvider.BOUNDS); 18071 break; 18072 case PROVIDER_PADDED_BOUNDS: 18073 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 18074 break; 18075 } 18076 } 18077 18078 /** 18079 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 18080 * the shape of the shadow it casts, and enables outline clipping. 18081 * <p> 18082 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 18083 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 18084 * outline provider with this method allows this behavior to be overridden. 18085 * <p> 18086 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 18087 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 18088 * <p> 18089 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 18090 * 18091 * @see #setClipToOutline(boolean) 18092 * @see #getClipToOutline() 18093 * @see #getOutlineProvider() 18094 */ setOutlineProvider(ViewOutlineProvider provider)18095 public void setOutlineProvider(ViewOutlineProvider provider) { 18096 mOutlineProvider = provider; 18097 invalidateOutline(); 18098 } 18099 18100 /** 18101 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 18102 * that defines the shape of the shadow it casts, and enables outline clipping. 18103 * 18104 * @see #setOutlineProvider(ViewOutlineProvider) 18105 */ 18106 @InspectableProperty getOutlineProvider()18107 public ViewOutlineProvider getOutlineProvider() { 18108 return mOutlineProvider; 18109 } 18110 18111 /** 18112 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 18113 * 18114 * @see #setOutlineProvider(ViewOutlineProvider) 18115 */ invalidateOutline()18116 public void invalidateOutline() { 18117 rebuildOutline(); 18118 18119 notifySubtreeAccessibilityStateChangedIfNeeded(); 18120 invalidateViewProperty(false, false); 18121 } 18122 18123 /** 18124 * Internal version of {@link #invalidateOutline()} which invalidates the 18125 * outline without invalidating the view itself. This is intended to be called from 18126 * within methods in the View class itself which are the result of the view being 18127 * invalidated already. For example, when we are drawing the background of a View, 18128 * we invalidate the outline in case it changed in the meantime, but we do not 18129 * need to invalidate the view because we're already drawing the background as part 18130 * of drawing the view in response to an earlier invalidation of the view. 18131 */ rebuildOutline()18132 private void rebuildOutline() { 18133 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 18134 if (mAttachInfo == null) return; 18135 18136 if (mOutlineProvider == null) { 18137 // no provider, remove outline 18138 mRenderNode.setOutline(null); 18139 } else { 18140 final Outline outline = mAttachInfo.mTmpOutline; 18141 outline.setEmpty(); 18142 outline.setAlpha(1.0f); 18143 18144 mOutlineProvider.getOutline(this, outline); 18145 mRenderNode.setOutline(outline); 18146 } 18147 } 18148 18149 /** 18150 * HierarchyViewer only 18151 * 18152 * @hide 18153 */ 18154 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()18155 public boolean hasShadow() { 18156 return mRenderNode.hasShadow(); 18157 } 18158 18159 /** 18160 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 18161 * elevation value. 18162 * <p> 18163 * By default the shadow color is black. Generally, this color will be opaque so the intensity 18164 * of the shadow is consistent between different views with different colors. 18165 * <p> 18166 * The opacity of the final spot shadow is a function of the shadow caster height, the 18167 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 18168 * {@link android.R.attr#spotShadowAlpha} theme attribute. 18169 * 18170 * @attr ref android.R.styleable#View_outlineSpotShadowColor 18171 * @param color The color this View will cast for its elevation spot shadow. 18172 */ setOutlineSpotShadowColor(@olorInt int color)18173 public void setOutlineSpotShadowColor(@ColorInt int color) { 18174 if (mRenderNode.setSpotShadowColor(color)) { 18175 invalidateViewProperty(true, true); 18176 } 18177 } 18178 18179 /** 18180 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 18181 * was set 18182 */ 18183 @InspectableProperty getOutlineSpotShadowColor()18184 public @ColorInt int getOutlineSpotShadowColor() { 18185 return mRenderNode.getSpotShadowColor(); 18186 } 18187 18188 /** 18189 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 18190 * elevation value. 18191 * <p> 18192 * By default the shadow color is black. Generally, this color will be opaque so the intensity 18193 * of the shadow is consistent between different views with different colors. 18194 * <p> 18195 * The opacity of the final ambient shadow is a function of the shadow caster height, the 18196 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 18197 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 18198 * 18199 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 18200 * @param color The color this View will cast for its elevation shadow. 18201 */ setOutlineAmbientShadowColor(@olorInt int color)18202 public void setOutlineAmbientShadowColor(@ColorInt int color) { 18203 if (mRenderNode.setAmbientShadowColor(color)) { 18204 invalidateViewProperty(true, true); 18205 } 18206 } 18207 18208 /** 18209 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 18210 * nothing was set 18211 */ 18212 @InspectableProperty getOutlineAmbientShadowColor()18213 public @ColorInt int getOutlineAmbientShadowColor() { 18214 return mRenderNode.getAmbientShadowColor(); 18215 } 18216 18217 18218 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)18219 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 18220 mRenderNode.setRevealClip(shouldClip, x, y, radius); 18221 invalidateViewProperty(false, false); 18222 } 18223 18224 /** 18225 * Hit rectangle in parent's coordinates 18226 * 18227 * @param outRect The hit rectangle of the view. 18228 */ getHitRect(Rect outRect)18229 public void getHitRect(Rect outRect) { 18230 if (hasIdentityMatrix() || mAttachInfo == null) { 18231 outRect.set(mLeft, mTop, mRight, mBottom); 18232 } else { 18233 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 18234 tmpRect.set(0, 0, getWidth(), getHeight()); 18235 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 18236 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 18237 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 18238 } 18239 } 18240 18241 /** 18242 * Determines whether the given point, in local coordinates is inside the view. 18243 */ pointInView(float localX, float localY)18244 /*package*/ final boolean pointInView(float localX, float localY) { 18245 return pointInView(localX, localY, 0); 18246 } 18247 18248 /** 18249 * Utility method to determine whether the given point, in local coordinates, 18250 * is inside the view, where the area of the view is expanded by the slop factor. 18251 * This method is called while processing touch-move events to determine if the event 18252 * is still within the view. 18253 * 18254 * @hide 18255 */ 18256 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)18257 public boolean pointInView(float localX, float localY, float slop) { 18258 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 18259 localY < ((mBottom - mTop) + slop); 18260 } 18261 18262 /** 18263 * When a view has focus and the user navigates away from it, the next view is searched for 18264 * starting from the rectangle filled in by this method. 18265 * 18266 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 18267 * of the view. However, if your view maintains some idea of internal selection, 18268 * such as a cursor, or a selected row or column, you should override this method and 18269 * fill in a more specific rectangle. 18270 * 18271 * @param r The rectangle to fill in, in this view's coordinates. 18272 */ getFocusedRect(Rect r)18273 public void getFocusedRect(Rect r) { 18274 getDrawingRect(r); 18275 } 18276 18277 /** 18278 * If some part of this view is not clipped by any of its parents, then 18279 * return that area in r in global (root) coordinates. To convert r to local 18280 * coordinates (without taking possible View rotations into account), offset 18281 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 18282 * If the view is completely clipped or translated out, return false. 18283 * 18284 * @param r If true is returned, r holds the global coordinates of the 18285 * visible portion of this view. 18286 * @param globalOffset If true is returned, globalOffset holds the dx,dy 18287 * between this view and its root. globalOffet may be null. 18288 * @return true if r is non-empty (i.e. part of the view is visible at the 18289 * root level. 18290 */ getGlobalVisibleRect(Rect r, Point globalOffset)18291 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 18292 int width = mRight - mLeft; 18293 int height = mBottom - mTop; 18294 if (width > 0 && height > 0) { 18295 r.set(0, 0, width, height); 18296 if (globalOffset != null) { 18297 globalOffset.set(-mScrollX, -mScrollY); 18298 } 18299 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 18300 } 18301 return false; 18302 } 18303 getGlobalVisibleRect(Rect r)18304 public final boolean getGlobalVisibleRect(Rect r) { 18305 return getGlobalVisibleRect(r, null); 18306 } 18307 getLocalVisibleRect(Rect r)18308 public final boolean getLocalVisibleRect(Rect r) { 18309 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 18310 if (getGlobalVisibleRect(r, offset)) { 18311 r.offset(-offset.x, -offset.y); // make r local 18312 return true; 18313 } 18314 return false; 18315 } 18316 18317 /** 18318 * Offset this view's vertical location by the specified number of pixels. 18319 * 18320 * @param offset the number of pixels to offset the view by 18321 */ offsetTopAndBottom(int offset)18322 public void offsetTopAndBottom(int offset) { 18323 if (offset != 0) { 18324 final boolean matrixIsIdentity = hasIdentityMatrix(); 18325 if (matrixIsIdentity) { 18326 if (isHardwareAccelerated()) { 18327 invalidateViewProperty(false, false); 18328 } else { 18329 final ViewParent p = mParent; 18330 if (p != null && mAttachInfo != null) { 18331 final Rect r = mAttachInfo.mTmpInvalRect; 18332 int minTop; 18333 int maxBottom; 18334 int yLoc; 18335 if (offset < 0) { 18336 minTop = mTop + offset; 18337 maxBottom = mBottom; 18338 yLoc = offset; 18339 } else { 18340 minTop = mTop; 18341 maxBottom = mBottom + offset; 18342 yLoc = 0; 18343 } 18344 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 18345 p.invalidateChild(this, r); 18346 } 18347 } 18348 } else { 18349 invalidateViewProperty(false, false); 18350 } 18351 18352 mTop += offset; 18353 mBottom += offset; 18354 mRenderNode.offsetTopAndBottom(offset); 18355 if (isHardwareAccelerated()) { 18356 invalidateViewProperty(false, false); 18357 invalidateParentIfNeededAndWasQuickRejected(); 18358 } else { 18359 if (!matrixIsIdentity) { 18360 invalidateViewProperty(false, true); 18361 } 18362 invalidateParentIfNeeded(); 18363 } 18364 notifySubtreeAccessibilityStateChangedIfNeeded(); 18365 } 18366 } 18367 18368 /** 18369 * Offset this view's horizontal location by the specified amount of pixels. 18370 * 18371 * @param offset the number of pixels to offset the view by 18372 */ offsetLeftAndRight(int offset)18373 public void offsetLeftAndRight(int offset) { 18374 if (offset != 0) { 18375 final boolean matrixIsIdentity = hasIdentityMatrix(); 18376 if (matrixIsIdentity) { 18377 if (isHardwareAccelerated()) { 18378 invalidateViewProperty(false, false); 18379 } else { 18380 final ViewParent p = mParent; 18381 if (p != null && mAttachInfo != null) { 18382 final Rect r = mAttachInfo.mTmpInvalRect; 18383 int minLeft; 18384 int maxRight; 18385 if (offset < 0) { 18386 minLeft = mLeft + offset; 18387 maxRight = mRight; 18388 } else { 18389 minLeft = mLeft; 18390 maxRight = mRight + offset; 18391 } 18392 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 18393 p.invalidateChild(this, r); 18394 } 18395 } 18396 } else { 18397 invalidateViewProperty(false, false); 18398 } 18399 18400 mLeft += offset; 18401 mRight += offset; 18402 mRenderNode.offsetLeftAndRight(offset); 18403 if (isHardwareAccelerated()) { 18404 invalidateViewProperty(false, false); 18405 invalidateParentIfNeededAndWasQuickRejected(); 18406 } else { 18407 if (!matrixIsIdentity) { 18408 invalidateViewProperty(false, true); 18409 } 18410 invalidateParentIfNeeded(); 18411 } 18412 notifySubtreeAccessibilityStateChangedIfNeeded(); 18413 } 18414 } 18415 18416 /** 18417 * Get the LayoutParams associated with this view. All views should have 18418 * layout parameters. These supply parameters to the <i>parent</i> of this 18419 * view specifying how it should be arranged. There are many subclasses of 18420 * ViewGroup.LayoutParams, and these correspond to the different subclasses 18421 * of ViewGroup that are responsible for arranging their children. 18422 * 18423 * This method may return null if this View is not attached to a parent 18424 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 18425 * was not invoked successfully. When a View is attached to a parent 18426 * ViewGroup, this method must not return null. 18427 * 18428 * @return The LayoutParams associated with this view, or null if no 18429 * parameters have been set yet 18430 */ 18431 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()18432 public ViewGroup.LayoutParams getLayoutParams() { 18433 return mLayoutParams; 18434 } 18435 18436 /** 18437 * Set the layout parameters associated with this view. These supply 18438 * parameters to the <i>parent</i> of this view specifying how it should be 18439 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 18440 * correspond to the different subclasses of ViewGroup that are responsible 18441 * for arranging their children. 18442 * 18443 * @param params The layout parameters for this view, cannot be null 18444 */ setLayoutParams(ViewGroup.LayoutParams params)18445 public void setLayoutParams(ViewGroup.LayoutParams params) { 18446 if (params == null) { 18447 throw new NullPointerException("Layout parameters cannot be null"); 18448 } 18449 mLayoutParams = params; 18450 resolveLayoutParams(); 18451 if (mParent instanceof ViewGroup) { 18452 ((ViewGroup) mParent).onSetLayoutParams(this, params); 18453 } 18454 requestLayout(); 18455 } 18456 18457 /** 18458 * Resolve the layout parameters depending on the resolved layout direction 18459 * 18460 * @hide 18461 */ resolveLayoutParams()18462 public void resolveLayoutParams() { 18463 if (mLayoutParams != null) { 18464 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 18465 } 18466 } 18467 18468 /** 18469 * Set the scrolled position of your view. This will cause a call to 18470 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18471 * invalidated. 18472 * @param x the x position to scroll to 18473 * @param y the y position to scroll to 18474 */ scrollTo(int x, int y)18475 public void scrollTo(int x, int y) { 18476 if (mScrollX != x || mScrollY != y) { 18477 int oldX = mScrollX; 18478 int oldY = mScrollY; 18479 mScrollX = x; 18480 mScrollY = y; 18481 invalidateParentCaches(); 18482 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 18483 if (!awakenScrollBars()) { 18484 postInvalidateOnAnimation(); 18485 } 18486 } 18487 } 18488 18489 /** 18490 * Move the scrolled position of your view. This will cause a call to 18491 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18492 * invalidated. 18493 * @param x the amount of pixels to scroll by horizontally 18494 * @param y the amount of pixels to scroll by vertically 18495 */ scrollBy(int x, int y)18496 public void scrollBy(int x, int y) { 18497 scrollTo(mScrollX + x, mScrollY + y); 18498 } 18499 18500 /** 18501 * <p>Trigger the scrollbars to draw. When invoked this method starts an 18502 * animation to fade the scrollbars out after a default delay. If a subclass 18503 * provides animated scrolling, the start delay should equal the duration 18504 * of the scrolling animation.</p> 18505 * 18506 * <p>The animation starts only if at least one of the scrollbars is 18507 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 18508 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18509 * this method returns true, and false otherwise. If the animation is 18510 * started, this method calls {@link #invalidate()}; in that case the 18511 * caller should not call {@link #invalidate()}.</p> 18512 * 18513 * <p>This method should be invoked every time a subclass directly updates 18514 * the scroll parameters.</p> 18515 * 18516 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 18517 * and {@link #scrollTo(int, int)}.</p> 18518 * 18519 * @return true if the animation is played, false otherwise 18520 * 18521 * @see #awakenScrollBars(int) 18522 * @see #scrollBy(int, int) 18523 * @see #scrollTo(int, int) 18524 * @see #isHorizontalScrollBarEnabled() 18525 * @see #isVerticalScrollBarEnabled() 18526 * @see #setHorizontalScrollBarEnabled(boolean) 18527 * @see #setVerticalScrollBarEnabled(boolean) 18528 */ awakenScrollBars()18529 protected boolean awakenScrollBars() { 18530 return mScrollCache != null && 18531 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 18532 } 18533 18534 /** 18535 * Trigger the scrollbars to draw. 18536 * This method differs from awakenScrollBars() only in its default duration. 18537 * initialAwakenScrollBars() will show the scroll bars for longer than 18538 * usual to give the user more of a chance to notice them. 18539 * 18540 * @return true if the animation is played, false otherwise. 18541 */ initialAwakenScrollBars()18542 private boolean initialAwakenScrollBars() { 18543 return mScrollCache != null && 18544 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 18545 } 18546 18547 /** 18548 * <p> 18549 * Trigger the scrollbars to draw. When invoked this method starts an 18550 * animation to fade the scrollbars out after a fixed delay. If a subclass 18551 * provides animated scrolling, the start delay should equal the duration of 18552 * the scrolling animation. 18553 * </p> 18554 * 18555 * <p> 18556 * The animation starts only if at least one of the scrollbars is enabled, 18557 * as specified by {@link #isHorizontalScrollBarEnabled()} and 18558 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18559 * this method returns true, and false otherwise. If the animation is 18560 * started, this method calls {@link #invalidate()}; in that case the caller 18561 * should not call {@link #invalidate()}. 18562 * </p> 18563 * 18564 * <p> 18565 * This method should be invoked every time a subclass directly updates the 18566 * scroll parameters. 18567 * </p> 18568 * 18569 * @param startDelay the delay, in milliseconds, after which the animation 18570 * should start; when the delay is 0, the animation starts 18571 * immediately 18572 * @return true if the animation is played, false otherwise 18573 * 18574 * @see #scrollBy(int, int) 18575 * @see #scrollTo(int, int) 18576 * @see #isHorizontalScrollBarEnabled() 18577 * @see #isVerticalScrollBarEnabled() 18578 * @see #setHorizontalScrollBarEnabled(boolean) 18579 * @see #setVerticalScrollBarEnabled(boolean) 18580 */ awakenScrollBars(int startDelay)18581 protected boolean awakenScrollBars(int startDelay) { 18582 return awakenScrollBars(startDelay, true); 18583 } 18584 18585 /** 18586 * <p> 18587 * Trigger the scrollbars to draw. When invoked this method starts an 18588 * animation to fade the scrollbars out after a fixed delay. If a subclass 18589 * provides animated scrolling, the start delay should equal the duration of 18590 * the scrolling animation. 18591 * </p> 18592 * 18593 * <p> 18594 * The animation starts only if at least one of the scrollbars is enabled, 18595 * as specified by {@link #isHorizontalScrollBarEnabled()} and 18596 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18597 * this method returns true, and false otherwise. If the animation is 18598 * started, this method calls {@link #invalidate()} if the invalidate parameter 18599 * is set to true; in that case the caller 18600 * should not call {@link #invalidate()}. 18601 * </p> 18602 * 18603 * <p> 18604 * This method should be invoked every time a subclass directly updates the 18605 * scroll parameters. 18606 * </p> 18607 * 18608 * @param startDelay the delay, in milliseconds, after which the animation 18609 * should start; when the delay is 0, the animation starts 18610 * immediately 18611 * 18612 * @param invalidate Whether this method should call invalidate 18613 * 18614 * @return true if the animation is played, false otherwise 18615 * 18616 * @see #scrollBy(int, int) 18617 * @see #scrollTo(int, int) 18618 * @see #isHorizontalScrollBarEnabled() 18619 * @see #isVerticalScrollBarEnabled() 18620 * @see #setHorizontalScrollBarEnabled(boolean) 18621 * @see #setVerticalScrollBarEnabled(boolean) 18622 */ awakenScrollBars(int startDelay, boolean invalidate)18623 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 18624 final ScrollabilityCache scrollCache = mScrollCache; 18625 18626 if (scrollCache == null || !scrollCache.fadeScrollBars) { 18627 return false; 18628 } 18629 18630 if (scrollCache.scrollBar == null) { 18631 scrollCache.scrollBar = new ScrollBarDrawable(); 18632 scrollCache.scrollBar.setState(getDrawableState()); 18633 scrollCache.scrollBar.setCallback(this); 18634 } 18635 18636 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 18637 18638 if (invalidate) { 18639 // Invalidate to show the scrollbars 18640 postInvalidateOnAnimation(); 18641 } 18642 18643 if (scrollCache.state == ScrollabilityCache.OFF) { 18644 // FIXME: this is copied from WindowManagerService. 18645 // We should get this value from the system when it 18646 // is possible to do so. 18647 final int KEY_REPEAT_FIRST_DELAY = 750; 18648 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 18649 } 18650 18651 // Tell mScrollCache when we should start fading. This may 18652 // extend the fade start time if one was already scheduled 18653 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 18654 scrollCache.fadeStartTime = fadeStartTime; 18655 scrollCache.state = ScrollabilityCache.ON; 18656 18657 // Schedule our fader to run, unscheduling any old ones first 18658 if (mAttachInfo != null) { 18659 mAttachInfo.mHandler.removeCallbacks(scrollCache); 18660 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 18661 } 18662 18663 return true; 18664 } 18665 18666 return false; 18667 } 18668 18669 /** 18670 * Do not invalidate views which are not visible and which are not running an animation. They 18671 * will not get drawn and they should not set dirty flags as if they will be drawn 18672 */ skipInvalidate()18673 private boolean skipInvalidate() { 18674 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 18675 (!(mParent instanceof ViewGroup) || 18676 !((ViewGroup) mParent).isViewTransitioning(this)); 18677 } 18678 18679 /** 18680 * Mark the area defined by dirty as needing to be drawn. If the view is 18681 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18682 * point in the future. 18683 * <p> 18684 * This must be called from a UI thread. To call from a non-UI thread, call 18685 * {@link #postInvalidate()}. 18686 * <p> 18687 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 18688 * {@code dirty}. 18689 * 18690 * @param dirty the rectangle representing the bounds of the dirty region 18691 * 18692 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18693 * the importance of the dirty rectangle. In API 21 the given rectangle is 18694 * ignored entirely in favor of an internally-calculated area instead. 18695 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18696 */ 18697 @Deprecated invalidate(Rect dirty)18698 public void invalidate(Rect dirty) { 18699 final int scrollX = mScrollX; 18700 final int scrollY = mScrollY; 18701 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 18702 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 18703 } 18704 18705 /** 18706 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 18707 * coordinates of the dirty rect are relative to the view. If the view is 18708 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18709 * point in the future. 18710 * <p> 18711 * This must be called from a UI thread. To call from a non-UI thread, call 18712 * {@link #postInvalidate()}. 18713 * 18714 * @param l the left position of the dirty region 18715 * @param t the top position of the dirty region 18716 * @param r the right position of the dirty region 18717 * @param b the bottom position of the dirty region 18718 * 18719 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18720 * the importance of the dirty rectangle. In API 21 the given rectangle is 18721 * ignored entirely in favor of an internally-calculated area instead. 18722 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18723 */ 18724 @Deprecated invalidate(int l, int t, int r, int b)18725 public void invalidate(int l, int t, int r, int b) { 18726 final int scrollX = mScrollX; 18727 final int scrollY = mScrollY; 18728 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 18729 } 18730 18731 /** 18732 * Invalidate the whole view. If the view is visible, 18733 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 18734 * the future. 18735 * <p> 18736 * This must be called from a UI thread. To call from a non-UI thread, call 18737 * {@link #postInvalidate()}. 18738 */ invalidate()18739 public void invalidate() { 18740 invalidate(true); 18741 } 18742 18743 /** 18744 * This is where the invalidate() work actually happens. A full invalidate() 18745 * causes the drawing cache to be invalidated, but this function can be 18746 * called with invalidateCache set to false to skip that invalidation step 18747 * for cases that do not need it (for example, a component that remains at 18748 * the same dimensions with the same content). 18749 * 18750 * @param invalidateCache Whether the drawing cache for this view should be 18751 * invalidated as well. This is usually true for a full 18752 * invalidate, but may be set to false if the View's contents or 18753 * dimensions have not changed. 18754 * @hide 18755 */ 18756 @UnsupportedAppUsage invalidate(boolean invalidateCache)18757 public void invalidate(boolean invalidateCache) { 18758 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 18759 } 18760 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)18761 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 18762 boolean fullInvalidate) { 18763 if (mGhostView != null) { 18764 mGhostView.invalidate(true); 18765 return; 18766 } 18767 18768 if (skipInvalidate()) { 18769 return; 18770 } 18771 18772 // Reset content capture caches 18773 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 18774 mContentCaptureSessionCached = false; 18775 18776 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 18777 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 18778 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 18779 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 18780 if (fullInvalidate) { 18781 mLastIsOpaque = isOpaque(); 18782 mPrivateFlags &= ~PFLAG_DRAWN; 18783 } 18784 18785 mPrivateFlags |= PFLAG_DIRTY; 18786 18787 if (invalidateCache) { 18788 mPrivateFlags |= PFLAG_INVALIDATED; 18789 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18790 } 18791 18792 // Propagate the damage rectangle to the parent view. 18793 final AttachInfo ai = mAttachInfo; 18794 final ViewParent p = mParent; 18795 if (p != null && ai != null && l < r && t < b) { 18796 final Rect damage = ai.mTmpInvalRect; 18797 damage.set(l, t, r, b); 18798 p.invalidateChild(this, damage); 18799 } 18800 18801 // Damage the entire projection receiver, if necessary. 18802 if (mBackground != null && mBackground.isProjected()) { 18803 final View receiver = getProjectionReceiver(); 18804 if (receiver != null) { 18805 receiver.damageInParent(); 18806 } 18807 } 18808 } 18809 } 18810 18811 /** 18812 * @return this view's projection receiver, or {@code null} if none exists 18813 */ getProjectionReceiver()18814 private View getProjectionReceiver() { 18815 ViewParent p = getParent(); 18816 while (p != null && p instanceof View) { 18817 final View v = (View) p; 18818 if (v.isProjectionReceiver()) { 18819 return v; 18820 } 18821 p = p.getParent(); 18822 } 18823 18824 return null; 18825 } 18826 18827 /** 18828 * @return whether the view is a projection receiver 18829 */ isProjectionReceiver()18830 private boolean isProjectionReceiver() { 18831 return mBackground != null; 18832 } 18833 18834 /** 18835 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 18836 * set any flags or handle all of the cases handled by the default invalidation methods. 18837 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 18838 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 18839 * walk up the hierarchy, transforming the dirty rect as necessary. 18840 * 18841 * The method also handles normal invalidation logic if display list properties are not 18842 * being used in this view. The invalidateParent and forceRedraw flags are used by that 18843 * backup approach, to handle these cases used in the various property-setting methods. 18844 * 18845 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 18846 * are not being used in this view 18847 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 18848 * list properties are not being used in this view 18849 */ 18850 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)18851 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 18852 if (!isHardwareAccelerated() 18853 || !mRenderNode.hasDisplayList() 18854 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 18855 if (invalidateParent) { 18856 invalidateParentCaches(); 18857 } 18858 if (forceRedraw) { 18859 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18860 } 18861 invalidate(false); 18862 } else { 18863 damageInParent(); 18864 } 18865 } 18866 18867 /** 18868 * Tells the parent view to damage this view's bounds. 18869 * 18870 * @hide 18871 */ damageInParent()18872 protected void damageInParent() { 18873 if (mParent != null && mAttachInfo != null) { 18874 mParent.onDescendantInvalidated(this, this); 18875 } 18876 } 18877 18878 /** 18879 * Used to indicate that the parent of this view should clear its caches. This functionality 18880 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18881 * which is necessary when various parent-managed properties of the view change, such as 18882 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 18883 * clears the parent caches and does not causes an invalidate event. 18884 * 18885 * @hide 18886 */ 18887 @UnsupportedAppUsage invalidateParentCaches()18888 protected void invalidateParentCaches() { 18889 if (mParent instanceof View) { 18890 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 18891 } 18892 } 18893 18894 /** 18895 * Used to indicate that the parent of this view should be invalidated. This functionality 18896 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18897 * which is necessary when various parent-managed properties of the view change, such as 18898 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 18899 * an invalidation event to the parent. 18900 * 18901 * @hide 18902 */ 18903 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) invalidateParentIfNeeded()18904 protected void invalidateParentIfNeeded() { 18905 if (isHardwareAccelerated() && mParent instanceof View) { 18906 ((View) mParent).invalidate(true); 18907 } 18908 } 18909 18910 /** 18911 * @hide 18912 */ invalidateParentIfNeededAndWasQuickRejected()18913 protected void invalidateParentIfNeededAndWasQuickRejected() { 18914 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 18915 // View was rejected last time it was drawn by its parent; this may have changed 18916 invalidateParentIfNeeded(); 18917 } 18918 } 18919 18920 /** 18921 * Indicates whether this View is opaque. An opaque View guarantees that it will 18922 * draw all the pixels overlapping its bounds using a fully opaque color. 18923 * 18924 * Subclasses of View should override this method whenever possible to indicate 18925 * whether an instance is opaque. Opaque Views are treated in a special way by 18926 * the View hierarchy, possibly allowing it to perform optimizations during 18927 * invalidate/draw passes. 18928 * 18929 * @return True if this View is guaranteed to be fully opaque, false otherwise. 18930 */ 18931 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()18932 public boolean isOpaque() { 18933 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 18934 getFinalAlpha() >= 1.0f; 18935 } 18936 18937 /** 18938 * @hide 18939 */ 18940 @UnsupportedAppUsage computeOpaqueFlags()18941 protected void computeOpaqueFlags() { 18942 // Opaque if: 18943 // - Has a background 18944 // - Background is opaque 18945 // - Doesn't have scrollbars or scrollbars overlay 18946 18947 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 18948 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 18949 } else { 18950 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 18951 } 18952 18953 final int flags = mViewFlags; 18954 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 18955 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 18956 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 18957 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 18958 } else { 18959 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 18960 } 18961 } 18962 18963 /** 18964 * @hide 18965 */ hasOpaqueScrollbars()18966 protected boolean hasOpaqueScrollbars() { 18967 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 18968 } 18969 18970 /** 18971 * @return A handler associated with the thread running the View. This 18972 * handler can be used to pump events in the UI events queue. 18973 */ getHandler()18974 public Handler getHandler() { 18975 final AttachInfo attachInfo = mAttachInfo; 18976 if (attachInfo != null) { 18977 return attachInfo.mHandler; 18978 } 18979 return null; 18980 } 18981 18982 /** 18983 * Returns the queue of runnable for this view. 18984 * 18985 * @return the queue of runnables for this view 18986 */ getRunQueue()18987 private HandlerActionQueue getRunQueue() { 18988 if (mRunQueue == null) { 18989 mRunQueue = new HandlerActionQueue(); 18990 } 18991 return mRunQueue; 18992 } 18993 18994 /** 18995 * Gets the view root associated with the View. 18996 * @return The view root, or null if none. 18997 * @hide 18998 */ 18999 @UnsupportedAppUsage getViewRootImpl()19000 public ViewRootImpl getViewRootImpl() { 19001 if (mAttachInfo != null) { 19002 return mAttachInfo.mViewRootImpl; 19003 } 19004 return null; 19005 } 19006 19007 /** 19008 * @hide 19009 */ 19010 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getThreadedRenderer()19011 public ThreadedRenderer getThreadedRenderer() { 19012 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 19013 } 19014 19015 /** 19016 * <p>Causes the Runnable to be added to the message queue. 19017 * The runnable will be run on the user interface thread.</p> 19018 * 19019 * @param action The Runnable that will be executed. 19020 * 19021 * @return Returns true if the Runnable was successfully placed in to the 19022 * message queue. Returns false on failure, usually because the 19023 * looper processing the message queue is exiting. 19024 * 19025 * @see #postDelayed 19026 * @see #removeCallbacks 19027 */ post(Runnable action)19028 public boolean post(Runnable action) { 19029 final AttachInfo attachInfo = mAttachInfo; 19030 if (attachInfo != null) { 19031 return attachInfo.mHandler.post(action); 19032 } 19033 19034 // Postpone the runnable until we know on which thread it needs to run. 19035 // Assume that the runnable will be successfully placed after attach. 19036 getRunQueue().post(action); 19037 return true; 19038 } 19039 19040 /** 19041 * <p>Causes the Runnable to be added to the message queue, to be run 19042 * after the specified amount of time elapses. 19043 * The runnable will be run on the user interface thread.</p> 19044 * 19045 * @param action The Runnable that will be executed. 19046 * @param delayMillis The delay (in milliseconds) until the Runnable 19047 * will be executed. 19048 * 19049 * @return true if the Runnable was successfully placed in to the 19050 * message queue. Returns false on failure, usually because the 19051 * looper processing the message queue is exiting. Note that a 19052 * result of true does not mean the Runnable will be processed -- 19053 * if the looper is quit before the delivery time of the message 19054 * occurs then the message will be dropped. 19055 * 19056 * @see #post 19057 * @see #removeCallbacks 19058 */ postDelayed(Runnable action, long delayMillis)19059 public boolean postDelayed(Runnable action, long delayMillis) { 19060 final AttachInfo attachInfo = mAttachInfo; 19061 if (attachInfo != null) { 19062 return attachInfo.mHandler.postDelayed(action, delayMillis); 19063 } 19064 19065 // Postpone the runnable until we know on which thread it needs to run. 19066 // Assume that the runnable will be successfully placed after attach. 19067 getRunQueue().postDelayed(action, delayMillis); 19068 return true; 19069 } 19070 19071 /** 19072 * <p>Causes the Runnable to execute on the next animation time step. 19073 * The runnable will be run on the user interface thread.</p> 19074 * 19075 * @param action The Runnable that will be executed. 19076 * 19077 * @see #postOnAnimationDelayed 19078 * @see #removeCallbacks 19079 */ postOnAnimation(Runnable action)19080 public void postOnAnimation(Runnable action) { 19081 final AttachInfo attachInfo = mAttachInfo; 19082 if (attachInfo != null) { 19083 attachInfo.mViewRootImpl.mChoreographer.postCallback( 19084 Choreographer.CALLBACK_ANIMATION, action, null); 19085 } else { 19086 // Postpone the runnable until we know 19087 // on which thread it needs to run. 19088 getRunQueue().post(action); 19089 } 19090 } 19091 19092 /** 19093 * <p>Causes the Runnable to execute on the next animation time step, 19094 * after the specified amount of time elapses. 19095 * The runnable will be run on the user interface thread.</p> 19096 * 19097 * @param action The Runnable that will be executed. 19098 * @param delayMillis The delay (in milliseconds) until the Runnable 19099 * will be executed. 19100 * 19101 * @see #postOnAnimation 19102 * @see #removeCallbacks 19103 */ postOnAnimationDelayed(Runnable action, long delayMillis)19104 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 19105 final AttachInfo attachInfo = mAttachInfo; 19106 if (attachInfo != null) { 19107 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19108 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 19109 } else { 19110 // Postpone the runnable until we know 19111 // on which thread it needs to run. 19112 getRunQueue().postDelayed(action, delayMillis); 19113 } 19114 } 19115 19116 /** 19117 * <p>Removes the specified Runnable from the message queue.</p> 19118 * 19119 * @param action The Runnable to remove from the message handling queue 19120 * 19121 * @return true if this view could ask the Handler to remove the Runnable, 19122 * false otherwise. When the returned value is true, the Runnable 19123 * may or may not have been actually removed from the message queue 19124 * (for instance, if the Runnable was not in the queue already.) 19125 * 19126 * @see #post 19127 * @see #postDelayed 19128 * @see #postOnAnimation 19129 * @see #postOnAnimationDelayed 19130 */ removeCallbacks(Runnable action)19131 public boolean removeCallbacks(Runnable action) { 19132 if (action != null) { 19133 final AttachInfo attachInfo = mAttachInfo; 19134 if (attachInfo != null) { 19135 attachInfo.mHandler.removeCallbacks(action); 19136 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19137 Choreographer.CALLBACK_ANIMATION, action, null); 19138 } 19139 getRunQueue().removeCallbacks(action); 19140 } 19141 return true; 19142 } 19143 19144 /** 19145 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 19146 * Use this to invalidate the View from a non-UI thread.</p> 19147 * 19148 * <p>This method can be invoked from outside of the UI thread 19149 * only when this View is attached to a window.</p> 19150 * 19151 * @see #invalidate() 19152 * @see #postInvalidateDelayed(long) 19153 */ postInvalidate()19154 public void postInvalidate() { 19155 postInvalidateDelayed(0); 19156 } 19157 19158 /** 19159 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 19160 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 19161 * 19162 * <p>This method can be invoked from outside of the UI thread 19163 * only when this View is attached to a window.</p> 19164 * 19165 * @param left The left coordinate of the rectangle to invalidate. 19166 * @param top The top coordinate of the rectangle to invalidate. 19167 * @param right The right coordinate of the rectangle to invalidate. 19168 * @param bottom The bottom coordinate of the rectangle to invalidate. 19169 * 19170 * @see #invalidate(int, int, int, int) 19171 * @see #invalidate(Rect) 19172 * @see #postInvalidateDelayed(long, int, int, int, int) 19173 */ postInvalidate(int left, int top, int right, int bottom)19174 public void postInvalidate(int left, int top, int right, int bottom) { 19175 postInvalidateDelayed(0, left, top, right, bottom); 19176 } 19177 19178 /** 19179 * <p>Cause an invalidate to happen on a subsequent cycle through the event 19180 * loop. Waits for the specified amount of time.</p> 19181 * 19182 * <p>This method can be invoked from outside of the UI thread 19183 * only when this View is attached to a window.</p> 19184 * 19185 * @param delayMilliseconds the duration in milliseconds to delay the 19186 * invalidation by 19187 * 19188 * @see #invalidate() 19189 * @see #postInvalidate() 19190 */ postInvalidateDelayed(long delayMilliseconds)19191 public void postInvalidateDelayed(long delayMilliseconds) { 19192 // We try only with the AttachInfo because there's no point in invalidating 19193 // if we are not attached to our window 19194 final AttachInfo attachInfo = mAttachInfo; 19195 if (attachInfo != null) { 19196 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 19197 } 19198 } 19199 19200 /** 19201 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 19202 * through the event loop. Waits for the specified amount of time.</p> 19203 * 19204 * <p>This method can be invoked from outside of the UI thread 19205 * only when this View is attached to a window.</p> 19206 * 19207 * @param delayMilliseconds the duration in milliseconds to delay the 19208 * invalidation by 19209 * @param left The left coordinate of the rectangle to invalidate. 19210 * @param top The top coordinate of the rectangle to invalidate. 19211 * @param right The right coordinate of the rectangle to invalidate. 19212 * @param bottom The bottom coordinate of the rectangle to invalidate. 19213 * 19214 * @see #invalidate(int, int, int, int) 19215 * @see #invalidate(Rect) 19216 * @see #postInvalidate(int, int, int, int) 19217 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)19218 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 19219 int right, int bottom) { 19220 19221 // We try only with the AttachInfo because there's no point in invalidating 19222 // if we are not attached to our window 19223 final AttachInfo attachInfo = mAttachInfo; 19224 if (attachInfo != null) { 19225 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19226 info.target = this; 19227 info.left = left; 19228 info.top = top; 19229 info.right = right; 19230 info.bottom = bottom; 19231 19232 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 19233 } 19234 } 19235 19236 /** 19237 * <p>Cause an invalidate to happen on the next animation time step, typically the 19238 * next display frame.</p> 19239 * 19240 * <p>This method can be invoked from outside of the UI thread 19241 * only when this View is attached to a window.</p> 19242 * 19243 * @see #invalidate() 19244 */ postInvalidateOnAnimation()19245 public void postInvalidateOnAnimation() { 19246 // We try only with the AttachInfo because there's no point in invalidating 19247 // if we are not attached to our window 19248 final AttachInfo attachInfo = mAttachInfo; 19249 if (attachInfo != null) { 19250 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 19251 } 19252 } 19253 19254 /** 19255 * <p>Cause an invalidate of the specified area to happen on the next animation 19256 * time step, typically the next display frame.</p> 19257 * 19258 * <p>This method can be invoked from outside of the UI thread 19259 * only when this View is attached to a window.</p> 19260 * 19261 * @param left The left coordinate of the rectangle to invalidate. 19262 * @param top The top coordinate of the rectangle to invalidate. 19263 * @param right The right coordinate of the rectangle to invalidate. 19264 * @param bottom The bottom coordinate of the rectangle to invalidate. 19265 * 19266 * @see #invalidate(int, int, int, int) 19267 * @see #invalidate(Rect) 19268 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)19269 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 19270 // We try only with the AttachInfo because there's no point in invalidating 19271 // if we are not attached to our window 19272 final AttachInfo attachInfo = mAttachInfo; 19273 if (attachInfo != null) { 19274 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19275 info.target = this; 19276 info.left = left; 19277 info.top = top; 19278 info.right = right; 19279 info.bottom = bottom; 19280 19281 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 19282 } 19283 } 19284 19285 /** 19286 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 19287 * This event is sent at most once every 19288 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 19289 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)19290 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 19291 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 19292 AccessibilityEvent event = 19293 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 19294 event.setScrollDeltaX(dx); 19295 event.setScrollDeltaY(dy); 19296 sendAccessibilityEventUnchecked(event); 19297 } 19298 } 19299 19300 /** 19301 * Called by a parent to request that a child update its values for mScrollX 19302 * and mScrollY if necessary. This will typically be done if the child is 19303 * animating a scroll using a {@link android.widget.Scroller Scroller} 19304 * object. 19305 */ computeScroll()19306 public void computeScroll() { 19307 } 19308 19309 /** 19310 * <p>Indicate whether the horizontal edges are faded when the view is 19311 * scrolled horizontally.</p> 19312 * 19313 * @return true if the horizontal edges should are faded on scroll, false 19314 * otherwise 19315 * 19316 * @see #setHorizontalFadingEdgeEnabled(boolean) 19317 * 19318 * @attr ref android.R.styleable#View_requiresFadingEdge 19319 */ isHorizontalFadingEdgeEnabled()19320 public boolean isHorizontalFadingEdgeEnabled() { 19321 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 19322 } 19323 19324 /** 19325 * <p>Define whether the horizontal edges should be faded when this view 19326 * is scrolled horizontally.</p> 19327 * 19328 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 19329 * be faded when the view is scrolled 19330 * horizontally 19331 * 19332 * @see #isHorizontalFadingEdgeEnabled() 19333 * 19334 * @attr ref android.R.styleable#View_requiresFadingEdge 19335 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)19336 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 19337 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 19338 if (horizontalFadingEdgeEnabled) { 19339 initScrollCache(); 19340 } 19341 19342 mViewFlags ^= FADING_EDGE_HORIZONTAL; 19343 } 19344 } 19345 19346 /** 19347 * <p>Indicate whether the vertical edges are faded when the view is 19348 * scrolled horizontally.</p> 19349 * 19350 * @return true if the vertical edges should are faded on scroll, false 19351 * otherwise 19352 * 19353 * @see #setVerticalFadingEdgeEnabled(boolean) 19354 * 19355 * @attr ref android.R.styleable#View_requiresFadingEdge 19356 */ isVerticalFadingEdgeEnabled()19357 public boolean isVerticalFadingEdgeEnabled() { 19358 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 19359 } 19360 19361 /** 19362 * <p>Define whether the vertical edges should be faded when this view 19363 * is scrolled vertically.</p> 19364 * 19365 * @param verticalFadingEdgeEnabled true if the vertical edges should 19366 * be faded when the view is scrolled 19367 * vertically 19368 * 19369 * @see #isVerticalFadingEdgeEnabled() 19370 * 19371 * @attr ref android.R.styleable#View_requiresFadingEdge 19372 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)19373 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 19374 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 19375 if (verticalFadingEdgeEnabled) { 19376 initScrollCache(); 19377 } 19378 19379 mViewFlags ^= FADING_EDGE_VERTICAL; 19380 } 19381 } 19382 19383 /** 19384 * Get the fading edge flags, used for inspection. 19385 * 19386 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 19387 * or {@link #FADING_EDGE_HORIZONTAL} 19388 * @hide 19389 */ 19390 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 19391 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 19392 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 19393 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 19394 }) getFadingEdge()19395 public int getFadingEdge() { 19396 return mViewFlags & FADING_EDGE_MASK; 19397 } 19398 19399 /** 19400 * Get the fading edge length, used for inspection 19401 * 19402 * @return The fading edge length or 0 19403 * @hide 19404 */ 19405 @InspectableProperty getFadingEdgeLength()19406 public int getFadingEdgeLength() { 19407 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 19408 return mScrollCache.fadingEdgeLength; 19409 } 19410 return 0; 19411 } 19412 19413 /** 19414 * Returns the strength, or intensity, of the top faded edge. The strength is 19415 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19416 * returns 0.0 or 1.0 but no value in between. 19417 * 19418 * Subclasses should override this method to provide a smoother fade transition 19419 * when scrolling occurs. 19420 * 19421 * @return the intensity of the top fade as a float between 0.0f and 1.0f 19422 */ getTopFadingEdgeStrength()19423 protected float getTopFadingEdgeStrength() { 19424 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 19425 } 19426 19427 /** 19428 * Returns the strength, or intensity, of the bottom faded edge. The strength is 19429 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19430 * returns 0.0 or 1.0 but no value in between. 19431 * 19432 * Subclasses should override this method to provide a smoother fade transition 19433 * when scrolling occurs. 19434 * 19435 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 19436 */ getBottomFadingEdgeStrength()19437 protected float getBottomFadingEdgeStrength() { 19438 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 19439 computeVerticalScrollRange() ? 1.0f : 0.0f; 19440 } 19441 19442 /** 19443 * Returns the strength, or intensity, of the left faded edge. The strength is 19444 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19445 * returns 0.0 or 1.0 but no value in between. 19446 * 19447 * Subclasses should override this method to provide a smoother fade transition 19448 * when scrolling occurs. 19449 * 19450 * @return the intensity of the left fade as a float between 0.0f and 1.0f 19451 */ getLeftFadingEdgeStrength()19452 protected float getLeftFadingEdgeStrength() { 19453 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 19454 } 19455 19456 /** 19457 * Returns the strength, or intensity, of the right faded edge. The strength is 19458 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19459 * returns 0.0 or 1.0 but no value in between. 19460 * 19461 * Subclasses should override this method to provide a smoother fade transition 19462 * when scrolling occurs. 19463 * 19464 * @return the intensity of the right fade as a float between 0.0f and 1.0f 19465 */ getRightFadingEdgeStrength()19466 protected float getRightFadingEdgeStrength() { 19467 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 19468 computeHorizontalScrollRange() ? 1.0f : 0.0f; 19469 } 19470 19471 /** 19472 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 19473 * scrollbar is not drawn by default.</p> 19474 * 19475 * @return true if the horizontal scrollbar should be painted, false 19476 * otherwise 19477 * 19478 * @see #setHorizontalScrollBarEnabled(boolean) 19479 */ isHorizontalScrollBarEnabled()19480 public boolean isHorizontalScrollBarEnabled() { 19481 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 19482 } 19483 19484 /** 19485 * <p>Define whether the horizontal scrollbar should be drawn or not. The 19486 * scrollbar is not drawn by default.</p> 19487 * 19488 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 19489 * be painted 19490 * 19491 * @see #isHorizontalScrollBarEnabled() 19492 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)19493 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 19494 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 19495 mViewFlags ^= SCROLLBARS_HORIZONTAL; 19496 computeOpaqueFlags(); 19497 resolvePadding(); 19498 } 19499 } 19500 19501 /** 19502 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 19503 * scrollbar is not drawn by default.</p> 19504 * 19505 * @return true if the vertical scrollbar should be painted, false 19506 * otherwise 19507 * 19508 * @see #setVerticalScrollBarEnabled(boolean) 19509 */ isVerticalScrollBarEnabled()19510 public boolean isVerticalScrollBarEnabled() { 19511 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 19512 } 19513 19514 /** 19515 * <p>Define whether the vertical scrollbar should be drawn or not. The 19516 * scrollbar is not drawn by default.</p> 19517 * 19518 * @param verticalScrollBarEnabled true if the vertical scrollbar should 19519 * be painted 19520 * 19521 * @see #isVerticalScrollBarEnabled() 19522 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)19523 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 19524 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 19525 mViewFlags ^= SCROLLBARS_VERTICAL; 19526 computeOpaqueFlags(); 19527 resolvePadding(); 19528 } 19529 } 19530 19531 /** 19532 * @hide 19533 */ 19534 @UnsupportedAppUsage recomputePadding()19535 protected void recomputePadding() { 19536 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 19537 } 19538 19539 /** 19540 * Define whether scrollbars will fade when the view is not scrolling. 19541 * 19542 * @param fadeScrollbars whether to enable fading 19543 * 19544 * @attr ref android.R.styleable#View_fadeScrollbars 19545 */ setScrollbarFadingEnabled(boolean fadeScrollbars)19546 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 19547 initScrollCache(); 19548 final ScrollabilityCache scrollabilityCache = mScrollCache; 19549 scrollabilityCache.fadeScrollBars = fadeScrollbars; 19550 if (fadeScrollbars) { 19551 scrollabilityCache.state = ScrollabilityCache.OFF; 19552 } else { 19553 scrollabilityCache.state = ScrollabilityCache.ON; 19554 } 19555 } 19556 19557 /** 19558 * 19559 * Returns true if scrollbars will fade when this view is not scrolling 19560 * 19561 * @return true if scrollbar fading is enabled 19562 * 19563 * @attr ref android.R.styleable#View_fadeScrollbars 19564 */ isScrollbarFadingEnabled()19565 public boolean isScrollbarFadingEnabled() { 19566 return mScrollCache != null && mScrollCache.fadeScrollBars; 19567 } 19568 19569 /** 19570 * 19571 * Returns the delay before scrollbars fade. 19572 * 19573 * @return the delay before scrollbars fade 19574 * 19575 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 19576 */ 19577 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()19578 public int getScrollBarDefaultDelayBeforeFade() { 19579 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 19580 mScrollCache.scrollBarDefaultDelayBeforeFade; 19581 } 19582 19583 /** 19584 * Define the delay before scrollbars fade. 19585 * 19586 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 19587 * 19588 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 19589 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)19590 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 19591 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 19592 } 19593 19594 /** 19595 * 19596 * Returns the scrollbar fade duration. 19597 * 19598 * @return the scrollbar fade duration, in milliseconds 19599 * 19600 * @attr ref android.R.styleable#View_scrollbarFadeDuration 19601 */ 19602 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()19603 public int getScrollBarFadeDuration() { 19604 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 19605 mScrollCache.scrollBarFadeDuration; 19606 } 19607 19608 /** 19609 * Define the scrollbar fade duration. 19610 * 19611 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 19612 * 19613 * @attr ref android.R.styleable#View_scrollbarFadeDuration 19614 */ setScrollBarFadeDuration(int scrollBarFadeDuration)19615 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 19616 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 19617 } 19618 19619 /** 19620 * 19621 * Returns the scrollbar size. 19622 * 19623 * @return the scrollbar size 19624 * 19625 * @attr ref android.R.styleable#View_scrollbarSize 19626 */ 19627 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()19628 public int getScrollBarSize() { 19629 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 19630 mScrollCache.scrollBarSize; 19631 } 19632 19633 /** 19634 * Define the scrollbar size. 19635 * 19636 * @param scrollBarSize - the scrollbar size 19637 * 19638 * @attr ref android.R.styleable#View_scrollbarSize 19639 */ setScrollBarSize(int scrollBarSize)19640 public void setScrollBarSize(int scrollBarSize) { 19641 getScrollCache().scrollBarSize = scrollBarSize; 19642 } 19643 19644 /** 19645 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 19646 * inset. When inset, they add to the padding of the view. And the scrollbars 19647 * can be drawn inside the padding area or on the edge of the view. For example, 19648 * if a view has a background drawable and you want to draw the scrollbars 19649 * inside the padding specified by the drawable, you can use 19650 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 19651 * appear at the edge of the view, ignoring the padding, then you can use 19652 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 19653 * @param style the style of the scrollbars. Should be one of 19654 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 19655 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 19656 * @see #SCROLLBARS_INSIDE_OVERLAY 19657 * @see #SCROLLBARS_INSIDE_INSET 19658 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19659 * @see #SCROLLBARS_OUTSIDE_INSET 19660 * 19661 * @attr ref android.R.styleable#View_scrollbarStyle 19662 */ setScrollBarStyle(@crollBarStyle int style)19663 public void setScrollBarStyle(@ScrollBarStyle int style) { 19664 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 19665 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 19666 computeOpaqueFlags(); 19667 resolvePadding(); 19668 } 19669 } 19670 19671 /** 19672 * <p>Returns the current scrollbar style.</p> 19673 * @return the current scrollbar style 19674 * @see #SCROLLBARS_INSIDE_OVERLAY 19675 * @see #SCROLLBARS_INSIDE_INSET 19676 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19677 * @see #SCROLLBARS_OUTSIDE_INSET 19678 * 19679 * @attr ref android.R.styleable#View_scrollbarStyle 19680 */ 19681 @ViewDebug.ExportedProperty(mapping = { 19682 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 19683 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 19684 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 19685 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 19686 }) 19687 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 19688 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 19689 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 19690 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 19691 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 19692 }) 19693 @ScrollBarStyle getScrollBarStyle()19694 public int getScrollBarStyle() { 19695 return mViewFlags & SCROLLBARS_STYLE_MASK; 19696 } 19697 19698 /** 19699 * <p>Compute the horizontal range that the horizontal scrollbar 19700 * represents.</p> 19701 * 19702 * <p>The range is expressed in arbitrary units that must be the same as the 19703 * units used by {@link #computeHorizontalScrollExtent()} and 19704 * {@link #computeHorizontalScrollOffset()}.</p> 19705 * 19706 * <p>The default range is the drawing width of this view.</p> 19707 * 19708 * @return the total horizontal range represented by the horizontal 19709 * scrollbar 19710 * 19711 * @see #computeHorizontalScrollExtent() 19712 * @see #computeHorizontalScrollOffset() 19713 */ computeHorizontalScrollRange()19714 protected int computeHorizontalScrollRange() { 19715 return getWidth(); 19716 } 19717 19718 /** 19719 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 19720 * within the horizontal range. This value is used to compute the position 19721 * of the thumb within the scrollbar's track.</p> 19722 * 19723 * <p>The range is expressed in arbitrary units that must be the same as the 19724 * units used by {@link #computeHorizontalScrollRange()} and 19725 * {@link #computeHorizontalScrollExtent()}.</p> 19726 * 19727 * <p>The default offset is the scroll offset of this view.</p> 19728 * 19729 * @return the horizontal offset of the scrollbar's thumb 19730 * 19731 * @see #computeHorizontalScrollRange() 19732 * @see #computeHorizontalScrollExtent() 19733 */ computeHorizontalScrollOffset()19734 protected int computeHorizontalScrollOffset() { 19735 return mScrollX; 19736 } 19737 19738 /** 19739 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 19740 * within the horizontal range. This value is used to compute the length 19741 * of the thumb within the scrollbar's track.</p> 19742 * 19743 * <p>The range is expressed in arbitrary units that must be the same as the 19744 * units used by {@link #computeHorizontalScrollRange()} and 19745 * {@link #computeHorizontalScrollOffset()}.</p> 19746 * 19747 * <p>The default extent is the drawing width of this view.</p> 19748 * 19749 * @return the horizontal extent of the scrollbar's thumb 19750 * 19751 * @see #computeHorizontalScrollRange() 19752 * @see #computeHorizontalScrollOffset() 19753 */ computeHorizontalScrollExtent()19754 protected int computeHorizontalScrollExtent() { 19755 return getWidth(); 19756 } 19757 19758 /** 19759 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 19760 * 19761 * <p>The range is expressed in arbitrary units that must be the same as the 19762 * units used by {@link #computeVerticalScrollExtent()} and 19763 * {@link #computeVerticalScrollOffset()}.</p> 19764 * 19765 * @return the total vertical range represented by the vertical scrollbar 19766 * 19767 * <p>The default range is the drawing height of this view.</p> 19768 * 19769 * @see #computeVerticalScrollExtent() 19770 * @see #computeVerticalScrollOffset() 19771 */ computeVerticalScrollRange()19772 protected int computeVerticalScrollRange() { 19773 return getHeight(); 19774 } 19775 19776 /** 19777 * <p>Compute the vertical offset of the vertical scrollbar's thumb 19778 * within the horizontal range. This value is used to compute the position 19779 * of the thumb within the scrollbar's track.</p> 19780 * 19781 * <p>The range is expressed in arbitrary units that must be the same as the 19782 * units used by {@link #computeVerticalScrollRange()} and 19783 * {@link #computeVerticalScrollExtent()}.</p> 19784 * 19785 * <p>The default offset is the scroll offset of this view.</p> 19786 * 19787 * @return the vertical offset of the scrollbar's thumb 19788 * 19789 * @see #computeVerticalScrollRange() 19790 * @see #computeVerticalScrollExtent() 19791 */ computeVerticalScrollOffset()19792 protected int computeVerticalScrollOffset() { 19793 return mScrollY; 19794 } 19795 19796 /** 19797 * <p>Compute the vertical extent of the vertical scrollbar's thumb 19798 * within the vertical range. This value is used to compute the length 19799 * of the thumb within the scrollbar's track.</p> 19800 * 19801 * <p>The range is expressed in arbitrary units that must be the same as the 19802 * units used by {@link #computeVerticalScrollRange()} and 19803 * {@link #computeVerticalScrollOffset()}.</p> 19804 * 19805 * <p>The default extent is the drawing height of this view.</p> 19806 * 19807 * @return the vertical extent of the scrollbar's thumb 19808 * 19809 * @see #computeVerticalScrollRange() 19810 * @see #computeVerticalScrollOffset() 19811 */ computeVerticalScrollExtent()19812 protected int computeVerticalScrollExtent() { 19813 return getHeight(); 19814 } 19815 19816 /** 19817 * Check if this view can be scrolled horizontally in a certain direction. 19818 * 19819 * @param direction Negative to check scrolling left, positive to check scrolling right. 19820 * @return true if this view can be scrolled in the specified direction, false otherwise. 19821 */ canScrollHorizontally(int direction)19822 public boolean canScrollHorizontally(int direction) { 19823 final int offset = computeHorizontalScrollOffset(); 19824 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 19825 if (range == 0) return false; 19826 if (direction < 0) { 19827 return offset > 0; 19828 } else { 19829 return offset < range - 1; 19830 } 19831 } 19832 19833 /** 19834 * Check if this view can be scrolled vertically in a certain direction. 19835 * 19836 * @param direction Negative to check scrolling up, positive to check scrolling down. 19837 * @return true if this view can be scrolled in the specified direction, false otherwise. 19838 */ canScrollVertically(int direction)19839 public boolean canScrollVertically(int direction) { 19840 final int offset = computeVerticalScrollOffset(); 19841 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 19842 if (range == 0) return false; 19843 if (direction < 0) { 19844 return offset > 0; 19845 } else { 19846 return offset < range - 1; 19847 } 19848 } 19849 getScrollIndicatorBounds(@onNull Rect out)19850 void getScrollIndicatorBounds(@NonNull Rect out) { 19851 out.left = mScrollX; 19852 out.right = mScrollX + mRight - mLeft; 19853 out.top = mScrollY; 19854 out.bottom = mScrollY + mBottom - mTop; 19855 } 19856 onDrawScrollIndicators(Canvas c)19857 private void onDrawScrollIndicators(Canvas c) { 19858 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 19859 // No scroll indicators enabled. 19860 return; 19861 } 19862 19863 final Drawable dr = mScrollIndicatorDrawable; 19864 if (dr == null) { 19865 // Scroll indicators aren't supported here. 19866 return; 19867 } 19868 19869 if (mAttachInfo == null) { 19870 // View is not attached. 19871 return; 19872 } 19873 19874 final int h = dr.getIntrinsicHeight(); 19875 final int w = dr.getIntrinsicWidth(); 19876 final Rect rect = mAttachInfo.mTmpInvalRect; 19877 getScrollIndicatorBounds(rect); 19878 19879 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 19880 final boolean canScrollUp = canScrollVertically(-1); 19881 if (canScrollUp) { 19882 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 19883 dr.draw(c); 19884 } 19885 } 19886 19887 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 19888 final boolean canScrollDown = canScrollVertically(1); 19889 if (canScrollDown) { 19890 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 19891 dr.draw(c); 19892 } 19893 } 19894 19895 final int leftRtl; 19896 final int rightRtl; 19897 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 19898 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 19899 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 19900 } else { 19901 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 19902 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 19903 } 19904 19905 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 19906 if ((mPrivateFlags3 & leftMask) != 0) { 19907 final boolean canScrollLeft = canScrollHorizontally(-1); 19908 if (canScrollLeft) { 19909 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 19910 dr.draw(c); 19911 } 19912 } 19913 19914 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 19915 if ((mPrivateFlags3 & rightMask) != 0) { 19916 final boolean canScrollRight = canScrollHorizontally(1); 19917 if (canScrollRight) { 19918 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 19919 dr.draw(c); 19920 } 19921 } 19922 } 19923 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19924 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 19925 @Nullable Rect touchBounds) { 19926 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19927 if (bounds == null) { 19928 return; 19929 } 19930 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19931 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 19932 && !isVerticalScrollBarHidden(); 19933 final int size = getHorizontalScrollbarHeight(); 19934 final int verticalScrollBarGap = drawVerticalScrollBar ? 19935 getVerticalScrollbarWidth() : 0; 19936 final int width = mRight - mLeft; 19937 final int height = mBottom - mTop; 19938 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 19939 bounds.left = mScrollX + (mPaddingLeft & inside); 19940 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 19941 bounds.bottom = bounds.top + size; 19942 19943 if (touchBounds == null) { 19944 return; 19945 } 19946 if (touchBounds != bounds) { 19947 touchBounds.set(bounds); 19948 } 19949 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 19950 if (touchBounds.height() < minTouchTarget) { 19951 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 19952 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 19953 touchBounds.top = touchBounds.bottom - minTouchTarget; 19954 } 19955 if (touchBounds.width() < minTouchTarget) { 19956 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 19957 touchBounds.left -= adjust; 19958 touchBounds.right = touchBounds.left + minTouchTarget; 19959 } 19960 } 19961 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)19962 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 19963 if (mRoundScrollbarRenderer == null) { 19964 getStraightVerticalScrollBarBounds(bounds, touchBounds); 19965 } else { 19966 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 19967 } 19968 } 19969 getRoundVerticalScrollBarBounds(Rect bounds)19970 private void getRoundVerticalScrollBarBounds(Rect bounds) { 19971 final int width = mRight - mLeft; 19972 final int height = mBottom - mTop; 19973 // Do not take padding into account as we always want the scrollbars 19974 // to hug the screen for round wearable devices. 19975 bounds.left = mScrollX; 19976 bounds.top = mScrollY; 19977 bounds.right = bounds.left + width; 19978 bounds.bottom = mScrollY + height; 19979 } 19980 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19981 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 19982 @Nullable Rect touchBounds) { 19983 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19984 if (bounds == null) { 19985 return; 19986 } 19987 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19988 final int size = getVerticalScrollbarWidth(); 19989 int verticalScrollbarPosition = mVerticalScrollbarPosition; 19990 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 19991 verticalScrollbarPosition = isLayoutRtl() ? 19992 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 19993 } 19994 final int width = mRight - mLeft; 19995 final int height = mBottom - mTop; 19996 switch (verticalScrollbarPosition) { 19997 default: 19998 case SCROLLBAR_POSITION_RIGHT: 19999 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 20000 break; 20001 case SCROLLBAR_POSITION_LEFT: 20002 bounds.left = mScrollX + (mUserPaddingLeft & inside); 20003 break; 20004 } 20005 bounds.top = mScrollY + (mPaddingTop & inside); 20006 bounds.right = bounds.left + size; 20007 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 20008 20009 if (touchBounds == null) { 20010 return; 20011 } 20012 if (touchBounds != bounds) { 20013 touchBounds.set(bounds); 20014 } 20015 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 20016 if (touchBounds.width() < minTouchTarget) { 20017 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 20018 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 20019 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 20020 touchBounds.left = touchBounds.right - minTouchTarget; 20021 } else { 20022 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 20023 touchBounds.right = touchBounds.left + minTouchTarget; 20024 } 20025 } 20026 if (touchBounds.height() < minTouchTarget) { 20027 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 20028 touchBounds.top -= adjust; 20029 touchBounds.bottom = touchBounds.top + minTouchTarget; 20030 } 20031 } 20032 20033 /** 20034 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 20035 * scrollbars are painted only if they have been awakened first.</p> 20036 * 20037 * @param canvas the canvas on which to draw the scrollbars 20038 * 20039 * @see #awakenScrollBars(int) 20040 */ onDrawScrollBars(Canvas canvas)20041 protected final void onDrawScrollBars(Canvas canvas) { 20042 // scrollbars are drawn only when the animation is running 20043 final ScrollabilityCache cache = mScrollCache; 20044 20045 if (cache != null) { 20046 20047 int state = cache.state; 20048 20049 if (state == ScrollabilityCache.OFF) { 20050 return; 20051 } 20052 20053 boolean invalidate = false; 20054 20055 if (state == ScrollabilityCache.FADING) { 20056 // We're fading -- get our fade interpolation 20057 if (cache.interpolatorValues == null) { 20058 cache.interpolatorValues = new float[1]; 20059 } 20060 20061 float[] values = cache.interpolatorValues; 20062 20063 // Stops the animation if we're done 20064 if (cache.scrollBarInterpolator.timeToValues(values) == 20065 Interpolator.Result.FREEZE_END) { 20066 cache.state = ScrollabilityCache.OFF; 20067 } else { 20068 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 20069 } 20070 20071 // This will make the scroll bars inval themselves after 20072 // drawing. We only want this when we're fading so that 20073 // we prevent excessive redraws 20074 invalidate = true; 20075 } else { 20076 // We're just on -- but we may have been fading before so 20077 // reset alpha 20078 cache.scrollBar.mutate().setAlpha(255); 20079 } 20080 20081 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 20082 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 20083 && !isVerticalScrollBarHidden(); 20084 20085 // Fork out the scroll bar drawing for round wearable devices. 20086 if (mRoundScrollbarRenderer != null) { 20087 if (drawVerticalScrollBar) { 20088 final Rect bounds = cache.mScrollBarBounds; 20089 getVerticalScrollBarBounds(bounds, null); 20090 mRoundScrollbarRenderer.drawRoundScrollbars( 20091 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 20092 if (invalidate) { 20093 invalidate(); 20094 } 20095 } 20096 // Do not draw horizontal scroll bars for round wearable devices. 20097 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 20098 final ScrollBarDrawable scrollBar = cache.scrollBar; 20099 20100 if (drawHorizontalScrollBar) { 20101 scrollBar.setParameters(computeHorizontalScrollRange(), 20102 computeHorizontalScrollOffset(), 20103 computeHorizontalScrollExtent(), false); 20104 final Rect bounds = cache.mScrollBarBounds; 20105 getHorizontalScrollBarBounds(bounds, null); 20106 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 20107 bounds.right, bounds.bottom); 20108 if (invalidate) { 20109 invalidate(bounds); 20110 } 20111 } 20112 20113 if (drawVerticalScrollBar) { 20114 scrollBar.setParameters(computeVerticalScrollRange(), 20115 computeVerticalScrollOffset(), 20116 computeVerticalScrollExtent(), true); 20117 final Rect bounds = cache.mScrollBarBounds; 20118 getVerticalScrollBarBounds(bounds, null); 20119 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 20120 bounds.right, bounds.bottom); 20121 if (invalidate) { 20122 invalidate(bounds); 20123 } 20124 } 20125 } 20126 } 20127 } 20128 20129 /** 20130 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 20131 * FastScroller is visible. 20132 * @return whether to temporarily hide the vertical scrollbar 20133 * @hide 20134 */ isVerticalScrollBarHidden()20135 protected boolean isVerticalScrollBarHidden() { 20136 return false; 20137 } 20138 20139 /** 20140 * <p>Draw the horizontal scrollbar if 20141 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 20142 * 20143 * @param canvas the canvas on which to draw the scrollbar 20144 * @param scrollBar the scrollbar's drawable 20145 * 20146 * @see #isHorizontalScrollBarEnabled() 20147 * @see #computeHorizontalScrollRange() 20148 * @see #computeHorizontalScrollExtent() 20149 * @see #computeHorizontalScrollOffset() 20150 * @hide 20151 */ 20152 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)20153 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 20154 int l, int t, int r, int b) { 20155 scrollBar.setBounds(l, t, r, b); 20156 scrollBar.draw(canvas); 20157 } 20158 20159 /** 20160 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 20161 * returns true.</p> 20162 * 20163 * @param canvas the canvas on which to draw the scrollbar 20164 * @param scrollBar the scrollbar's drawable 20165 * 20166 * @see #isVerticalScrollBarEnabled() 20167 * @see #computeVerticalScrollRange() 20168 * @see #computeVerticalScrollExtent() 20169 * @see #computeVerticalScrollOffset() 20170 * @hide 20171 */ 20172 @UnsupportedAppUsage onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)20173 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 20174 int l, int t, int r, int b) { 20175 scrollBar.setBounds(l, t, r, b); 20176 scrollBar.draw(canvas); 20177 } 20178 20179 /** 20180 * Implement this to do your drawing. 20181 * 20182 * @param canvas the canvas on which the background will be drawn 20183 */ onDraw(Canvas canvas)20184 protected void onDraw(Canvas canvas) { 20185 } 20186 20187 /* 20188 * Caller is responsible for calling requestLayout if necessary. 20189 * (This allows addViewInLayout to not request a new layout.) 20190 */ 20191 @UnsupportedAppUsage assignParent(ViewParent parent)20192 void assignParent(ViewParent parent) { 20193 if (mParent == null) { 20194 mParent = parent; 20195 } else if (parent == null) { 20196 mParent = null; 20197 } else { 20198 throw new RuntimeException("view " + this + " being added, but" 20199 + " it already has a parent"); 20200 } 20201 } 20202 20203 /** 20204 * This is called when the view is attached to a window. At this point it 20205 * has a Surface and will start drawing. Note that this function is 20206 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 20207 * however it may be called any time before the first onDraw -- including 20208 * before or after {@link #onMeasure(int, int)}. 20209 * 20210 * @see #onDetachedFromWindow() 20211 */ 20212 @CallSuper onAttachedToWindow()20213 protected void onAttachedToWindow() { 20214 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 20215 mParent.requestTransparentRegion(this); 20216 } 20217 20218 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 20219 20220 jumpDrawablesToCurrentState(); 20221 20222 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 20223 resetSubtreeAccessibilityStateChanged(); 20224 20225 // rebuild, since Outline not maintained while View is detached 20226 rebuildOutline(); 20227 20228 if (isFocused()) { 20229 notifyFocusChangeToImeFocusController(true /* hasFocus */); 20230 } 20231 } 20232 20233 /** 20234 * Resolve all RTL related properties. 20235 * 20236 * @return true if resolution of RTL properties has been done 20237 * 20238 * @hide 20239 */ resolveRtlPropertiesIfNeeded()20240 public boolean resolveRtlPropertiesIfNeeded() { 20241 if (!needRtlPropertiesResolution()) return false; 20242 20243 // Order is important here: LayoutDirection MUST be resolved first 20244 if (!isLayoutDirectionResolved()) { 20245 resolveLayoutDirection(); 20246 resolveLayoutParams(); 20247 } 20248 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 20249 if (!isTextDirectionResolved()) { 20250 resolveTextDirection(); 20251 } 20252 if (!isTextAlignmentResolved()) { 20253 resolveTextAlignment(); 20254 } 20255 // Should resolve Drawables before Padding because we need the layout direction of the 20256 // Drawable to correctly resolve Padding. 20257 if (!areDrawablesResolved()) { 20258 resolveDrawables(); 20259 } 20260 if (!isPaddingResolved()) { 20261 resolvePadding(); 20262 } 20263 onRtlPropertiesChanged(getLayoutDirection()); 20264 return true; 20265 } 20266 20267 /** 20268 * Reset resolution of all RTL related properties. 20269 * 20270 * @hide 20271 */ 20272 @TestApi resetRtlProperties()20273 public void resetRtlProperties() { 20274 resetResolvedLayoutDirection(); 20275 resetResolvedTextDirection(); 20276 resetResolvedTextAlignment(); 20277 resetResolvedPadding(); 20278 resetResolvedDrawables(); 20279 } 20280 20281 /** 20282 * @see #onScreenStateChanged(int) 20283 */ dispatchScreenStateChanged(int screenState)20284 void dispatchScreenStateChanged(int screenState) { 20285 onScreenStateChanged(screenState); 20286 } 20287 20288 /** 20289 * This method is called whenever the state of the screen this view is 20290 * attached to changes. A state change will usually occurs when the screen 20291 * turns on or off (whether it happens automatically or the user does it 20292 * manually.) 20293 * 20294 * @param screenState The new state of the screen. Can be either 20295 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 20296 */ onScreenStateChanged(int screenState)20297 public void onScreenStateChanged(int screenState) { 20298 } 20299 20300 /** 20301 * @see #onMovedToDisplay(int, Configuration) 20302 */ dispatchMovedToDisplay(Display display, Configuration config)20303 void dispatchMovedToDisplay(Display display, Configuration config) { 20304 mAttachInfo.mDisplay = display; 20305 mAttachInfo.mDisplayState = display.getState(); 20306 onMovedToDisplay(display.getDisplayId(), config); 20307 } 20308 20309 /** 20310 * Called by the system when the hosting activity is moved from one display to another without 20311 * recreation. This means that the activity is declared to handle all changes to configuration 20312 * that happened when it was switched to another display, so it wasn't destroyed and created 20313 * again. 20314 * 20315 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 20316 * applied configuration actually changed. It is up to app developer to choose whether to handle 20317 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 20318 * call. 20319 * 20320 * <p>Use this callback to track changes to the displays if some functionality relies on an 20321 * association with some display properties. 20322 * 20323 * @param displayId The id of the display to which the view was moved. 20324 * @param config Configuration of the resources on new display after move. 20325 * 20326 * @see #onConfigurationChanged(Configuration) 20327 * @hide 20328 */ onMovedToDisplay(int displayId, Configuration config)20329 public void onMovedToDisplay(int displayId, Configuration config) { 20330 } 20331 20332 /** 20333 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 20334 */ 20335 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hasRtlSupport()20336 private boolean hasRtlSupport() { 20337 return mContext.getApplicationInfo().hasRtlSupport(); 20338 } 20339 20340 /** 20341 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 20342 * RTL not supported) 20343 */ isRtlCompatibilityMode()20344 private boolean isRtlCompatibilityMode() { 20345 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 20346 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 20347 } 20348 20349 /** 20350 * @return true if RTL properties need resolution. 20351 * 20352 */ needRtlPropertiesResolution()20353 private boolean needRtlPropertiesResolution() { 20354 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 20355 } 20356 20357 /** 20358 * Called when any RTL property (layout direction or text direction or text alignment) has 20359 * been changed. 20360 * 20361 * Subclasses need to override this method to take care of cached information that depends on the 20362 * resolved layout direction, or to inform child views that inherit their layout direction. 20363 * 20364 * The default implementation does nothing. 20365 * 20366 * @param layoutDirection the direction of the layout 20367 * 20368 * @see #LAYOUT_DIRECTION_LTR 20369 * @see #LAYOUT_DIRECTION_RTL 20370 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)20371 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 20372 } 20373 20374 /** 20375 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 20376 * that the parent directionality can and will be resolved before its children. 20377 * 20378 * @return true if resolution has been done, false otherwise. 20379 * 20380 * @hide 20381 */ resolveLayoutDirection()20382 public boolean resolveLayoutDirection() { 20383 // Clear any previous layout direction resolution 20384 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20385 20386 if (hasRtlSupport()) { 20387 // Set resolved depending on layout direction 20388 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 20389 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 20390 case LAYOUT_DIRECTION_INHERIT: 20391 // We cannot resolve yet. LTR is by default and let the resolution happen again 20392 // later to get the correct resolved value 20393 if (!canResolveLayoutDirection()) return false; 20394 20395 // Parent has not yet resolved, LTR is still the default 20396 try { 20397 if (!mParent.isLayoutDirectionResolved()) return false; 20398 20399 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 20400 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20401 } 20402 } catch (AbstractMethodError e) { 20403 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20404 " does not fully implement ViewParent", e); 20405 } 20406 break; 20407 case LAYOUT_DIRECTION_RTL: 20408 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20409 break; 20410 case LAYOUT_DIRECTION_LOCALE: 20411 if((LAYOUT_DIRECTION_RTL == 20412 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 20413 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20414 } 20415 break; 20416 default: 20417 // Nothing to do, LTR by default 20418 } 20419 } 20420 20421 // Set to resolved 20422 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 20423 return true; 20424 } 20425 20426 /** 20427 * Check if layout direction resolution can be done. 20428 * 20429 * @return true if layout direction resolution can be done otherwise return false. 20430 */ canResolveLayoutDirection()20431 public boolean canResolveLayoutDirection() { 20432 switch (getRawLayoutDirection()) { 20433 case LAYOUT_DIRECTION_INHERIT: 20434 if (mParent != null) { 20435 try { 20436 return mParent.canResolveLayoutDirection(); 20437 } catch (AbstractMethodError e) { 20438 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20439 " does not fully implement ViewParent", e); 20440 } 20441 } 20442 return false; 20443 20444 default: 20445 return true; 20446 } 20447 } 20448 20449 /** 20450 * Reset the resolved layout direction. Layout direction will be resolved during a call to 20451 * {@link #onMeasure(int, int)}. 20452 * 20453 * @hide 20454 */ 20455 @TestApi resetResolvedLayoutDirection()20456 public void resetResolvedLayoutDirection() { 20457 // Reset the current resolved bits 20458 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20459 } 20460 20461 /** 20462 * @return true if the layout direction is inherited. 20463 * 20464 * @hide 20465 */ isLayoutDirectionInherited()20466 public boolean isLayoutDirectionInherited() { 20467 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 20468 } 20469 20470 /** 20471 * @return true if layout direction has been resolved. 20472 */ isLayoutDirectionResolved()20473 public boolean isLayoutDirectionResolved() { 20474 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 20475 } 20476 20477 /** 20478 * Return if padding has been resolved 20479 * 20480 * @hide 20481 */ 20482 @UnsupportedAppUsage isPaddingResolved()20483 boolean isPaddingResolved() { 20484 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 20485 } 20486 20487 /** 20488 * Resolves padding depending on layout direction, if applicable, and 20489 * recomputes internal padding values to adjust for scroll bars. 20490 * 20491 * @hide 20492 */ 20493 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolvePadding()20494 public void resolvePadding() { 20495 final int resolvedLayoutDirection = getLayoutDirection(); 20496 20497 if (!isRtlCompatibilityMode()) { 20498 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 20499 // If start / end padding are defined, they will be resolved (hence overriding) to 20500 // left / right or right / left depending on the resolved layout direction. 20501 // If start / end padding are not defined, use the left / right ones. 20502 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 20503 Rect padding = sThreadLocal.get(); 20504 if (padding == null) { 20505 padding = new Rect(); 20506 sThreadLocal.set(padding); 20507 } 20508 mBackground.getPadding(padding); 20509 if (!mLeftPaddingDefined) { 20510 mUserPaddingLeftInitial = padding.left; 20511 } 20512 if (!mRightPaddingDefined) { 20513 mUserPaddingRightInitial = padding.right; 20514 } 20515 } 20516 switch (resolvedLayoutDirection) { 20517 case LAYOUT_DIRECTION_RTL: 20518 if (mUserPaddingStart != UNDEFINED_PADDING) { 20519 mUserPaddingRight = mUserPaddingStart; 20520 } else { 20521 mUserPaddingRight = mUserPaddingRightInitial; 20522 } 20523 if (mUserPaddingEnd != UNDEFINED_PADDING) { 20524 mUserPaddingLeft = mUserPaddingEnd; 20525 } else { 20526 mUserPaddingLeft = mUserPaddingLeftInitial; 20527 } 20528 break; 20529 case LAYOUT_DIRECTION_LTR: 20530 default: 20531 if (mUserPaddingStart != UNDEFINED_PADDING) { 20532 mUserPaddingLeft = mUserPaddingStart; 20533 } else { 20534 mUserPaddingLeft = mUserPaddingLeftInitial; 20535 } 20536 if (mUserPaddingEnd != UNDEFINED_PADDING) { 20537 mUserPaddingRight = mUserPaddingEnd; 20538 } else { 20539 mUserPaddingRight = mUserPaddingRightInitial; 20540 } 20541 } 20542 20543 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 20544 } 20545 20546 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 20547 onRtlPropertiesChanged(resolvedLayoutDirection); 20548 20549 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 20550 } 20551 20552 /** 20553 * Reset the resolved layout direction. 20554 * 20555 * @hide 20556 */ 20557 @TestApi resetResolvedPadding()20558 public void resetResolvedPadding() { 20559 resetResolvedPaddingInternal(); 20560 } 20561 20562 /** 20563 * Used when we only want to reset *this* view's padding and not trigger overrides 20564 * in ViewGroup that reset children too. 20565 */ resetResolvedPaddingInternal()20566 void resetResolvedPaddingInternal() { 20567 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 20568 } 20569 20570 /** 20571 * This is called when the view is detached from a window. At this point it 20572 * no longer has a surface for drawing. 20573 * 20574 * @see #onAttachedToWindow() 20575 */ 20576 @CallSuper onDetachedFromWindow()20577 protected void onDetachedFromWindow() { 20578 } 20579 20580 /** 20581 * This is a framework-internal mirror of onDetachedFromWindow() that's called 20582 * after onDetachedFromWindow(). 20583 * 20584 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 20585 * The super method should be called at the end of the overridden method to ensure 20586 * subclasses are destroyed first 20587 * 20588 * @hide 20589 */ 20590 @CallSuper 20591 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()20592 protected void onDetachedFromWindowInternal() { 20593 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 20594 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 20595 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 20596 20597 removeUnsetPressCallback(); 20598 removeLongPressCallback(); 20599 removePerformClickCallback(); 20600 clearAccessibilityThrottles(); 20601 stopNestedScroll(); 20602 20603 // Anything that started animating right before detach should already 20604 // be in its final state when re-attached. 20605 jumpDrawablesToCurrentState(); 20606 20607 destroyDrawingCache(); 20608 20609 cleanupDraw(); 20610 mCurrentAnimation = null; 20611 20612 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 20613 hideTooltip(); 20614 } 20615 20616 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 20617 } 20618 cleanupDraw()20619 private void cleanupDraw() { 20620 resetDisplayList(); 20621 if (mAttachInfo != null) { 20622 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 20623 } 20624 } 20625 invalidateInheritedLayoutMode(int layoutModeOfRoot)20626 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 20627 } 20628 20629 /** 20630 * @return The number of times this view has been attached to a window 20631 */ getWindowAttachCount()20632 protected int getWindowAttachCount() { 20633 return mWindowAttachCount; 20634 } 20635 20636 /** 20637 * Retrieve a unique token identifying the window this view is attached to. 20638 * @return Return the window's token for use in 20639 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 20640 */ getWindowToken()20641 public IBinder getWindowToken() { 20642 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 20643 } 20644 20645 /** 20646 * Retrieve the {@link WindowId} for the window this view is 20647 * currently attached to. 20648 */ getWindowId()20649 public WindowId getWindowId() { 20650 AttachInfo ai = mAttachInfo; 20651 if (ai == null) { 20652 return null; 20653 } 20654 if (ai.mWindowId == null) { 20655 try { 20656 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 20657 if (ai.mIWindowId != null) { 20658 ai.mWindowId = new WindowId(ai.mIWindowId); 20659 } 20660 } catch (RemoteException e) { 20661 } 20662 } 20663 return ai.mWindowId; 20664 } 20665 20666 /** 20667 * Retrieve a unique token identifying the top-level "real" window of 20668 * the window that this view is attached to. That is, this is like 20669 * {@link #getWindowToken}, except if the window this view in is a panel 20670 * window (attached to another containing window), then the token of 20671 * the containing window is returned instead. 20672 * 20673 * @return Returns the associated window token, either 20674 * {@link #getWindowToken()} or the containing window's token. 20675 */ getApplicationWindowToken()20676 public IBinder getApplicationWindowToken() { 20677 AttachInfo ai = mAttachInfo; 20678 if (ai != null) { 20679 IBinder appWindowToken = ai.mPanelParentWindowToken; 20680 if (appWindowToken == null) { 20681 appWindowToken = ai.mWindowToken; 20682 } 20683 return appWindowToken; 20684 } 20685 return null; 20686 } 20687 20688 /** 20689 * Gets the logical display to which the view's window has been attached. 20690 * 20691 * @return The logical display, or null if the view is not currently attached to a window. 20692 */ getDisplay()20693 public Display getDisplay() { 20694 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 20695 } 20696 20697 /** 20698 * Retrieve private session object this view hierarchy is using to 20699 * communicate with the window manager. 20700 * @return the session object to communicate with the window manager 20701 */ 20702 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()20703 /*package*/ IWindowSession getWindowSession() { 20704 return mAttachInfo != null ? mAttachInfo.mSession : null; 20705 } 20706 20707 /** 20708 * Return the window this view is currently attached to. 20709 * @hide 20710 */ getWindow()20711 protected IWindow getWindow() { 20712 return mAttachInfo != null ? mAttachInfo.mWindow : null; 20713 } 20714 20715 /** 20716 * Return the visibility value of the least visible component passed. 20717 */ combineVisibility(int vis1, int vis2)20718 int combineVisibility(int vis1, int vis2) { 20719 // This works because VISIBLE < INVISIBLE < GONE. 20720 return Math.max(vis1, vis2); 20721 } 20722 20723 /** 20724 * @param info the {@link android.view.View.AttachInfo} to associated with 20725 * this view 20726 */ 20727 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)20728 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 20729 mAttachInfo = info; 20730 if (mOverlay != null) { 20731 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 20732 } 20733 mWindowAttachCount++; 20734 // We will need to evaluate the drawable state at least once. 20735 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20736 if (mFloatingTreeObserver != null) { 20737 info.mTreeObserver.merge(mFloatingTreeObserver); 20738 mFloatingTreeObserver = null; 20739 } 20740 20741 registerPendingFrameMetricsObservers(); 20742 20743 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 20744 mAttachInfo.mScrollContainers.add(this); 20745 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 20746 } 20747 // Transfer all pending runnables. 20748 if (mRunQueue != null) { 20749 mRunQueue.executeActions(info.mHandler); 20750 mRunQueue = null; 20751 } 20752 performCollectViewAttributes(mAttachInfo, visibility); 20753 onAttachedToWindow(); 20754 20755 ListenerInfo li = mListenerInfo; 20756 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20757 li != null ? li.mOnAttachStateChangeListeners : null; 20758 if (listeners != null && listeners.size() > 0) { 20759 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20760 // perform the dispatching. The iterator is a safe guard against listeners that 20761 // could mutate the list by calling the various add/remove methods. This prevents 20762 // the array from being modified while we iterate it. 20763 for (OnAttachStateChangeListener listener : listeners) { 20764 listener.onViewAttachedToWindow(this); 20765 } 20766 } 20767 20768 int vis = info.mWindowVisibility; 20769 if (vis != GONE) { 20770 onWindowVisibilityChanged(vis); 20771 if (isShown()) { 20772 // Calling onVisibilityAggregated directly here since the subtree will also 20773 // receive dispatchAttachedToWindow and this same call 20774 onVisibilityAggregated(vis == VISIBLE); 20775 } 20776 } 20777 20778 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 20779 // As all views in the subtree will already receive dispatchAttachedToWindow 20780 // traversing the subtree again here is not desired. 20781 onVisibilityChanged(this, visibility); 20782 20783 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 20784 // If nobody has evaluated the drawable state yet, then do it now. 20785 refreshDrawableState(); 20786 } 20787 needGlobalAttributesUpdate(false); 20788 20789 notifyEnterOrExitForAutoFillIfNeeded(true); 20790 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 20791 } 20792 20793 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()20794 void dispatchDetachedFromWindow() { 20795 AttachInfo info = mAttachInfo; 20796 if (info != null) { 20797 int vis = info.mWindowVisibility; 20798 if (vis != GONE) { 20799 onWindowVisibilityChanged(GONE); 20800 if (isShown()) { 20801 // Invoking onVisibilityAggregated directly here since the subtree 20802 // will also receive detached from window 20803 onVisibilityAggregated(false); 20804 } 20805 } 20806 } 20807 20808 onDetachedFromWindow(); 20809 onDetachedFromWindowInternal(); 20810 20811 if (info != null) { 20812 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 20813 } 20814 20815 ListenerInfo li = mListenerInfo; 20816 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20817 li != null ? li.mOnAttachStateChangeListeners : null; 20818 if (listeners != null && listeners.size() > 0) { 20819 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20820 // perform the dispatching. The iterator is a safe guard against listeners that 20821 // could mutate the list by calling the various add/remove methods. This prevents 20822 // the array from being modified while we iterate it. 20823 for (OnAttachStateChangeListener listener : listeners) { 20824 listener.onViewDetachedFromWindow(this); 20825 } 20826 } 20827 20828 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 20829 mAttachInfo.mScrollContainers.remove(this); 20830 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 20831 } 20832 20833 mAttachInfo = null; 20834 if (mOverlay != null) { 20835 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 20836 } 20837 20838 notifyEnterOrExitForAutoFillIfNeeded(false); 20839 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 20840 } 20841 20842 /** 20843 * Cancel any deferred high-level input events that were previously posted to the event queue. 20844 * 20845 * <p>Many views post high-level events such as click handlers to the event queue 20846 * to run deferred in order to preserve a desired user experience - clearing visible 20847 * pressed states before executing, etc. This method will abort any events of this nature 20848 * that are currently in flight.</p> 20849 * 20850 * <p>Custom views that generate their own high-level deferred input events should override 20851 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 20852 * 20853 * <p>This will also cancel pending input events for any child views.</p> 20854 * 20855 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 20856 * This will not impact newer events posted after this call that may occur as a result of 20857 * lower-level input events still waiting in the queue. If you are trying to prevent 20858 * double-submitted events for the duration of some sort of asynchronous transaction 20859 * you should also take other steps to protect against unexpected double inputs e.g. calling 20860 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 20861 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 20862 */ cancelPendingInputEvents()20863 public final void cancelPendingInputEvents() { 20864 dispatchCancelPendingInputEvents(); 20865 } 20866 20867 /** 20868 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 20869 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 20870 */ dispatchCancelPendingInputEvents()20871 void dispatchCancelPendingInputEvents() { 20872 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 20873 onCancelPendingInputEvents(); 20874 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 20875 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 20876 " did not call through to super.onCancelPendingInputEvents()"); 20877 } 20878 } 20879 20880 /** 20881 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 20882 * a parent view. 20883 * 20884 * <p>This method is responsible for removing any pending high-level input events that were 20885 * posted to the event queue to run later. Custom view classes that post their own deferred 20886 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 20887 * {@link android.os.Handler} should override this method, call 20888 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 20889 * </p> 20890 */ onCancelPendingInputEvents()20891 public void onCancelPendingInputEvents() { 20892 removePerformClickCallback(); 20893 cancelLongPress(); 20894 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 20895 } 20896 20897 /** 20898 * Store this view hierarchy's frozen state into the given container. 20899 * 20900 * @param container The SparseArray in which to save the view's state. 20901 * 20902 * @see #restoreHierarchyState(android.util.SparseArray) 20903 * @see #dispatchSaveInstanceState(android.util.SparseArray) 20904 * @see #onSaveInstanceState() 20905 */ saveHierarchyState(SparseArray<Parcelable> container)20906 public void saveHierarchyState(SparseArray<Parcelable> container) { 20907 dispatchSaveInstanceState(container); 20908 } 20909 20910 /** 20911 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 20912 * this view and its children. May be overridden to modify how freezing happens to a 20913 * view's children; for example, some views may want to not store state for their children. 20914 * 20915 * @param container The SparseArray in which to save the view's state. 20916 * 20917 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20918 * @see #saveHierarchyState(android.util.SparseArray) 20919 * @see #onSaveInstanceState() 20920 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)20921 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 20922 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 20923 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 20924 Parcelable state = onSaveInstanceState(); 20925 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 20926 throw new IllegalStateException( 20927 "Derived class did not call super.onSaveInstanceState()"); 20928 } 20929 if (state != null) { 20930 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 20931 // + ": " + state); 20932 container.put(mID, state); 20933 } 20934 } 20935 } 20936 20937 /** 20938 * Hook allowing a view to generate a representation of its internal state 20939 * that can later be used to create a new instance with that same state. 20940 * This state should only contain information that is not persistent or can 20941 * not be reconstructed later. For example, you will never store your 20942 * current position on screen because that will be computed again when a 20943 * new instance of the view is placed in its view hierarchy. 20944 * <p> 20945 * Some examples of things you may store here: the current cursor position 20946 * in a text view (but usually not the text itself since that is stored in a 20947 * content provider or other persistent storage), the currently selected 20948 * item in a list view. 20949 * 20950 * @return Returns a Parcelable object containing the view's current dynamic 20951 * state, or null if there is nothing interesting to save. 20952 * @see #onRestoreInstanceState(Parcelable) 20953 * @see #saveHierarchyState(SparseArray) 20954 * @see #dispatchSaveInstanceState(SparseArray) 20955 * @see #setSaveEnabled(boolean) 20956 */ 20957 @CallSuper onSaveInstanceState()20958 @Nullable protected Parcelable onSaveInstanceState() { 20959 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 20960 if (mStartActivityRequestWho != null || isAutofilled() 20961 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 20962 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 20963 20964 if (mStartActivityRequestWho != null) { 20965 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 20966 } 20967 20968 if (isAutofilled()) { 20969 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 20970 } 20971 20972 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 20973 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 20974 } 20975 20976 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 20977 state.mIsAutofilled = isAutofilled(); 20978 state.mHideHighlight = hideAutofillHighlight(); 20979 state.mAutofillViewId = mAutofillViewId; 20980 return state; 20981 } 20982 return BaseSavedState.EMPTY_STATE; 20983 } 20984 20985 /** 20986 * Restore this view hierarchy's frozen state from the given container. 20987 * 20988 * @param container The SparseArray which holds previously frozen states. 20989 * 20990 * @see #saveHierarchyState(android.util.SparseArray) 20991 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20992 * @see #onRestoreInstanceState(android.os.Parcelable) 20993 */ restoreHierarchyState(SparseArray<Parcelable> container)20994 public void restoreHierarchyState(SparseArray<Parcelable> container) { 20995 dispatchRestoreInstanceState(container); 20996 } 20997 20998 /** 20999 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 21000 * state for this view and its children. May be overridden to modify how restoring 21001 * happens to a view's children; for example, some views may want to not store state 21002 * for their children. 21003 * 21004 * @param container The SparseArray which holds previously saved state. 21005 * 21006 * @see #dispatchSaveInstanceState(android.util.SparseArray) 21007 * @see #restoreHierarchyState(android.util.SparseArray) 21008 * @see #onRestoreInstanceState(android.os.Parcelable) 21009 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)21010 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 21011 if (mID != NO_ID) { 21012 Parcelable state = container.get(mID); 21013 if (state != null) { 21014 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 21015 // + ": " + state); 21016 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 21017 onRestoreInstanceState(state); 21018 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 21019 throw new IllegalStateException( 21020 "Derived class did not call super.onRestoreInstanceState()"); 21021 } 21022 } 21023 } 21024 } 21025 21026 /** 21027 * Hook allowing a view to re-apply a representation of its internal state that had previously 21028 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 21029 * null state. 21030 * 21031 * @param state The frozen state that had previously been returned by 21032 * {@link #onSaveInstanceState}. 21033 * 21034 * @see #onSaveInstanceState() 21035 * @see #restoreHierarchyState(android.util.SparseArray) 21036 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 21037 */ 21038 @CallSuper onRestoreInstanceState(Parcelable state)21039 protected void onRestoreInstanceState(Parcelable state) { 21040 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 21041 if (state != null && !(state instanceof AbsSavedState)) { 21042 throw new IllegalArgumentException("Wrong state class, expecting View State but " 21043 + "received " + state.getClass().toString() + " instead. This usually happens " 21044 + "when two views of different type have the same id in the same hierarchy. " 21045 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 21046 + "other views do not use the same id."); 21047 } 21048 if (state != null && state instanceof BaseSavedState) { 21049 BaseSavedState baseState = (BaseSavedState) state; 21050 21051 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 21052 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 21053 } 21054 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 21055 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 21056 } 21057 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 21058 // It can happen that views have the same view id and the restoration path will not 21059 // be able to distinguish between them. The autofill id needs to be unique though. 21060 // Hence prevent the same autofill view id from being restored multiple times. 21061 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 21062 21063 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 21064 // Ignore when view already set it through setAutofillId(); 21065 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 21066 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 21067 + "to " + baseState.mAutofillViewId + " because view explicitly set" 21068 + " it to " + mAutofillId); 21069 } 21070 } else { 21071 mAutofillViewId = baseState.mAutofillViewId; 21072 mAutofillId = null; // will be set on demand by getAutofillId() 21073 } 21074 } 21075 } 21076 } 21077 21078 /** 21079 * <p>Return the time at which the drawing of the view hierarchy started.</p> 21080 * 21081 * @return the drawing start time in milliseconds 21082 */ getDrawingTime()21083 public long getDrawingTime() { 21084 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 21085 } 21086 21087 /** 21088 * <p>Enables or disables the duplication of the parent's state into this view. When 21089 * duplication is enabled, this view gets its drawable state from its parent rather 21090 * than from its own internal properties.</p> 21091 * 21092 * <p>Note: in the current implementation, setting this property to true after the 21093 * view was added to a ViewGroup might have no effect at all. This property should 21094 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 21095 * 21096 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 21097 * property is enabled, an exception will be thrown.</p> 21098 * 21099 * <p>Note: if the child view uses and updates additional states which are unknown to the 21100 * parent, these states should not be affected by this method.</p> 21101 * 21102 * @param enabled True to enable duplication of the parent's drawable state, false 21103 * to disable it. 21104 * 21105 * @see #getDrawableState() 21106 * @see #isDuplicateParentStateEnabled() 21107 */ setDuplicateParentStateEnabled(boolean enabled)21108 public void setDuplicateParentStateEnabled(boolean enabled) { 21109 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 21110 } 21111 21112 /** 21113 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 21114 * 21115 * @return True if this view's drawable state is duplicated from the parent, 21116 * false otherwise 21117 * 21118 * @see #getDrawableState() 21119 * @see #setDuplicateParentStateEnabled(boolean) 21120 */ 21121 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()21122 public boolean isDuplicateParentStateEnabled() { 21123 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 21124 } 21125 21126 /** 21127 * <p>Specifies the type of layer backing this view. The layer can be 21128 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21129 * {@link #LAYER_TYPE_HARDWARE}.</p> 21130 * 21131 * <p>A layer is associated with an optional {@link android.graphics.Paint} 21132 * instance that controls how the layer is composed on screen. The following 21133 * properties of the paint are taken into account when composing the layer:</p> 21134 * <ul> 21135 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 21136 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 21137 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 21138 * </ul> 21139 * 21140 * <p>If this view has an alpha value set to < 1.0 by calling 21141 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 21142 * by this view's alpha value.</p> 21143 * 21144 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 21145 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 21146 * for more information on when and how to use layers.</p> 21147 * 21148 * @param layerType The type of layer to use with this view, must be one of 21149 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21150 * {@link #LAYER_TYPE_HARDWARE} 21151 * @param paint The paint used to compose the layer. This argument is optional 21152 * and can be null. It is ignored when the layer type is 21153 * {@link #LAYER_TYPE_NONE} 21154 * 21155 * @see #getLayerType() 21156 * @see #LAYER_TYPE_NONE 21157 * @see #LAYER_TYPE_SOFTWARE 21158 * @see #LAYER_TYPE_HARDWARE 21159 * @see #setAlpha(float) 21160 * 21161 * @attr ref android.R.styleable#View_layerType 21162 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)21163 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 21164 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 21165 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 21166 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 21167 } 21168 21169 boolean typeChanged = mRenderNode.setLayerType(layerType); 21170 21171 if (!typeChanged) { 21172 setLayerPaint(paint); 21173 return; 21174 } 21175 21176 if (layerType != LAYER_TYPE_SOFTWARE) { 21177 // Destroy any previous software drawing cache if present 21178 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 21179 // drawing cache created in View#draw when drawing to a SW canvas. 21180 destroyDrawingCache(); 21181 } 21182 21183 mLayerType = layerType; 21184 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 21185 mRenderNode.setLayerPaint(mLayerPaint); 21186 21187 // draw() behaves differently if we are on a layer, so we need to 21188 // invalidate() here 21189 invalidateParentCaches(); 21190 invalidate(true); 21191 } 21192 21193 /** 21194 * Configure the {@link android.graphics.RenderEffect} to apply to this View. 21195 * This will apply a visual effect to the results of the View before it is drawn. For example if 21196 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 21197 * is provided, the contents will be drawn in a separate layer, then this layer will be blurred 21198 * when this View is drawn. 21199 * @param renderEffect to be applied to the View. Passing null clears the previously configured 21200 * {@link RenderEffect} 21201 */ setRenderEffect(@ullable RenderEffect renderEffect)21202 public void setRenderEffect(@Nullable RenderEffect renderEffect) { 21203 if (mRenderNode.setRenderEffect(renderEffect)) { 21204 invalidateViewProperty(true, true); 21205 } 21206 } 21207 21208 /** 21209 * Updates the {@link Paint} object used with the current layer (used only if the current 21210 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 21211 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 21212 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 21213 * ensure that the view gets redrawn immediately. 21214 * 21215 * <p>A layer is associated with an optional {@link android.graphics.Paint} 21216 * instance that controls how the layer is composed on screen. The following 21217 * properties of the paint are taken into account when composing the layer:</p> 21218 * <ul> 21219 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 21220 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 21221 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 21222 * </ul> 21223 * 21224 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 21225 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 21226 * 21227 * @param paint The paint used to compose the layer. This argument is optional 21228 * and can be null. It is ignored when the layer type is 21229 * {@link #LAYER_TYPE_NONE} 21230 * 21231 * @see #setLayerType(int, android.graphics.Paint) 21232 */ setLayerPaint(@ullable Paint paint)21233 public void setLayerPaint(@Nullable Paint paint) { 21234 int layerType = getLayerType(); 21235 if (layerType != LAYER_TYPE_NONE) { 21236 mLayerPaint = paint; 21237 if (layerType == LAYER_TYPE_HARDWARE) { 21238 if (mRenderNode.setLayerPaint(paint)) { 21239 invalidateViewProperty(false, false); 21240 } 21241 } else { 21242 invalidate(); 21243 } 21244 } 21245 } 21246 21247 /** 21248 * Indicates what type of layer is currently associated with this view. By default 21249 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 21250 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 21251 * for more information on the different types of layers. 21252 * 21253 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 21254 * {@link #LAYER_TYPE_HARDWARE} 21255 * 21256 * @see #setLayerType(int, android.graphics.Paint) 21257 * @see #buildLayer() 21258 * @see #LAYER_TYPE_NONE 21259 * @see #LAYER_TYPE_SOFTWARE 21260 * @see #LAYER_TYPE_HARDWARE 21261 */ 21262 @InspectableProperty(enumMapping = { 21263 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 21264 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 21265 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 21266 }) 21267 @LayerType getLayerType()21268 public int getLayerType() { 21269 return mLayerType; 21270 } 21271 21272 /** 21273 * Forces this view's layer to be created and this view to be rendered 21274 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 21275 * invoking this method will have no effect. 21276 * 21277 * This method can for instance be used to render a view into its layer before 21278 * starting an animation. If this view is complex, rendering into the layer 21279 * before starting the animation will avoid skipping frames. 21280 * 21281 * @throws IllegalStateException If this view is not attached to a window 21282 * 21283 * @see #setLayerType(int, android.graphics.Paint) 21284 */ buildLayer()21285 public void buildLayer() { 21286 if (mLayerType == LAYER_TYPE_NONE) return; 21287 21288 final AttachInfo attachInfo = mAttachInfo; 21289 if (attachInfo == null) { 21290 throw new IllegalStateException("This view must be attached to a window first"); 21291 } 21292 21293 if (getWidth() == 0 || getHeight() == 0) { 21294 return; 21295 } 21296 21297 switch (mLayerType) { 21298 case LAYER_TYPE_HARDWARE: 21299 updateDisplayListIfDirty(); 21300 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 21301 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 21302 } 21303 break; 21304 case LAYER_TYPE_SOFTWARE: 21305 buildDrawingCache(true); 21306 break; 21307 } 21308 } 21309 21310 /** 21311 * Destroys all hardware rendering resources. This method is invoked 21312 * when the system needs to reclaim resources. Upon execution of this 21313 * method, you should free any OpenGL resources created by the view. 21314 * 21315 * Note: you <strong>must</strong> call 21316 * <code>super.destroyHardwareResources()</code> when overriding 21317 * this method. 21318 * 21319 * @hide 21320 */ 21321 @CallSuper 21322 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareResources()21323 protected void destroyHardwareResources() { 21324 if (mOverlay != null) { 21325 mOverlay.getOverlayView().destroyHardwareResources(); 21326 } 21327 if (mGhostView != null) { 21328 mGhostView.destroyHardwareResources(); 21329 } 21330 } 21331 21332 /** 21333 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 21334 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 21335 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 21336 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 21337 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 21338 * null.</p> 21339 * 21340 * <p>Enabling the drawing cache is similar to 21341 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 21342 * acceleration is turned off. When hardware acceleration is turned on, enabling the 21343 * drawing cache has no effect on rendering because the system uses a different mechanism 21344 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 21345 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 21346 * for information on how to enable software and hardware layers.</p> 21347 * 21348 * <p>This API can be used to manually generate 21349 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 21350 * {@link #getDrawingCache()}.</p> 21351 * 21352 * @param enabled true to enable the drawing cache, false otherwise 21353 * 21354 * @see #isDrawingCacheEnabled() 21355 * @see #getDrawingCache() 21356 * @see #buildDrawingCache() 21357 * @see #setLayerType(int, android.graphics.Paint) 21358 * 21359 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21360 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21361 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21362 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21363 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21364 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21365 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21366 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21367 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21368 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21369 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21370 * reports or unit testing the {@link PixelCopy} API is recommended. 21371 */ 21372 @Deprecated setDrawingCacheEnabled(boolean enabled)21373 public void setDrawingCacheEnabled(boolean enabled) { 21374 mCachingFailed = false; 21375 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 21376 } 21377 21378 /** 21379 * <p>Indicates whether the drawing cache is enabled for this view.</p> 21380 * 21381 * @return true if the drawing cache is enabled 21382 * 21383 * @see #setDrawingCacheEnabled(boolean) 21384 * @see #getDrawingCache() 21385 * 21386 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21387 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21388 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21389 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21390 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21391 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21392 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21393 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21394 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21395 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21396 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21397 * reports or unit testing the {@link PixelCopy} API is recommended. 21398 */ 21399 @Deprecated 21400 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()21401 public boolean isDrawingCacheEnabled() { 21402 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 21403 } 21404 21405 /** 21406 * Debugging utility which recursively outputs the dirty state of a view and its 21407 * descendants. 21408 * 21409 * @hide 21410 */ 21411 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)21412 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 21413 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 21414 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 21415 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 21416 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 21417 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 21418 if (clear) { 21419 mPrivateFlags &= clearMask; 21420 } 21421 if (this instanceof ViewGroup) { 21422 ViewGroup parent = (ViewGroup) this; 21423 final int count = parent.getChildCount(); 21424 for (int i = 0; i < count; i++) { 21425 final View child = parent.getChildAt(i); 21426 child.outputDirtyFlags(indent + " ", clear, clearMask); 21427 } 21428 } 21429 } 21430 21431 /** 21432 * This method is used by ViewGroup to cause its children to restore or recreate their 21433 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 21434 * to recreate its own display list, which would happen if it went through the normal 21435 * draw/dispatchDraw mechanisms. 21436 * 21437 * @hide 21438 */ dispatchGetDisplayList()21439 protected void dispatchGetDisplayList() {} 21440 21441 /** 21442 * A view that is not attached or hardware accelerated cannot create a display list. 21443 * This method checks these conditions and returns the appropriate result. 21444 * 21445 * @return true if view has the ability to create a display list, false otherwise. 21446 * 21447 * @hide 21448 */ canHaveDisplayList()21449 public boolean canHaveDisplayList() { 21450 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 21451 } 21452 21453 /** 21454 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 21455 * @hide 21456 */ 21457 @NonNull 21458 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateDisplayListIfDirty()21459 public RenderNode updateDisplayListIfDirty() { 21460 final RenderNode renderNode = mRenderNode; 21461 if (!canHaveDisplayList()) { 21462 // can't populate RenderNode, don't try 21463 return renderNode; 21464 } 21465 21466 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 21467 || !renderNode.hasDisplayList() 21468 || (mRecreateDisplayList)) { 21469 // Don't need to recreate the display list, just need to tell our 21470 // children to restore/recreate theirs 21471 if (renderNode.hasDisplayList() 21472 && !mRecreateDisplayList) { 21473 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21474 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21475 dispatchGetDisplayList(); 21476 21477 return renderNode; // no work needed 21478 } 21479 21480 // If we got here, we're recreating it. Mark it as such to ensure that 21481 // we copy in child display lists into ours in drawChild() 21482 mRecreateDisplayList = true; 21483 21484 int width = mRight - mLeft; 21485 int height = mBottom - mTop; 21486 int layerType = getLayerType(); 21487 21488 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 21489 // instead of being "stateful" like other RenderNode properties 21490 renderNode.clearStretch(); 21491 21492 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 21493 21494 try { 21495 if (layerType == LAYER_TYPE_SOFTWARE) { 21496 buildDrawingCache(true); 21497 Bitmap cache = getDrawingCache(true); 21498 if (cache != null) { 21499 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 21500 } 21501 } else { 21502 computeScroll(); 21503 21504 canvas.translate(-mScrollX, -mScrollY); 21505 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21506 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21507 21508 // Fast path for layouts with no backgrounds 21509 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21510 dispatchDraw(canvas); 21511 drawAutofilledHighlight(canvas); 21512 if (mOverlay != null && !mOverlay.isEmpty()) { 21513 mOverlay.getOverlayView().draw(canvas); 21514 } 21515 if (isShowingLayoutBounds()) { 21516 debugDrawFocus(canvas); 21517 } 21518 } else { 21519 draw(canvas); 21520 } 21521 } 21522 } finally { 21523 renderNode.endRecording(); 21524 setDisplayListProperties(renderNode); 21525 } 21526 } else { 21527 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21528 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21529 } 21530 return renderNode; 21531 } 21532 21533 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resetDisplayList()21534 private void resetDisplayList() { 21535 mRenderNode.discardDisplayList(); 21536 if (mBackgroundRenderNode != null) { 21537 mBackgroundRenderNode.discardDisplayList(); 21538 } 21539 } 21540 21541 /** 21542 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 21543 * 21544 * @return A non-scaled bitmap representing this view or null if cache is disabled. 21545 * 21546 * @see #getDrawingCache(boolean) 21547 * 21548 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21549 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21550 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21551 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21552 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21553 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21554 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21555 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21556 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21557 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21558 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21559 * reports or unit testing the {@link PixelCopy} API is recommended. 21560 */ 21561 @Deprecated getDrawingCache()21562 public Bitmap getDrawingCache() { 21563 return getDrawingCache(false); 21564 } 21565 21566 /** 21567 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 21568 * is null when caching is disabled. If caching is enabled and the cache is not ready, 21569 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 21570 * draw from the cache when the cache is enabled. To benefit from the cache, you must 21571 * request the drawing cache by calling this method and draw it on screen if the 21572 * returned bitmap is not null.</p> 21573 * 21574 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21575 * this method will create a bitmap of the same size as this view. Because this bitmap 21576 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21577 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21578 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21579 * size than the view. This implies that your application must be able to handle this 21580 * size.</p> 21581 * 21582 * @param autoScale Indicates whether the generated bitmap should be scaled based on 21583 * the current density of the screen when the application is in compatibility 21584 * mode. 21585 * 21586 * @return A bitmap representing this view or null if cache is disabled. 21587 * 21588 * @see #setDrawingCacheEnabled(boolean) 21589 * @see #isDrawingCacheEnabled() 21590 * @see #buildDrawingCache(boolean) 21591 * @see #destroyDrawingCache() 21592 * 21593 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21594 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21595 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21596 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21597 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21598 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21599 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21600 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21601 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21602 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21603 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21604 * reports or unit testing the {@link PixelCopy} API is recommended. 21605 */ 21606 @Deprecated getDrawingCache(boolean autoScale)21607 public Bitmap getDrawingCache(boolean autoScale) { 21608 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 21609 return null; 21610 } 21611 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 21612 buildDrawingCache(autoScale); 21613 } 21614 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 21615 } 21616 21617 /** 21618 * <p>Frees the resources used by the drawing cache. If you call 21619 * {@link #buildDrawingCache()} manually without calling 21620 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21621 * should cleanup the cache with this method afterwards.</p> 21622 * 21623 * @see #setDrawingCacheEnabled(boolean) 21624 * @see #buildDrawingCache() 21625 * @see #getDrawingCache() 21626 * 21627 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21628 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21629 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21630 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21631 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21632 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21633 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21634 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21635 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21636 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21637 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21638 * reports or unit testing the {@link PixelCopy} API is recommended. 21639 */ 21640 @Deprecated destroyDrawingCache()21641 public void destroyDrawingCache() { 21642 if (mDrawingCache != null) { 21643 mDrawingCache.recycle(); 21644 mDrawingCache = null; 21645 } 21646 if (mUnscaledDrawingCache != null) { 21647 mUnscaledDrawingCache.recycle(); 21648 mUnscaledDrawingCache = null; 21649 } 21650 } 21651 21652 /** 21653 * Setting a solid background color for the drawing cache's bitmaps will improve 21654 * performance and memory usage. Note, though that this should only be used if this 21655 * view will always be drawn on top of a solid color. 21656 * 21657 * @param color The background color to use for the drawing cache's bitmap 21658 * 21659 * @see #setDrawingCacheEnabled(boolean) 21660 * @see #buildDrawingCache() 21661 * @see #getDrawingCache() 21662 * 21663 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21664 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21665 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21666 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21667 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21668 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21669 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21670 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21671 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21672 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21673 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21674 * reports or unit testing the {@link PixelCopy} API is recommended. 21675 */ 21676 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)21677 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 21678 if (color != mDrawingCacheBackgroundColor) { 21679 mDrawingCacheBackgroundColor = color; 21680 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 21681 } 21682 } 21683 21684 /** 21685 * @see #setDrawingCacheBackgroundColor(int) 21686 * 21687 * @return The background color to used for the drawing cache's bitmap 21688 * 21689 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21690 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21691 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21692 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21693 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21694 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21695 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21696 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21697 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21698 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21699 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21700 * reports or unit testing the {@link PixelCopy} API is recommended. 21701 */ 21702 @Deprecated 21703 @ColorInt getDrawingCacheBackgroundColor()21704 public int getDrawingCacheBackgroundColor() { 21705 return mDrawingCacheBackgroundColor; 21706 } 21707 21708 /** 21709 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 21710 * 21711 * @see #buildDrawingCache(boolean) 21712 * 21713 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21714 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21715 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21716 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21717 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21718 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21719 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21720 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21721 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21722 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21723 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21724 * reports or unit testing the {@link PixelCopy} API is recommended. 21725 */ 21726 @Deprecated buildDrawingCache()21727 public void buildDrawingCache() { 21728 buildDrawingCache(false); 21729 } 21730 21731 /** 21732 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 21733 * 21734 * <p>If you call {@link #buildDrawingCache()} manually without calling 21735 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21736 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 21737 * 21738 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21739 * this method will create a bitmap of the same size as this view. Because this bitmap 21740 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21741 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21742 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21743 * size than the view. This implies that your application must be able to handle this 21744 * size.</p> 21745 * 21746 * <p>You should avoid calling this method when hardware acceleration is enabled. If 21747 * you do not need the drawing cache bitmap, calling this method will increase memory 21748 * usage and cause the view to be rendered in software once, thus negatively impacting 21749 * performance.</p> 21750 * 21751 * @see #getDrawingCache() 21752 * @see #destroyDrawingCache() 21753 * 21754 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21755 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21756 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21757 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21758 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21759 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21760 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21761 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21762 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21763 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21764 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21765 * reports or unit testing the {@link PixelCopy} API is recommended. 21766 */ 21767 @Deprecated buildDrawingCache(boolean autoScale)21768 public void buildDrawingCache(boolean autoScale) { 21769 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 21770 mDrawingCache == null : mUnscaledDrawingCache == null)) { 21771 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 21772 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 21773 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 21774 } 21775 try { 21776 buildDrawingCacheImpl(autoScale); 21777 } finally { 21778 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 21779 } 21780 } 21781 } 21782 21783 /** 21784 * private, internal implementation of buildDrawingCache, used to enable tracing 21785 */ buildDrawingCacheImpl(boolean autoScale)21786 private void buildDrawingCacheImpl(boolean autoScale) { 21787 mCachingFailed = false; 21788 21789 int width = mRight - mLeft; 21790 int height = mBottom - mTop; 21791 21792 final AttachInfo attachInfo = mAttachInfo; 21793 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 21794 21795 if (autoScale && scalingRequired) { 21796 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 21797 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 21798 } 21799 21800 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 21801 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 21802 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 21803 21804 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 21805 final long drawingCacheSize = 21806 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 21807 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 21808 if (width > 0 && height > 0) { 21809 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 21810 + " too large to fit into a software layer (or drawing cache), needs " 21811 + projectedBitmapSize + " bytes, only " 21812 + drawingCacheSize + " available"); 21813 } 21814 destroyDrawingCache(); 21815 mCachingFailed = true; 21816 return; 21817 } 21818 21819 boolean clear = true; 21820 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 21821 21822 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 21823 Bitmap.Config quality; 21824 if (!opaque) { 21825 // Never pick ARGB_4444 because it looks awful 21826 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 21827 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 21828 case DRAWING_CACHE_QUALITY_AUTO: 21829 case DRAWING_CACHE_QUALITY_LOW: 21830 case DRAWING_CACHE_QUALITY_HIGH: 21831 default: 21832 quality = Bitmap.Config.ARGB_8888; 21833 break; 21834 } 21835 } else { 21836 // Optimization for translucent windows 21837 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 21838 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 21839 } 21840 21841 // Try to cleanup memory 21842 if (bitmap != null) bitmap.recycle(); 21843 21844 try { 21845 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 21846 width, height, quality); 21847 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 21848 if (autoScale) { 21849 mDrawingCache = bitmap; 21850 } else { 21851 mUnscaledDrawingCache = bitmap; 21852 } 21853 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 21854 } catch (OutOfMemoryError e) { 21855 // If there is not enough memory to create the bitmap cache, just 21856 // ignore the issue as bitmap caches are not required to draw the 21857 // view hierarchy 21858 if (autoScale) { 21859 mDrawingCache = null; 21860 } else { 21861 mUnscaledDrawingCache = null; 21862 } 21863 mCachingFailed = true; 21864 return; 21865 } 21866 21867 clear = drawingCacheBackgroundColor != 0; 21868 } 21869 21870 Canvas canvas; 21871 if (attachInfo != null) { 21872 canvas = attachInfo.mCanvas; 21873 if (canvas == null) { 21874 canvas = new Canvas(); 21875 } 21876 canvas.setBitmap(bitmap); 21877 // Temporarily clobber the cached Canvas in case one of our children 21878 // is also using a drawing cache. Without this, the children would 21879 // steal the canvas by attaching their own bitmap to it and bad, bad 21880 // thing would happen (invisible views, corrupted drawings, etc.) 21881 attachInfo.mCanvas = null; 21882 } else { 21883 // This case should hopefully never or seldom happen 21884 canvas = new Canvas(bitmap); 21885 } 21886 21887 if (clear) { 21888 bitmap.eraseColor(drawingCacheBackgroundColor); 21889 } 21890 21891 computeScroll(); 21892 final int restoreCount = canvas.save(); 21893 21894 if (autoScale && scalingRequired) { 21895 final float scale = attachInfo.mApplicationScale; 21896 canvas.scale(scale, scale); 21897 } 21898 21899 canvas.translate(-mScrollX, -mScrollY); 21900 21901 mPrivateFlags |= PFLAG_DRAWN; 21902 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 21903 mLayerType != LAYER_TYPE_NONE) { 21904 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 21905 } 21906 21907 // Fast path for layouts with no backgrounds 21908 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21909 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21910 dispatchDraw(canvas); 21911 drawAutofilledHighlight(canvas); 21912 if (mOverlay != null && !mOverlay.isEmpty()) { 21913 mOverlay.getOverlayView().draw(canvas); 21914 } 21915 } else { 21916 draw(canvas); 21917 } 21918 21919 canvas.restoreToCount(restoreCount); 21920 canvas.setBitmap(null); 21921 21922 if (attachInfo != null) { 21923 // Restore the cached Canvas for our siblings 21924 attachInfo.mCanvas = canvas; 21925 } 21926 } 21927 21928 /** 21929 * Create a snapshot of the view into a bitmap. We should probably make 21930 * some form of this public, but should think about the API. 21931 * 21932 * @hide 21933 */ 21934 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)21935 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 21936 int width = mRight - mLeft; 21937 int height = mBottom - mTop; 21938 21939 final AttachInfo attachInfo = mAttachInfo; 21940 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 21941 width = (int) ((width * scale) + 0.5f); 21942 height = (int) ((height * scale) + 0.5f); 21943 21944 Canvas oldCanvas = null; 21945 try { 21946 Canvas canvas = canvasProvider.getCanvas(this, 21947 width > 0 ? width : 1, height > 0 ? height : 1); 21948 21949 if (attachInfo != null) { 21950 oldCanvas = attachInfo.mCanvas; 21951 // Temporarily clobber the cached Canvas in case one of our children 21952 // is also using a drawing cache. Without this, the children would 21953 // steal the canvas by attaching their own bitmap to it and bad, bad 21954 // things would happen (invisible views, corrupted drawings, etc.) 21955 attachInfo.mCanvas = null; 21956 } 21957 21958 computeScroll(); 21959 final int restoreCount = canvas.save(); 21960 canvas.scale(scale, scale); 21961 canvas.translate(-mScrollX, -mScrollY); 21962 21963 // Temporarily remove the dirty mask 21964 int flags = mPrivateFlags; 21965 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21966 21967 // Fast path for layouts with no backgrounds 21968 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21969 dispatchDraw(canvas); 21970 drawAutofilledHighlight(canvas); 21971 if (mOverlay != null && !mOverlay.isEmpty()) { 21972 mOverlay.getOverlayView().draw(canvas); 21973 } 21974 } else { 21975 draw(canvas); 21976 } 21977 21978 mPrivateFlags = flags; 21979 canvas.restoreToCount(restoreCount); 21980 return canvasProvider.createBitmap(); 21981 } finally { 21982 if (oldCanvas != null) { 21983 attachInfo.mCanvas = oldCanvas; 21984 } 21985 } 21986 } 21987 21988 /** 21989 * Indicates whether this View is currently in edit mode. A View is usually 21990 * in edit mode when displayed within a developer tool. For instance, if 21991 * this View is being drawn by a visual user interface builder, this method 21992 * should return true. 21993 * 21994 * Subclasses should check the return value of this method to provide 21995 * different behaviors if their normal behavior might interfere with the 21996 * host environment. For instance: the class spawns a thread in its 21997 * constructor, the drawing code relies on device-specific features, etc. 21998 * 21999 * This method is usually checked in the drawing code of custom widgets. 22000 * 22001 * @return True if this View is in edit mode, false otherwise. 22002 */ isInEditMode()22003 public boolean isInEditMode() { 22004 return false; 22005 } 22006 22007 /** 22008 * If the View draws content inside its padding and enables fading edges, 22009 * it needs to support padding offsets. Padding offsets are added to the 22010 * fading edges to extend the length of the fade so that it covers pixels 22011 * drawn inside the padding. 22012 * 22013 * Subclasses of this class should override this method if they need 22014 * to draw content inside the padding. 22015 * 22016 * @return True if padding offset must be applied, false otherwise. 22017 * 22018 * @see #getLeftPaddingOffset() 22019 * @see #getRightPaddingOffset() 22020 * @see #getTopPaddingOffset() 22021 * @see #getBottomPaddingOffset() 22022 * 22023 * @since CURRENT 22024 */ isPaddingOffsetRequired()22025 protected boolean isPaddingOffsetRequired() { 22026 return false; 22027 } 22028 22029 /** 22030 * Amount by which to extend the left fading region. Called only when 22031 * {@link #isPaddingOffsetRequired()} returns true. 22032 * 22033 * @return The left padding offset in pixels. 22034 * 22035 * @see #isPaddingOffsetRequired() 22036 * 22037 * @since CURRENT 22038 */ getLeftPaddingOffset()22039 protected int getLeftPaddingOffset() { 22040 return 0; 22041 } 22042 22043 /** 22044 * Amount by which to extend the right fading region. Called only when 22045 * {@link #isPaddingOffsetRequired()} returns true. 22046 * 22047 * @return The right padding offset in pixels. 22048 * 22049 * @see #isPaddingOffsetRequired() 22050 * 22051 * @since CURRENT 22052 */ getRightPaddingOffset()22053 protected int getRightPaddingOffset() { 22054 return 0; 22055 } 22056 22057 /** 22058 * Amount by which to extend the top fading region. Called only when 22059 * {@link #isPaddingOffsetRequired()} returns true. 22060 * 22061 * @return The top padding offset in pixels. 22062 * 22063 * @see #isPaddingOffsetRequired() 22064 * 22065 * @since CURRENT 22066 */ getTopPaddingOffset()22067 protected int getTopPaddingOffset() { 22068 return 0; 22069 } 22070 22071 /** 22072 * Amount by which to extend the bottom fading region. Called only when 22073 * {@link #isPaddingOffsetRequired()} returns true. 22074 * 22075 * @return The bottom padding offset in pixels. 22076 * 22077 * @see #isPaddingOffsetRequired() 22078 * 22079 * @since CURRENT 22080 */ getBottomPaddingOffset()22081 protected int getBottomPaddingOffset() { 22082 return 0; 22083 } 22084 22085 /** 22086 * @hide 22087 * @param offsetRequired 22088 */ getFadeTop(boolean offsetRequired)22089 protected int getFadeTop(boolean offsetRequired) { 22090 int top = mPaddingTop; 22091 if (offsetRequired) top += getTopPaddingOffset(); 22092 return top; 22093 } 22094 22095 /** 22096 * @hide 22097 * @param offsetRequired 22098 */ getFadeHeight(boolean offsetRequired)22099 protected int getFadeHeight(boolean offsetRequired) { 22100 int padding = mPaddingTop; 22101 if (offsetRequired) padding += getTopPaddingOffset(); 22102 return mBottom - mTop - mPaddingBottom - padding; 22103 } 22104 22105 /** 22106 * <p>Indicates whether this view is attached to a hardware accelerated 22107 * window or not.</p> 22108 * 22109 * <p>Even if this method returns true, it does not mean that every call 22110 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 22111 * accelerated {@link android.graphics.Canvas}. For instance, if this view 22112 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 22113 * window is hardware accelerated, 22114 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 22115 * return false, and this method will return true.</p> 22116 * 22117 * @return True if the view is attached to a window and the window is 22118 * hardware accelerated; false in any other case. 22119 */ 22120 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()22121 public boolean isHardwareAccelerated() { 22122 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 22123 } 22124 22125 /** 22126 * Sets a rectangular area on this view to which the view will be clipped 22127 * when it is drawn. Setting the value to null will remove the clip bounds 22128 * and the view will draw normally, using its full bounds. 22129 * 22130 * @param clipBounds The rectangular area, in the local coordinates of 22131 * this view, to which future drawing operations will be clipped. 22132 */ setClipBounds(Rect clipBounds)22133 public void setClipBounds(Rect clipBounds) { 22134 if (clipBounds == mClipBounds 22135 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 22136 return; 22137 } 22138 if (clipBounds != null) { 22139 if (mClipBounds == null) { 22140 mClipBounds = new Rect(clipBounds); 22141 } else { 22142 mClipBounds.set(clipBounds); 22143 } 22144 } else { 22145 mClipBounds = null; 22146 } 22147 mRenderNode.setClipRect(mClipBounds); 22148 invalidateViewProperty(false, false); 22149 } 22150 22151 /** 22152 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 22153 * 22154 * @return A copy of the current clip bounds if clip bounds are set, 22155 * otherwise null. 22156 */ getClipBounds()22157 public Rect getClipBounds() { 22158 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 22159 } 22160 22161 22162 /** 22163 * Populates an output rectangle with the clip bounds of the view, 22164 * returning {@code true} if successful or {@code false} if the view's 22165 * clip bounds are {@code null}. 22166 * 22167 * @param outRect rectangle in which to place the clip bounds of the view 22168 * @return {@code true} if successful or {@code false} if the view's 22169 * clip bounds are {@code null} 22170 */ getClipBounds(Rect outRect)22171 public boolean getClipBounds(Rect outRect) { 22172 if (mClipBounds != null) { 22173 outRect.set(mClipBounds); 22174 return true; 22175 } 22176 return false; 22177 } 22178 22179 /** 22180 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 22181 * case of an active Animation being run on the view. 22182 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)22183 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 22184 Animation a, boolean scalingRequired) { 22185 Transformation invalidationTransform; 22186 final int flags = parent.mGroupFlags; 22187 final boolean initialized = a.isInitialized(); 22188 if (!initialized) { 22189 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 22190 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 22191 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 22192 onAnimationStart(); 22193 } 22194 22195 final Transformation t = parent.getChildTransformation(); 22196 boolean more = a.getTransformation(drawingTime, t, 1f); 22197 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 22198 if (parent.mInvalidationTransformation == null) { 22199 parent.mInvalidationTransformation = new Transformation(); 22200 } 22201 invalidationTransform = parent.mInvalidationTransformation; 22202 a.getTransformation(drawingTime, invalidationTransform, 1f); 22203 } else { 22204 invalidationTransform = t; 22205 } 22206 22207 if (more) { 22208 if (!a.willChangeBounds()) { 22209 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 22210 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 22211 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 22212 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 22213 // The child need to draw an animation, potentially offscreen, so 22214 // make sure we do not cancel invalidate requests 22215 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 22216 parent.invalidate(mLeft, mTop, mRight, mBottom); 22217 } 22218 } else { 22219 if (parent.mInvalidateRegion == null) { 22220 parent.mInvalidateRegion = new RectF(); 22221 } 22222 final RectF region = parent.mInvalidateRegion; 22223 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 22224 invalidationTransform); 22225 22226 // The child need to draw an animation, potentially offscreen, so 22227 // make sure we do not cancel invalidate requests 22228 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 22229 22230 final int left = mLeft + (int) region.left; 22231 final int top = mTop + (int) region.top; 22232 parent.invalidate(left, top, left + (int) (region.width() + .5f), 22233 top + (int) (region.height() + .5f)); 22234 } 22235 } 22236 return more; 22237 } 22238 22239 /** 22240 * This method is called by getDisplayList() when a display list is recorded for a View. 22241 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 22242 */ setDisplayListProperties(RenderNode renderNode)22243 void setDisplayListProperties(RenderNode renderNode) { 22244 if (renderNode != null) { 22245 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 22246 renderNode.setClipToBounds(mParent instanceof ViewGroup 22247 && ((ViewGroup) mParent).getClipChildren()); 22248 22249 float alpha = 1; 22250 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 22251 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22252 ViewGroup parentVG = (ViewGroup) mParent; 22253 final Transformation t = parentVG.getChildTransformation(); 22254 if (parentVG.getChildStaticTransformation(this, t)) { 22255 final int transformType = t.getTransformationType(); 22256 if (transformType != Transformation.TYPE_IDENTITY) { 22257 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 22258 alpha = t.getAlpha(); 22259 } 22260 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 22261 renderNode.setStaticMatrix(t.getMatrix()); 22262 } 22263 } 22264 } 22265 } 22266 if (mTransformationInfo != null) { 22267 alpha *= getFinalAlpha(); 22268 if (alpha < 1) { 22269 final int multipliedAlpha = (int) (255 * alpha); 22270 if (onSetAlpha(multipliedAlpha)) { 22271 alpha = 1; 22272 } 22273 } 22274 renderNode.setAlpha(alpha); 22275 } else if (alpha < 1) { 22276 renderNode.setAlpha(alpha); 22277 } 22278 } 22279 } 22280 22281 /** 22282 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 22283 * 22284 * This is where the View specializes rendering behavior based on layer type, 22285 * and hardware acceleration. 22286 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)22287 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 22288 22289 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 22290 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 22291 * 22292 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 22293 * HW accelerated, it can't handle drawing RenderNodes. 22294 */ 22295 boolean drawingWithRenderNode = mAttachInfo != null 22296 && mAttachInfo.mHardwareAccelerated 22297 && hardwareAcceleratedCanvas; 22298 22299 boolean more = false; 22300 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 22301 final int parentFlags = parent.mGroupFlags; 22302 22303 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 22304 parent.getChildTransformation().clear(); 22305 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22306 } 22307 22308 Transformation transformToApply = null; 22309 boolean concatMatrix = false; 22310 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 22311 final Animation a = getAnimation(); 22312 if (a != null) { 22313 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 22314 concatMatrix = a.willChangeTransformationMatrix(); 22315 if (concatMatrix) { 22316 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22317 } 22318 transformToApply = parent.getChildTransformation(); 22319 } else { 22320 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 22321 // No longer animating: clear out old animation matrix 22322 mRenderNode.setAnimationMatrix(null); 22323 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22324 } 22325 if (!drawingWithRenderNode 22326 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22327 final Transformation t = parent.getChildTransformation(); 22328 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 22329 if (hasTransform) { 22330 final int transformType = t.getTransformationType(); 22331 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 22332 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 22333 } 22334 } 22335 } 22336 22337 concatMatrix |= !childHasIdentityMatrix; 22338 22339 // Sets the flag as early as possible to allow draw() implementations 22340 // to call invalidate() successfully when doing animations 22341 mPrivateFlags |= PFLAG_DRAWN; 22342 22343 if (!concatMatrix && 22344 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 22345 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 22346 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 22347 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 22348 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 22349 return more; 22350 } 22351 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 22352 22353 if (hardwareAcceleratedCanvas) { 22354 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 22355 // retain the flag's value temporarily in the mRecreateDisplayList flag 22356 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 22357 mPrivateFlags &= ~PFLAG_INVALIDATED; 22358 } 22359 22360 RenderNode renderNode = null; 22361 Bitmap cache = null; 22362 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 22363 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 22364 if (layerType != LAYER_TYPE_NONE) { 22365 // If not drawing with RenderNode, treat HW layers as SW 22366 layerType = LAYER_TYPE_SOFTWARE; 22367 buildDrawingCache(true); 22368 } 22369 cache = getDrawingCache(true); 22370 } 22371 22372 if (drawingWithRenderNode) { 22373 // Delay getting the display list until animation-driven alpha values are 22374 // set up and possibly passed on to the view 22375 renderNode = updateDisplayListIfDirty(); 22376 if (!renderNode.hasDisplayList()) { 22377 // Uncommon, but possible. If a view is removed from the hierarchy during the call 22378 // to getDisplayList(), the display list will be marked invalid and we should not 22379 // try to use it again. 22380 renderNode = null; 22381 drawingWithRenderNode = false; 22382 } 22383 } 22384 22385 int sx = 0; 22386 int sy = 0; 22387 if (!drawingWithRenderNode) { 22388 computeScroll(); 22389 sx = mScrollX; 22390 sy = mScrollY; 22391 } 22392 22393 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 22394 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 22395 22396 int restoreTo = -1; 22397 if (!drawingWithRenderNode || transformToApply != null) { 22398 restoreTo = canvas.save(); 22399 } 22400 if (offsetForScroll) { 22401 canvas.translate(mLeft - sx, mTop - sy); 22402 } else { 22403 if (!drawingWithRenderNode) { 22404 canvas.translate(mLeft, mTop); 22405 } 22406 if (scalingRequired) { 22407 if (drawingWithRenderNode) { 22408 // TODO: Might not need this if we put everything inside the DL 22409 restoreTo = canvas.save(); 22410 } 22411 // mAttachInfo cannot be null, otherwise scalingRequired == false 22412 final float scale = 1.0f / mAttachInfo.mApplicationScale; 22413 canvas.scale(scale, scale); 22414 } 22415 } 22416 22417 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 22418 if (transformToApply != null 22419 || alpha < 1 22420 || !hasIdentityMatrix() 22421 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 22422 if (transformToApply != null || !childHasIdentityMatrix) { 22423 int transX = 0; 22424 int transY = 0; 22425 22426 if (offsetForScroll) { 22427 transX = -sx; 22428 transY = -sy; 22429 } 22430 22431 if (transformToApply != null) { 22432 if (concatMatrix) { 22433 if (drawingWithRenderNode) { 22434 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 22435 } else { 22436 // Undo the scroll translation, apply the transformation matrix, 22437 // then redo the scroll translate to get the correct result. 22438 canvas.translate(-transX, -transY); 22439 canvas.concat(transformToApply.getMatrix()); 22440 canvas.translate(transX, transY); 22441 } 22442 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22443 } 22444 22445 float transformAlpha = transformToApply.getAlpha(); 22446 if (transformAlpha < 1) { 22447 alpha *= transformAlpha; 22448 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22449 } 22450 } 22451 22452 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 22453 canvas.translate(-transX, -transY); 22454 canvas.concat(getMatrix()); 22455 canvas.translate(transX, transY); 22456 } 22457 } 22458 22459 // Deal with alpha if it is or used to be <1 22460 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 22461 if (alpha < 1) { 22462 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 22463 } else { 22464 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 22465 } 22466 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22467 if (!drawingWithDrawingCache) { 22468 final int multipliedAlpha = (int) (255 * alpha); 22469 if (!onSetAlpha(multipliedAlpha)) { 22470 if (drawingWithRenderNode) { 22471 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 22472 } else if (layerType == LAYER_TYPE_NONE) { 22473 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 22474 multipliedAlpha); 22475 } 22476 } else { 22477 // Alpha is handled by the child directly, clobber the layer's alpha 22478 mPrivateFlags |= PFLAG_ALPHA_SET; 22479 } 22480 } 22481 } 22482 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 22483 onSetAlpha(255); 22484 mPrivateFlags &= ~PFLAG_ALPHA_SET; 22485 } 22486 22487 if (!drawingWithRenderNode) { 22488 // apply clips directly, since RenderNode won't do it for this draw 22489 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 22490 if (offsetForScroll) { 22491 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 22492 } else { 22493 if (!scalingRequired || cache == null) { 22494 canvas.clipRect(0, 0, getWidth(), getHeight()); 22495 } else { 22496 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 22497 } 22498 } 22499 } 22500 22501 if (mClipBounds != null) { 22502 // clip bounds ignore scroll 22503 canvas.clipRect(mClipBounds); 22504 } 22505 } 22506 22507 if (!drawingWithDrawingCache) { 22508 if (drawingWithRenderNode) { 22509 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22510 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22511 } else { 22512 // Fast path for layouts with no backgrounds 22513 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22514 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22515 dispatchDraw(canvas); 22516 } else { 22517 draw(canvas); 22518 } 22519 } 22520 } else if (cache != null) { 22521 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22522 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 22523 // no layer paint, use temporary paint to draw bitmap 22524 Paint cachePaint = parent.mCachePaint; 22525 if (cachePaint == null) { 22526 cachePaint = new Paint(); 22527 cachePaint.setDither(false); 22528 parent.mCachePaint = cachePaint; 22529 } 22530 cachePaint.setAlpha((int) (alpha * 255)); 22531 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 22532 } else { 22533 // use layer paint to draw the bitmap, merging the two alphas, but also restore 22534 int layerPaintAlpha = mLayerPaint.getAlpha(); 22535 if (alpha < 1) { 22536 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 22537 } 22538 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 22539 if (alpha < 1) { 22540 mLayerPaint.setAlpha(layerPaintAlpha); 22541 } 22542 } 22543 } 22544 22545 if (restoreTo >= 0) { 22546 canvas.restoreToCount(restoreTo); 22547 } 22548 22549 if (a != null && !more) { 22550 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 22551 onSetAlpha(255); 22552 } 22553 parent.finishAnimatingView(this, a); 22554 } 22555 22556 if (more && hardwareAcceleratedCanvas) { 22557 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 22558 // alpha animations should cause the child to recreate its display list 22559 invalidate(true); 22560 } 22561 } 22562 22563 mRecreateDisplayList = false; 22564 22565 return more; 22566 } 22567 getDebugPaint()22568 static Paint getDebugPaint() { 22569 if (sDebugPaint == null) { 22570 sDebugPaint = new Paint(); 22571 sDebugPaint.setAntiAlias(false); 22572 } 22573 return sDebugPaint; 22574 } 22575 dipsToPixels(int dips)22576 final int dipsToPixels(int dips) { 22577 float scale = getContext().getResources().getDisplayMetrics().density; 22578 return (int) (dips * scale + 0.5f); 22579 } 22580 debugDrawFocus(Canvas canvas)22581 final private void debugDrawFocus(Canvas canvas) { 22582 if (isFocused()) { 22583 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 22584 final int l = mScrollX; 22585 final int r = l + mRight - mLeft; 22586 final int t = mScrollY; 22587 final int b = t + mBottom - mTop; 22588 22589 final Paint paint = getDebugPaint(); 22590 paint.setColor(DEBUG_CORNERS_COLOR); 22591 22592 // Draw squares in corners. 22593 paint.setStyle(Paint.Style.FILL); 22594 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 22595 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 22596 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 22597 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 22598 22599 // Draw big X across the view. 22600 paint.setStyle(Paint.Style.STROKE); 22601 canvas.drawLine(l, t, r, b, paint); 22602 canvas.drawLine(l, b, r, t, paint); 22603 } 22604 } 22605 22606 /** 22607 * Manually render this view (and all of its children) to the given Canvas. 22608 * The view must have already done a full layout before this function is 22609 * called. When implementing a view, implement 22610 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 22611 * If you do need to override this method, call the superclass version. 22612 * 22613 * @param canvas The Canvas to which the View is rendered. 22614 */ 22615 @CallSuper draw(Canvas canvas)22616 public void draw(Canvas canvas) { 22617 final int privateFlags = mPrivateFlags; 22618 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 22619 22620 /* 22621 * Draw traversal performs several drawing steps which must be executed 22622 * in the appropriate order: 22623 * 22624 * 1. Draw the background 22625 * 2. If necessary, save the canvas' layers to prepare for fading 22626 * 3. Draw view's content 22627 * 4. Draw children 22628 * 5. If necessary, draw the fading edges and restore layers 22629 * 6. Draw decorations (scrollbars for instance) 22630 * 7. If necessary, draw the default focus highlight 22631 */ 22632 22633 // Step 1, draw the background, if needed 22634 int saveCount; 22635 22636 drawBackground(canvas); 22637 22638 // skip step 2 & 5 if possible (common case) 22639 final int viewFlags = mViewFlags; 22640 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 22641 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 22642 if (!verticalEdges && !horizontalEdges) { 22643 // Step 3, draw the content 22644 onDraw(canvas); 22645 22646 // Step 4, draw the children 22647 dispatchDraw(canvas); 22648 22649 drawAutofilledHighlight(canvas); 22650 22651 // Overlay is part of the content and draws beneath Foreground 22652 if (mOverlay != null && !mOverlay.isEmpty()) { 22653 mOverlay.getOverlayView().dispatchDraw(canvas); 22654 } 22655 22656 // Step 6, draw decorations (foreground, scrollbars) 22657 onDrawForeground(canvas); 22658 22659 // Step 7, draw the default focus highlight 22660 drawDefaultFocusHighlight(canvas); 22661 22662 if (isShowingLayoutBounds()) { 22663 debugDrawFocus(canvas); 22664 } 22665 22666 // we're done... 22667 return; 22668 } 22669 22670 /* 22671 * Here we do the full fledged routine... 22672 * (this is an uncommon case where speed matters less, 22673 * this is why we repeat some of the tests that have been 22674 * done above) 22675 */ 22676 22677 boolean drawTop = false; 22678 boolean drawBottom = false; 22679 boolean drawLeft = false; 22680 boolean drawRight = false; 22681 22682 float topFadeStrength = 0.0f; 22683 float bottomFadeStrength = 0.0f; 22684 float leftFadeStrength = 0.0f; 22685 float rightFadeStrength = 0.0f; 22686 22687 // Step 2, save the canvas' layers 22688 int paddingLeft = mPaddingLeft; 22689 22690 final boolean offsetRequired = isPaddingOffsetRequired(); 22691 if (offsetRequired) { 22692 paddingLeft += getLeftPaddingOffset(); 22693 } 22694 22695 int left = mScrollX + paddingLeft; 22696 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 22697 int top = mScrollY + getFadeTop(offsetRequired); 22698 int bottom = top + getFadeHeight(offsetRequired); 22699 22700 if (offsetRequired) { 22701 right += getRightPaddingOffset(); 22702 bottom += getBottomPaddingOffset(); 22703 } 22704 22705 final ScrollabilityCache scrollabilityCache = mScrollCache; 22706 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 22707 int length = (int) fadeHeight; 22708 22709 // clip the fade length if top and bottom fades overlap 22710 // overlapping fades produce odd-looking artifacts 22711 if (verticalEdges && (top + length > bottom - length)) { 22712 length = (bottom - top) / 2; 22713 } 22714 22715 // also clip horizontal fades if necessary 22716 if (horizontalEdges && (left + length > right - length)) { 22717 length = (right - left) / 2; 22718 } 22719 22720 if (verticalEdges) { 22721 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 22722 drawTop = topFadeStrength * fadeHeight > 1.0f; 22723 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 22724 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 22725 } 22726 22727 if (horizontalEdges) { 22728 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 22729 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 22730 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 22731 drawRight = rightFadeStrength * fadeHeight > 1.0f; 22732 } 22733 22734 saveCount = canvas.getSaveCount(); 22735 int topSaveCount = -1; 22736 int bottomSaveCount = -1; 22737 int leftSaveCount = -1; 22738 int rightSaveCount = -1; 22739 22740 int solidColor = getSolidColor(); 22741 if (solidColor == 0) { 22742 if (drawTop) { 22743 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 22744 } 22745 22746 if (drawBottom) { 22747 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 22748 } 22749 22750 if (drawLeft) { 22751 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 22752 } 22753 22754 if (drawRight) { 22755 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 22756 } 22757 } else { 22758 scrollabilityCache.setFadeColor(solidColor); 22759 } 22760 22761 // Step 3, draw the content 22762 onDraw(canvas); 22763 22764 // Step 4, draw the children 22765 dispatchDraw(canvas); 22766 22767 // Step 5, draw the fade effect and restore layers 22768 final Paint p = scrollabilityCache.paint; 22769 final Matrix matrix = scrollabilityCache.matrix; 22770 final Shader fade = scrollabilityCache.shader; 22771 22772 // must be restored in the reverse order that they were saved 22773 if (drawRight) { 22774 matrix.setScale(1, fadeHeight * rightFadeStrength); 22775 matrix.postRotate(90); 22776 matrix.postTranslate(right, top); 22777 fade.setLocalMatrix(matrix); 22778 p.setShader(fade); 22779 if (solidColor == 0) { 22780 canvas.restoreUnclippedLayer(rightSaveCount, p); 22781 22782 } else { 22783 canvas.drawRect(right - length, top, right, bottom, p); 22784 } 22785 } 22786 22787 if (drawLeft) { 22788 matrix.setScale(1, fadeHeight * leftFadeStrength); 22789 matrix.postRotate(-90); 22790 matrix.postTranslate(left, top); 22791 fade.setLocalMatrix(matrix); 22792 p.setShader(fade); 22793 if (solidColor == 0) { 22794 canvas.restoreUnclippedLayer(leftSaveCount, p); 22795 } else { 22796 canvas.drawRect(left, top, left + length, bottom, p); 22797 } 22798 } 22799 22800 if (drawBottom) { 22801 matrix.setScale(1, fadeHeight * bottomFadeStrength); 22802 matrix.postRotate(180); 22803 matrix.postTranslate(left, bottom); 22804 fade.setLocalMatrix(matrix); 22805 p.setShader(fade); 22806 if (solidColor == 0) { 22807 canvas.restoreUnclippedLayer(bottomSaveCount, p); 22808 } else { 22809 canvas.drawRect(left, bottom - length, right, bottom, p); 22810 } 22811 } 22812 22813 if (drawTop) { 22814 matrix.setScale(1, fadeHeight * topFadeStrength); 22815 matrix.postTranslate(left, top); 22816 fade.setLocalMatrix(matrix); 22817 p.setShader(fade); 22818 if (solidColor == 0) { 22819 canvas.restoreUnclippedLayer(topSaveCount, p); 22820 } else { 22821 canvas.drawRect(left, top, right, top + length, p); 22822 } 22823 } 22824 22825 canvas.restoreToCount(saveCount); 22826 22827 drawAutofilledHighlight(canvas); 22828 22829 // Overlay is part of the content and draws beneath Foreground 22830 if (mOverlay != null && !mOverlay.isEmpty()) { 22831 mOverlay.getOverlayView().dispatchDraw(canvas); 22832 } 22833 22834 // Step 6, draw decorations (foreground, scrollbars) 22835 onDrawForeground(canvas); 22836 22837 // Step 7, draw the default focus highlight 22838 drawDefaultFocusHighlight(canvas); 22839 22840 if (isShowingLayoutBounds()) { 22841 debugDrawFocus(canvas); 22842 } 22843 } 22844 22845 /** 22846 * Draws the background onto the specified canvas. 22847 * 22848 * @param canvas Canvas on which to draw the background 22849 */ 22850 @UnsupportedAppUsage drawBackground(Canvas canvas)22851 private void drawBackground(Canvas canvas) { 22852 final Drawable background = mBackground; 22853 if (background == null) { 22854 return; 22855 } 22856 22857 setBackgroundBounds(); 22858 22859 // Attempt to use a display list if requested. 22860 if (canvas.isHardwareAccelerated() && mAttachInfo != null 22861 && mAttachInfo.mThreadedRenderer != null) { 22862 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 22863 22864 final RenderNode renderNode = mBackgroundRenderNode; 22865 if (renderNode != null && renderNode.hasDisplayList()) { 22866 setBackgroundRenderNodeProperties(renderNode); 22867 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22868 return; 22869 } 22870 } 22871 22872 final int scrollX = mScrollX; 22873 final int scrollY = mScrollY; 22874 if ((scrollX | scrollY) == 0) { 22875 background.draw(canvas); 22876 } else { 22877 canvas.translate(scrollX, scrollY); 22878 background.draw(canvas); 22879 canvas.translate(-scrollX, -scrollY); 22880 } 22881 } 22882 22883 /** 22884 * Sets the correct background bounds and rebuilds the outline, if needed. 22885 * <p/> 22886 * This is called by LayoutLib. 22887 */ setBackgroundBounds()22888 void setBackgroundBounds() { 22889 if (mBackgroundSizeChanged && mBackground != null) { 22890 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 22891 mBackgroundSizeChanged = false; 22892 rebuildOutline(); 22893 } 22894 } 22895 setBackgroundRenderNodeProperties(RenderNode renderNode)22896 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 22897 renderNode.setTranslationX(mScrollX); 22898 renderNode.setTranslationY(mScrollY); 22899 } 22900 22901 /** 22902 * Creates a new display list or updates the existing display list for the 22903 * specified Drawable. 22904 * 22905 * @param drawable Drawable for which to create a display list 22906 * @param renderNode Existing RenderNode, or {@code null} 22907 * @return A valid display list for the specified drawable 22908 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)22909 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 22910 if (renderNode == null) { 22911 renderNode = RenderNode.create(drawable.getClass().getName(), 22912 new ViewAnimationHostBridge(this)); 22913 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 22914 } 22915 22916 final Rect bounds = drawable.getBounds(); 22917 final int width = bounds.width(); 22918 final int height = bounds.height(); 22919 22920 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 22921 // instead of being "stateful" like other RenderNode properties 22922 renderNode.clearStretch(); 22923 22924 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 22925 22926 // Reverse left/top translation done by drawable canvas, which will 22927 // instead be applied by rendernode's LTRB bounds below. This way, the 22928 // drawable's bounds match with its rendernode bounds and its content 22929 // will lie within those bounds in the rendernode tree. 22930 canvas.translate(-bounds.left, -bounds.top); 22931 22932 try { 22933 drawable.draw(canvas); 22934 } finally { 22935 renderNode.endRecording(); 22936 } 22937 22938 // Set up drawable properties that are view-independent. 22939 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 22940 renderNode.setProjectBackwards(drawable.isProjected()); 22941 renderNode.setProjectionReceiver(true); 22942 renderNode.setClipToBounds(false); 22943 return renderNode; 22944 } 22945 22946 /** 22947 * Returns the overlay for this view, creating it if it does not yet exist. 22948 * Adding drawables to the overlay will cause them to be displayed whenever 22949 * the view itself is redrawn. Objects in the overlay should be actively 22950 * managed: remove them when they should not be displayed anymore. The 22951 * overlay will always have the same size as its host view. 22952 * 22953 * <p>Note: Overlays do not currently work correctly with {@link 22954 * SurfaceView} or {@link TextureView}; contents in overlays for these 22955 * types of views may not display correctly.</p> 22956 * 22957 * @return The ViewOverlay object for this view. 22958 * @see ViewOverlay 22959 */ getOverlay()22960 public ViewOverlay getOverlay() { 22961 if (mOverlay == null) { 22962 mOverlay = new ViewOverlay(mContext, this); 22963 } 22964 return mOverlay; 22965 } 22966 22967 /** 22968 * Override this if your view is known to always be drawn on top of a solid color background, 22969 * and needs to draw fading edges. Returning a non-zero color enables the view system to 22970 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 22971 * should be set to 0xFF. 22972 * 22973 * @see #setVerticalFadingEdgeEnabled(boolean) 22974 * @see #setHorizontalFadingEdgeEnabled(boolean) 22975 * 22976 * @return The known solid color background for this view, or 0 if the color may vary 22977 */ 22978 @ViewDebug.ExportedProperty(category = "drawing") 22979 @InspectableProperty 22980 @ColorInt getSolidColor()22981 public int getSolidColor() { 22982 return 0; 22983 } 22984 22985 /** 22986 * Build a human readable string representation of the specified view flags. 22987 * 22988 * @param flags the view flags to convert to a string 22989 * @return a String representing the supplied flags 22990 */ printFlags(int flags)22991 private static String printFlags(int flags) { 22992 String output = ""; 22993 int numFlags = 0; 22994 if ((flags & FOCUSABLE) == FOCUSABLE) { 22995 output += "TAKES_FOCUS"; 22996 numFlags++; 22997 } 22998 22999 switch (flags & VISIBILITY_MASK) { 23000 case INVISIBLE: 23001 if (numFlags > 0) { 23002 output += " "; 23003 } 23004 output += "INVISIBLE"; 23005 // USELESS HERE numFlags++; 23006 break; 23007 case GONE: 23008 if (numFlags > 0) { 23009 output += " "; 23010 } 23011 output += "GONE"; 23012 // USELESS HERE numFlags++; 23013 break; 23014 default: 23015 break; 23016 } 23017 return output; 23018 } 23019 23020 /** 23021 * Build a human readable string representation of the specified private 23022 * view flags. 23023 * 23024 * @param privateFlags the private view flags to convert to a string 23025 * @return a String representing the supplied flags 23026 */ printPrivateFlags(int privateFlags)23027 private static String printPrivateFlags(int privateFlags) { 23028 String output = ""; 23029 int numFlags = 0; 23030 23031 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 23032 output += "WANTS_FOCUS"; 23033 numFlags++; 23034 } 23035 23036 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 23037 if (numFlags > 0) { 23038 output += " "; 23039 } 23040 output += "FOCUSED"; 23041 numFlags++; 23042 } 23043 23044 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 23045 if (numFlags > 0) { 23046 output += " "; 23047 } 23048 output += "SELECTED"; 23049 numFlags++; 23050 } 23051 23052 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 23053 if (numFlags > 0) { 23054 output += " "; 23055 } 23056 output += "IS_ROOT_NAMESPACE"; 23057 numFlags++; 23058 } 23059 23060 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 23061 if (numFlags > 0) { 23062 output += " "; 23063 } 23064 output += "HAS_BOUNDS"; 23065 numFlags++; 23066 } 23067 23068 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 23069 if (numFlags > 0) { 23070 output += " "; 23071 } 23072 output += "DRAWN"; 23073 // USELESS HERE numFlags++; 23074 } 23075 return output; 23076 } 23077 23078 /** 23079 * <p>Indicates whether or not this view's layout will be requested during 23080 * the next hierarchy layout pass.</p> 23081 * 23082 * @return true if the layout will be forced during next layout pass 23083 */ isLayoutRequested()23084 public boolean isLayoutRequested() { 23085 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 23086 } 23087 23088 /** 23089 * Return true if o is a ViewGroup that is laying out using optical bounds. 23090 * @hide 23091 */ isLayoutModeOptical(Object o)23092 public static boolean isLayoutModeOptical(Object o) { 23093 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 23094 } 23095 setOpticalFrame(int left, int top, int right, int bottom)23096 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 23097 Insets parentInsets = mParent instanceof View ? 23098 ((View) mParent).getOpticalInsets() : Insets.NONE; 23099 Insets childInsets = getOpticalInsets(); 23100 return setFrame( 23101 left + parentInsets.left - childInsets.left, 23102 top + parentInsets.top - childInsets.top, 23103 right + parentInsets.left + childInsets.right, 23104 bottom + parentInsets.top + childInsets.bottom); 23105 } 23106 23107 /** 23108 * Assign a size and position to a view and all of its 23109 * descendants 23110 * 23111 * <p>This is the second phase of the layout mechanism. 23112 * (The first is measuring). In this phase, each parent calls 23113 * layout on all of its children to position them. 23114 * This is typically done using the child measurements 23115 * that were stored in the measure pass().</p> 23116 * 23117 * <p>Derived classes should not override this method. 23118 * Derived classes with children should override 23119 * onLayout. In that method, they should 23120 * call layout on each of their children.</p> 23121 * 23122 * @param l Left position, relative to parent 23123 * @param t Top position, relative to parent 23124 * @param r Right position, relative to parent 23125 * @param b Bottom position, relative to parent 23126 */ 23127 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)23128 public void layout(int l, int t, int r, int b) { 23129 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 23130 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 23131 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 23132 } 23133 23134 int oldL = mLeft; 23135 int oldT = mTop; 23136 int oldB = mBottom; 23137 int oldR = mRight; 23138 23139 boolean changed = isLayoutModeOptical(mParent) ? 23140 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 23141 23142 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 23143 onLayout(changed, l, t, r, b); 23144 23145 if (shouldDrawRoundScrollbar()) { 23146 if(mRoundScrollbarRenderer == null) { 23147 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 23148 } 23149 } else { 23150 mRoundScrollbarRenderer = null; 23151 } 23152 23153 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 23154 23155 ListenerInfo li = mListenerInfo; 23156 if (li != null && li.mOnLayoutChangeListeners != null) { 23157 ArrayList<OnLayoutChangeListener> listenersCopy = 23158 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 23159 int numListeners = listenersCopy.size(); 23160 for (int i = 0; i < numListeners; ++i) { 23161 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 23162 } 23163 } 23164 } 23165 23166 final boolean wasLayoutValid = isLayoutValid(); 23167 23168 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 23169 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 23170 23171 if (!wasLayoutValid && isFocused()) { 23172 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 23173 if (canTakeFocus()) { 23174 // We have a robust focus, so parents should no longer be wanting focus. 23175 clearParentsWantFocus(); 23176 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 23177 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 23178 // layout. In this case, there's no guarantee that parent layouts will be evaluated 23179 // and thus the safest action is to clear focus here. 23180 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23181 clearParentsWantFocus(); 23182 } else if (!hasParentWantsFocus()) { 23183 // original requestFocus was likely on this view directly, so just clear focus 23184 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23185 } 23186 // otherwise, we let parents handle re-assigning focus during their layout passes. 23187 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 23188 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 23189 View focused = findFocus(); 23190 if (focused != null) { 23191 // Try to restore focus as close as possible to our starting focus. 23192 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 23193 // Give up and clear focus once we've reached the top-most parent which wants 23194 // focus. 23195 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 23196 } 23197 } 23198 } 23199 23200 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 23201 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 23202 notifyEnterOrExitForAutoFillIfNeeded(true); 23203 } 23204 23205 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 23206 } 23207 hasParentWantsFocus()23208 private boolean hasParentWantsFocus() { 23209 ViewParent parent = mParent; 23210 while (parent instanceof ViewGroup) { 23211 ViewGroup pv = (ViewGroup) parent; 23212 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 23213 return true; 23214 } 23215 parent = pv.mParent; 23216 } 23217 return false; 23218 } 23219 23220 /** 23221 * Called from layout when this view should 23222 * assign a size and position to each of its children. 23223 * 23224 * Derived classes with children should override 23225 * this method and call layout on each of 23226 * their children. 23227 * @param changed This is a new size or position for this view 23228 * @param left Left position, relative to parent 23229 * @param top Top position, relative to parent 23230 * @param right Right position, relative to parent 23231 * @param bottom Bottom position, relative to parent 23232 */ onLayout(boolean changed, int left, int top, int right, int bottom)23233 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 23234 } 23235 23236 /** 23237 * Assign a size and position to this view. 23238 * 23239 * This is called from layout. 23240 * 23241 * @param left Left position, relative to parent 23242 * @param top Top position, relative to parent 23243 * @param right Right position, relative to parent 23244 * @param bottom Bottom position, relative to parent 23245 * @return true if the new size and position are different than the 23246 * previous ones 23247 * {@hide} 23248 */ 23249 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)23250 protected boolean setFrame(int left, int top, int right, int bottom) { 23251 boolean changed = false; 23252 23253 if (DBG) { 23254 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 23255 + right + "," + bottom + ")"); 23256 } 23257 23258 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 23259 changed = true; 23260 23261 // Remember our drawn bit 23262 int drawn = mPrivateFlags & PFLAG_DRAWN; 23263 23264 int oldWidth = mRight - mLeft; 23265 int oldHeight = mBottom - mTop; 23266 int newWidth = right - left; 23267 int newHeight = bottom - top; 23268 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 23269 23270 // Invalidate our old position 23271 invalidate(sizeChanged); 23272 23273 mLeft = left; 23274 mTop = top; 23275 mRight = right; 23276 mBottom = bottom; 23277 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 23278 23279 mPrivateFlags |= PFLAG_HAS_BOUNDS; 23280 23281 23282 if (sizeChanged) { 23283 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 23284 } 23285 23286 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 23287 // If we are visible, force the DRAWN bit to on so that 23288 // this invalidate will go through (at least to our parent). 23289 // This is because someone may have invalidated this view 23290 // before this call to setFrame came in, thereby clearing 23291 // the DRAWN bit. 23292 mPrivateFlags |= PFLAG_DRAWN; 23293 invalidate(sizeChanged); 23294 // parent display list may need to be recreated based on a change in the bounds 23295 // of any child 23296 invalidateParentCaches(); 23297 } 23298 23299 // Reset drawn bit to original value (invalidate turns it off) 23300 mPrivateFlags |= drawn; 23301 23302 mBackgroundSizeChanged = true; 23303 mDefaultFocusHighlightSizeChanged = true; 23304 if (mForegroundInfo != null) { 23305 mForegroundInfo.mBoundsChanged = true; 23306 } 23307 23308 notifySubtreeAccessibilityStateChangedIfNeeded(); 23309 } 23310 return changed; 23311 } 23312 23313 /** 23314 * Assign a size and position to this view. 23315 * 23316 * This method is meant to be used in animations only as it applies this position and size 23317 * for the view only temporary and it can be changed back at any time by the layout. 23318 * 23319 * @param left Left position, relative to parent 23320 * @param top Top position, relative to parent 23321 * @param right Right position, relative to parent 23322 * @param bottom Bottom position, relative to parent 23323 * 23324 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 23325 */ setLeftTopRightBottom(int left, int top, int right, int bottom)23326 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 23327 setFrame(left, top, right, bottom); 23328 } 23329 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)23330 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 23331 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 23332 if (mOverlay != null) { 23333 mOverlay.getOverlayView().setRight(newWidth); 23334 mOverlay.getOverlayView().setBottom(newHeight); 23335 } 23336 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 23337 // backtracking" of requestFocus during layout, so don't touch focus here. 23338 if (!sCanFocusZeroSized && isLayoutValid() 23339 // Don't touch focus if animating 23340 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 23341 if (newWidth <= 0 || newHeight <= 0) { 23342 if (hasFocus()) { 23343 clearFocus(); 23344 if (mParent instanceof ViewGroup) { 23345 ((ViewGroup) mParent).clearFocusedInCluster(); 23346 } 23347 } 23348 clearAccessibilityFocus(); 23349 } else if (oldWidth <= 0 || oldHeight <= 0) { 23350 if (mParent != null && canTakeFocus()) { 23351 mParent.focusableViewAvailable(this); 23352 } 23353 } 23354 } 23355 rebuildOutline(); 23356 } 23357 23358 /** 23359 * Finalize inflating a view from XML. This is called as the last phase 23360 * of inflation, after all child views have been added. 23361 * 23362 * <p>Even if the subclass overrides onFinishInflate, they should always be 23363 * sure to call the super method, so that we get called. 23364 */ 23365 @CallSuper onFinishInflate()23366 protected void onFinishInflate() { 23367 } 23368 23369 /** 23370 * Returns the resources associated with this view. 23371 * 23372 * @return Resources object. 23373 */ getResources()23374 public Resources getResources() { 23375 return mResources; 23376 } 23377 23378 /** 23379 * Invalidates the specified Drawable. 23380 * 23381 * @param drawable the drawable to invalidate 23382 */ 23383 @Override invalidateDrawable(@onNull Drawable drawable)23384 public void invalidateDrawable(@NonNull Drawable drawable) { 23385 if (verifyDrawable(drawable)) { 23386 final Rect dirty = drawable.getDirtyBounds(); 23387 final int scrollX = mScrollX; 23388 final int scrollY = mScrollY; 23389 23390 invalidate(dirty.left + scrollX, dirty.top + scrollY, 23391 dirty.right + scrollX, dirty.bottom + scrollY); 23392 rebuildOutline(); 23393 } 23394 } 23395 23396 /** 23397 * Schedules an action on a drawable to occur at a specified time. 23398 * 23399 * @param who the recipient of the action 23400 * @param what the action to run on the drawable 23401 * @param when the time at which the action must occur. Uses the 23402 * {@link SystemClock#uptimeMillis} timebase. 23403 */ 23404 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)23405 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 23406 if (verifyDrawable(who) && what != null) { 23407 final long delay = when - SystemClock.uptimeMillis(); 23408 if (mAttachInfo != null) { 23409 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 23410 Choreographer.CALLBACK_ANIMATION, what, who, 23411 Choreographer.subtractFrameDelay(delay)); 23412 } else { 23413 // Postpone the runnable until we know 23414 // on which thread it needs to run. 23415 getRunQueue().postDelayed(what, delay); 23416 } 23417 } 23418 } 23419 23420 /** 23421 * Cancels a scheduled action on a drawable. 23422 * 23423 * @param who the recipient of the action 23424 * @param what the action to cancel 23425 */ 23426 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)23427 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 23428 if (verifyDrawable(who) && what != null) { 23429 if (mAttachInfo != null) { 23430 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 23431 Choreographer.CALLBACK_ANIMATION, what, who); 23432 } 23433 getRunQueue().removeCallbacks(what); 23434 } 23435 } 23436 23437 /** 23438 * Unschedule any events associated with the given Drawable. This can be 23439 * used when selecting a new Drawable into a view, so that the previous 23440 * one is completely unscheduled. 23441 * 23442 * @param who The Drawable to unschedule. 23443 * 23444 * @see #drawableStateChanged 23445 */ unscheduleDrawable(Drawable who)23446 public void unscheduleDrawable(Drawable who) { 23447 if (mAttachInfo != null && who != null) { 23448 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 23449 Choreographer.CALLBACK_ANIMATION, null, who); 23450 } 23451 } 23452 23453 /** 23454 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 23455 * that the View directionality can and will be resolved before its Drawables. 23456 * 23457 * Will call {@link View#onResolveDrawables} when resolution is done. 23458 * 23459 * @hide 23460 */ resolveDrawables()23461 protected void resolveDrawables() { 23462 // Drawables resolution may need to happen before resolving the layout direction (which is 23463 // done only during the measure() call). 23464 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 23465 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 23466 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 23467 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 23468 // direction to be resolved as its resolved value will be the same as its raw value. 23469 if (!isLayoutDirectionResolved() && 23470 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 23471 return; 23472 } 23473 23474 final int layoutDirection = isLayoutDirectionResolved() ? 23475 getLayoutDirection() : getRawLayoutDirection(); 23476 23477 if (mBackground != null) { 23478 mBackground.setLayoutDirection(layoutDirection); 23479 } 23480 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23481 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 23482 } 23483 if (mDefaultFocusHighlight != null) { 23484 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 23485 } 23486 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 23487 onResolveDrawables(layoutDirection); 23488 } 23489 areDrawablesResolved()23490 boolean areDrawablesResolved() { 23491 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 23492 } 23493 23494 /** 23495 * Called when layout direction has been resolved. 23496 * 23497 * The default implementation does nothing. 23498 * 23499 * @param layoutDirection The resolved layout direction. 23500 * 23501 * @see #LAYOUT_DIRECTION_LTR 23502 * @see #LAYOUT_DIRECTION_RTL 23503 * 23504 * @hide 23505 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)23506 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 23507 } 23508 23509 /** 23510 * @hide 23511 */ 23512 @TestApi resetResolvedDrawables()23513 protected void resetResolvedDrawables() { 23514 resetResolvedDrawablesInternal(); 23515 } 23516 resetResolvedDrawablesInternal()23517 void resetResolvedDrawablesInternal() { 23518 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 23519 } 23520 23521 /** 23522 * If your view subclass is displaying its own Drawable objects, it should 23523 * override this function and return true for any Drawable it is 23524 * displaying. This allows animations for those drawables to be 23525 * scheduled. 23526 * 23527 * <p>Be sure to call through to the super class when overriding this 23528 * function. 23529 * 23530 * @param who The Drawable to verify. Return true if it is one you are 23531 * displaying, else return the result of calling through to the 23532 * super class. 23533 * 23534 * @return boolean If true then the Drawable is being displayed in the 23535 * view; else false and it is not allowed to animate. 23536 * 23537 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 23538 * @see #drawableStateChanged() 23539 */ 23540 @CallSuper verifyDrawable(@onNull Drawable who)23541 protected boolean verifyDrawable(@NonNull Drawable who) { 23542 // Avoid verifying the scroll bar drawable so that we don't end up in 23543 // an invalidation loop. This effectively prevents the scroll bar 23544 // drawable from triggering invalidations and scheduling runnables. 23545 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 23546 || (mDefaultFocusHighlight == who); 23547 } 23548 23549 /** 23550 * This function is called whenever the state of the view changes in such 23551 * a way that it impacts the state of drawables being shown. 23552 * <p> 23553 * If the View has a StateListAnimator, it will also be called to run necessary state 23554 * change animations. 23555 * <p> 23556 * Be sure to call through to the superclass when overriding this function. 23557 * 23558 * @see Drawable#setState(int[]) 23559 */ 23560 @CallSuper drawableStateChanged()23561 protected void drawableStateChanged() { 23562 final int[] state = getDrawableState(); 23563 boolean changed = false; 23564 23565 final Drawable bg = mBackground; 23566 if (bg != null && bg.isStateful()) { 23567 changed |= bg.setState(state); 23568 } 23569 23570 final Drawable hl = mDefaultFocusHighlight; 23571 if (hl != null && hl.isStateful()) { 23572 changed |= hl.setState(state); 23573 } 23574 23575 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23576 if (fg != null && fg.isStateful()) { 23577 changed |= fg.setState(state); 23578 } 23579 23580 if (mScrollCache != null) { 23581 final Drawable scrollBar = mScrollCache.scrollBar; 23582 if (scrollBar != null && scrollBar.isStateful()) { 23583 changed |= scrollBar.setState(state) 23584 && mScrollCache.state != ScrollabilityCache.OFF; 23585 } 23586 } 23587 23588 if (mStateListAnimator != null) { 23589 mStateListAnimator.setState(state); 23590 } 23591 23592 if (!isAggregatedVisible()) { 23593 // If we're not visible, skip any animated changes 23594 jumpDrawablesToCurrentState(); 23595 } 23596 23597 if (changed) { 23598 invalidate(); 23599 } 23600 } 23601 23602 /** 23603 * This function is called whenever the view hotspot changes and needs to 23604 * be propagated to drawables or child views managed by the view. 23605 * <p> 23606 * Dispatching to child views is handled by 23607 * {@link #dispatchDrawableHotspotChanged(float, float)}. 23608 * <p> 23609 * Be sure to call through to the superclass when overriding this function. 23610 * 23611 * @param x hotspot x coordinate 23612 * @param y hotspot y coordinate 23613 */ 23614 @CallSuper drawableHotspotChanged(float x, float y)23615 public void drawableHotspotChanged(float x, float y) { 23616 if (mBackground != null) { 23617 mBackground.setHotspot(x, y); 23618 } 23619 if (mDefaultFocusHighlight != null) { 23620 mDefaultFocusHighlight.setHotspot(x, y); 23621 } 23622 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23623 mForegroundInfo.mDrawable.setHotspot(x, y); 23624 } 23625 23626 dispatchDrawableHotspotChanged(x, y); 23627 } 23628 23629 /** 23630 * Dispatches drawableHotspotChanged to all of this View's children. 23631 * 23632 * @param x hotspot x coordinate 23633 * @param y hotspot y coordinate 23634 * @see #drawableHotspotChanged(float, float) 23635 */ dispatchDrawableHotspotChanged(float x, float y)23636 public void dispatchDrawableHotspotChanged(float x, float y) { 23637 } 23638 23639 /** 23640 * Call this to force a view to update its drawable state. This will cause 23641 * drawableStateChanged to be called on this view. Views that are interested 23642 * in the new state should call getDrawableState. 23643 * 23644 * @see #drawableStateChanged 23645 * @see #getDrawableState 23646 */ refreshDrawableState()23647 public void refreshDrawableState() { 23648 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 23649 drawableStateChanged(); 23650 23651 ViewParent parent = mParent; 23652 if (parent != null) { 23653 parent.childDrawableStateChanged(this); 23654 } 23655 } 23656 23657 /** 23658 * Create a default focus highlight if it doesn't exist. 23659 * @return a default focus highlight. 23660 */ getDefaultFocusHighlightDrawable()23661 private Drawable getDefaultFocusHighlightDrawable() { 23662 if (mDefaultFocusHighlightCache == null) { 23663 if (mContext != null) { 23664 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 23665 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 23666 mDefaultFocusHighlightCache = ta.getDrawable(0); 23667 ta.recycle(); 23668 } 23669 } 23670 return mDefaultFocusHighlightCache; 23671 } 23672 23673 /** 23674 * Set the current default focus highlight. 23675 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 23676 */ setDefaultFocusHighlight(Drawable highlight)23677 private void setDefaultFocusHighlight(Drawable highlight) { 23678 mDefaultFocusHighlight = highlight; 23679 mDefaultFocusHighlightSizeChanged = true; 23680 if (highlight != null) { 23681 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23682 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23683 } 23684 highlight.setLayoutDirection(getLayoutDirection()); 23685 if (highlight.isStateful()) { 23686 highlight.setState(getDrawableState()); 23687 } 23688 if (isAttachedToWindow()) { 23689 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23690 } 23691 // Set callback last, since the view may still be initializing. 23692 highlight.setCallback(this); 23693 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23694 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 23695 mPrivateFlags |= PFLAG_SKIP_DRAW; 23696 } 23697 invalidate(); 23698 } 23699 23700 /** 23701 * Check whether we need to draw a default focus highlight when this view gets focused, 23702 * which requires: 23703 * <ul> 23704 * <li>In both background and foreground, {@link android.R.attr#state_focused} 23705 * is not defined.</li> 23706 * <li>This view is not in touch mode.</li> 23707 * <li>This view doesn't opt out for a default focus highlight, via 23708 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 23709 * <li>This view is attached to window.</li> 23710 * </ul> 23711 * @return {@code true} if a default focus highlight is needed. 23712 * @hide 23713 */ 23714 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)23715 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 23716 final boolean lackFocusState = (background == null || !background.isStateful() 23717 || !background.hasFocusStateSpecified()) 23718 && (foreground == null || !foreground.isStateful() 23719 || !foreground.hasFocusStateSpecified()); 23720 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 23721 && isAttachedToWindow() && sUseDefaultFocusHighlight; 23722 } 23723 23724 /** 23725 * When this view is focused, switches on/off the default focused highlight. 23726 * <p> 23727 * This always happens when this view is focused, and only at this moment the default focus 23728 * highlight can be visible. 23729 */ switchDefaultFocusHighlight()23730 private void switchDefaultFocusHighlight() { 23731 if (isFocused()) { 23732 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 23733 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 23734 final boolean active = mDefaultFocusHighlight != null; 23735 if (needed && !active) { 23736 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 23737 } else if (!needed && active) { 23738 // The highlight is no longer needed, so tear it down. 23739 setDefaultFocusHighlight(null); 23740 } 23741 } 23742 } 23743 23744 /** 23745 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 23746 * @param canvas the canvas where we're drawing the highlight. 23747 */ drawDefaultFocusHighlight(Canvas canvas)23748 private void drawDefaultFocusHighlight(Canvas canvas) { 23749 if (mDefaultFocusHighlight != null && isFocused()) { 23750 if (mDefaultFocusHighlightSizeChanged) { 23751 mDefaultFocusHighlightSizeChanged = false; 23752 final int l = mScrollX; 23753 final int r = l + mRight - mLeft; 23754 final int t = mScrollY; 23755 final int b = t + mBottom - mTop; 23756 mDefaultFocusHighlight.setBounds(l, t, r, b); 23757 } 23758 mDefaultFocusHighlight.draw(canvas); 23759 } 23760 } 23761 23762 /** 23763 * Return an array of resource IDs of the drawable states representing the 23764 * current state of the view. 23765 * 23766 * @return The current drawable state 23767 * 23768 * @see Drawable#setState(int[]) 23769 * @see #drawableStateChanged() 23770 * @see #onCreateDrawableState(int) 23771 */ getDrawableState()23772 public final int[] getDrawableState() { 23773 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 23774 return mDrawableState; 23775 } else { 23776 mDrawableState = onCreateDrawableState(0); 23777 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 23778 return mDrawableState; 23779 } 23780 } 23781 23782 /** 23783 * Generate the new {@link android.graphics.drawable.Drawable} state for 23784 * this view. This is called by the view 23785 * system when the cached Drawable state is determined to be invalid. To 23786 * retrieve the current state, you should use {@link #getDrawableState}. 23787 * 23788 * @param extraSpace if non-zero, this is the number of extra entries you 23789 * would like in the returned array in which you can place your own 23790 * states. 23791 * 23792 * @return Returns an array holding the current {@link Drawable} state of 23793 * the view. 23794 * 23795 * @see #mergeDrawableStates(int[], int[]) 23796 */ onCreateDrawableState(int extraSpace)23797 protected int[] onCreateDrawableState(int extraSpace) { 23798 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 23799 mParent instanceof View) { 23800 return ((View) mParent).onCreateDrawableState(extraSpace); 23801 } 23802 23803 int[] drawableState; 23804 23805 int privateFlags = mPrivateFlags; 23806 23807 int viewStateIndex = 0; 23808 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 23809 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 23810 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 23811 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 23812 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 23813 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 23814 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { 23815 // This is set if HW acceleration is requested, even if the current 23816 // process doesn't allow it. This is just to allow app preview 23817 // windows to better match their app. 23818 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 23819 } 23820 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 23821 23822 final int privateFlags2 = mPrivateFlags2; 23823 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 23824 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 23825 } 23826 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 23827 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 23828 } 23829 23830 drawableState = StateSet.get(viewStateIndex); 23831 23832 //noinspection ConstantIfStatement 23833 if (false) { 23834 Log.i("View", "drawableStateIndex=" + viewStateIndex); 23835 Log.i("View", toString() 23836 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 23837 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 23838 + " fo=" + hasFocus() 23839 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 23840 + " wf=" + hasWindowFocus() 23841 + ": " + Arrays.toString(drawableState)); 23842 } 23843 23844 if (extraSpace == 0) { 23845 return drawableState; 23846 } 23847 23848 final int[] fullState; 23849 if (drawableState != null) { 23850 fullState = new int[drawableState.length + extraSpace]; 23851 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 23852 } else { 23853 fullState = new int[extraSpace]; 23854 } 23855 23856 return fullState; 23857 } 23858 23859 /** 23860 * Merge your own state values in <var>additionalState</var> into the base 23861 * state values <var>baseState</var> that were returned by 23862 * {@link #onCreateDrawableState(int)}. 23863 * 23864 * @param baseState The base state values returned by 23865 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 23866 * own additional state values. 23867 * 23868 * @param additionalState The additional state values you would like 23869 * added to <var>baseState</var>; this array is not modified. 23870 * 23871 * @return As a convenience, the <var>baseState</var> array you originally 23872 * passed into the function is returned. 23873 * 23874 * @see #onCreateDrawableState(int) 23875 */ mergeDrawableStates(int[] baseState, int[] additionalState)23876 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 23877 final int N = baseState.length; 23878 int i = N - 1; 23879 while (i >= 0 && baseState[i] == 0) { 23880 i--; 23881 } 23882 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 23883 return baseState; 23884 } 23885 23886 /** 23887 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 23888 * on all Drawable objects associated with this view. 23889 * <p> 23890 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 23891 * attached to this view. 23892 */ 23893 @CallSuper jumpDrawablesToCurrentState()23894 public void jumpDrawablesToCurrentState() { 23895 if (mBackground != null) { 23896 mBackground.jumpToCurrentState(); 23897 } 23898 if (mStateListAnimator != null) { 23899 mStateListAnimator.jumpToCurrentState(); 23900 } 23901 if (mDefaultFocusHighlight != null) { 23902 mDefaultFocusHighlight.jumpToCurrentState(); 23903 } 23904 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23905 mForegroundInfo.mDrawable.jumpToCurrentState(); 23906 } 23907 } 23908 23909 /** 23910 * Sets the background color for this view. 23911 * @param color the color of the background 23912 */ 23913 @RemotableViewMethod setBackgroundColor(@olorInt int color)23914 public void setBackgroundColor(@ColorInt int color) { 23915 if (mBackground instanceof ColorDrawable) { 23916 ((ColorDrawable) mBackground.mutate()).setColor(color); 23917 computeOpaqueFlags(); 23918 mBackgroundResource = 0; 23919 } else { 23920 setBackground(new ColorDrawable(color)); 23921 } 23922 } 23923 23924 /** 23925 * Set the background to a given resource. The resource should refer to 23926 * a Drawable object or 0 to remove the background. 23927 * @param resid The identifier of the resource. 23928 * 23929 * @attr ref android.R.styleable#View_background 23930 */ 23931 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)23932 public void setBackgroundResource(@DrawableRes int resid) { 23933 if (resid != 0 && resid == mBackgroundResource) { 23934 return; 23935 } 23936 23937 Drawable d = null; 23938 if (resid != 0) { 23939 d = mContext.getDrawable(resid); 23940 } 23941 setBackground(d); 23942 23943 mBackgroundResource = resid; 23944 } 23945 23946 /** 23947 * Set the background to a given Drawable, or remove the background. If the 23948 * background has padding, this View's padding is set to the background's 23949 * padding. However, when a background is removed, this View's padding isn't 23950 * touched. If setting the padding is desired, please use 23951 * {@link #setPadding(int, int, int, int)}. 23952 * 23953 * @param background The Drawable to use as the background, or null to remove the 23954 * background 23955 */ setBackground(Drawable background)23956 public void setBackground(Drawable background) { 23957 //noinspection deprecation 23958 setBackgroundDrawable(background); 23959 } 23960 23961 /** 23962 * @deprecated use {@link #setBackground(Drawable)} instead 23963 */ 23964 @Deprecated setBackgroundDrawable(Drawable background)23965 public void setBackgroundDrawable(Drawable background) { 23966 computeOpaqueFlags(); 23967 23968 if (background == mBackground) { 23969 return; 23970 } 23971 23972 boolean requestLayout = false; 23973 23974 mBackgroundResource = 0; 23975 23976 /* 23977 * Regardless of whether we're setting a new background or not, we want 23978 * to clear the previous drawable. setVisible first while we still have the callback set. 23979 */ 23980 if (mBackground != null) { 23981 if (isAttachedToWindow()) { 23982 mBackground.setVisible(false, false); 23983 } 23984 mBackground.setCallback(null); 23985 unscheduleDrawable(mBackground); 23986 } 23987 23988 if (background != null) { 23989 Rect padding = sThreadLocal.get(); 23990 if (padding == null) { 23991 padding = new Rect(); 23992 sThreadLocal.set(padding); 23993 } 23994 resetResolvedDrawablesInternal(); 23995 background.setLayoutDirection(getLayoutDirection()); 23996 if (background.getPadding(padding)) { 23997 resetResolvedPaddingInternal(); 23998 switch (background.getLayoutDirection()) { 23999 case LAYOUT_DIRECTION_RTL: 24000 mUserPaddingLeftInitial = padding.right; 24001 mUserPaddingRightInitial = padding.left; 24002 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 24003 break; 24004 case LAYOUT_DIRECTION_LTR: 24005 default: 24006 mUserPaddingLeftInitial = padding.left; 24007 mUserPaddingRightInitial = padding.right; 24008 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 24009 } 24010 mLeftPaddingDefined = false; 24011 mRightPaddingDefined = false; 24012 } 24013 24014 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 24015 // if it has a different minimum size, we should layout again 24016 if (mBackground == null 24017 || mBackground.getMinimumHeight() != background.getMinimumHeight() 24018 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 24019 requestLayout = true; 24020 } 24021 24022 // Set mBackground before we set this as the callback and start making other 24023 // background drawable state change calls. In particular, the setVisible call below 24024 // can result in drawables attempting to start animations or otherwise invalidate, 24025 // which requires the view set as the callback (us) to recognize the drawable as 24026 // belonging to it as per verifyDrawable. 24027 mBackground = background; 24028 if (background.isStateful()) { 24029 background.setState(getDrawableState()); 24030 } 24031 if (isAttachedToWindow()) { 24032 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24033 } 24034 24035 applyBackgroundTint(); 24036 24037 // Set callback last, since the view may still be initializing. 24038 background.setCallback(this); 24039 24040 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24041 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24042 requestLayout = true; 24043 } 24044 } else { 24045 /* Remove the background */ 24046 mBackground = null; 24047 if ((mViewFlags & WILL_NOT_DRAW) != 0 24048 && (mDefaultFocusHighlight == null) 24049 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 24050 mPrivateFlags |= PFLAG_SKIP_DRAW; 24051 } 24052 24053 /* 24054 * When the background is set, we try to apply its padding to this 24055 * View. When the background is removed, we don't touch this View's 24056 * padding. This is noted in the Javadocs. Hence, we don't need to 24057 * requestLayout(), the invalidate() below is sufficient. 24058 */ 24059 24060 // The old background's minimum size could have affected this 24061 // View's layout, so let's requestLayout 24062 requestLayout = true; 24063 } 24064 24065 computeOpaqueFlags(); 24066 24067 if (requestLayout) { 24068 requestLayout(); 24069 } 24070 24071 mBackgroundSizeChanged = true; 24072 invalidate(true); 24073 invalidateOutline(); 24074 } 24075 24076 /** 24077 * Gets the background drawable 24078 * 24079 * @return The drawable used as the background for this view, if any. 24080 * 24081 * @see #setBackground(Drawable) 24082 * 24083 * @attr ref android.R.styleable#View_background 24084 */ 24085 @InspectableProperty getBackground()24086 public Drawable getBackground() { 24087 return mBackground; 24088 } 24089 24090 /** 24091 * Applies a tint to the background drawable. Does not modify the current tint 24092 * mode, which is {@link BlendMode#SRC_IN} by default. 24093 * <p> 24094 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 24095 * mutate the drawable and apply the specified tint and tint mode using 24096 * {@link Drawable#setTintList(ColorStateList)}. 24097 * 24098 * @param tint the tint to apply, may be {@code null} to clear tint 24099 * 24100 * @attr ref android.R.styleable#View_backgroundTint 24101 * @see #getBackgroundTintList() 24102 * @see Drawable#setTintList(ColorStateList) 24103 */ 24104 @RemotableViewMethod setBackgroundTintList(@ullable ColorStateList tint)24105 public void setBackgroundTintList(@Nullable ColorStateList tint) { 24106 if (mBackgroundTint == null) { 24107 mBackgroundTint = new TintInfo(); 24108 } 24109 mBackgroundTint.mTintList = tint; 24110 mBackgroundTint.mHasTintList = true; 24111 24112 applyBackgroundTint(); 24113 } 24114 24115 /** 24116 * Return the tint applied to the background drawable, if specified. 24117 * 24118 * @return the tint applied to the background drawable 24119 * @attr ref android.R.styleable#View_backgroundTint 24120 * @see #setBackgroundTintList(ColorStateList) 24121 */ 24122 @InspectableProperty(name = "backgroundTint") 24123 @Nullable getBackgroundTintList()24124 public ColorStateList getBackgroundTintList() { 24125 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 24126 } 24127 24128 /** 24129 * Specifies the blending mode used to apply the tint specified by 24130 * {@link #setBackgroundTintList(ColorStateList)}} to the background 24131 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 24132 * 24133 * @param tintMode the blending mode used to apply the tint, may be 24134 * {@code null} to clear tint 24135 * @attr ref android.R.styleable#View_backgroundTintMode 24136 * @see #getBackgroundTintMode() 24137 * @see Drawable#setTintMode(PorterDuff.Mode) 24138 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)24139 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 24140 BlendMode mode = null; 24141 if (tintMode != null) { 24142 mode = BlendMode.fromValue(tintMode.nativeInt); 24143 } 24144 24145 setBackgroundTintBlendMode(mode); 24146 } 24147 24148 /** 24149 * Specifies the blending mode used to apply the tint specified by 24150 * {@link #setBackgroundTintList(ColorStateList)}} to the background 24151 * drawable. The default mode is {@link BlendMode#SRC_IN}. 24152 * 24153 * @param blendMode the blending mode used to apply the tint, may be 24154 * {@code null} to clear tint 24155 * @attr ref android.R.styleable#View_backgroundTintMode 24156 * @see #getBackgroundTintMode() 24157 * @see Drawable#setTintBlendMode(BlendMode) 24158 */ 24159 @RemotableViewMethod setBackgroundTintBlendMode(@ullable BlendMode blendMode)24160 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 24161 if (mBackgroundTint == null) { 24162 mBackgroundTint = new TintInfo(); 24163 } 24164 24165 mBackgroundTint.mBlendMode = blendMode; 24166 mBackgroundTint.mHasTintMode = true; 24167 24168 applyBackgroundTint(); 24169 } 24170 24171 /** 24172 * Return the blending mode used to apply the tint to the background 24173 * drawable, if specified. 24174 * 24175 * @return the blending mode used to apply the tint to the background 24176 * drawable 24177 * @attr ref android.R.styleable#View_backgroundTintMode 24178 * @see #setBackgroundTintBlendMode(BlendMode) 24179 * 24180 */ 24181 @Nullable 24182 @InspectableProperty getBackgroundTintMode()24183 public PorterDuff.Mode getBackgroundTintMode() { 24184 PorterDuff.Mode porterDuffMode; 24185 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 24186 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 24187 } else { 24188 porterDuffMode = null; 24189 } 24190 return porterDuffMode; 24191 } 24192 24193 /** 24194 * Return the blending mode used to apply the tint to the background 24195 * drawable, if specified. 24196 * 24197 * @return the blending mode used to apply the tint to the background 24198 * drawable, null if no blend has previously been configured 24199 * @attr ref android.R.styleable#View_backgroundTintMode 24200 * @see #setBackgroundTintBlendMode(BlendMode) 24201 */ getBackgroundTintBlendMode()24202 public @Nullable BlendMode getBackgroundTintBlendMode() { 24203 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 24204 } 24205 applyBackgroundTint()24206 private void applyBackgroundTint() { 24207 if (mBackground != null && mBackgroundTint != null) { 24208 final TintInfo tintInfo = mBackgroundTint; 24209 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 24210 mBackground = mBackground.mutate(); 24211 24212 if (tintInfo.mHasTintList) { 24213 mBackground.setTintList(tintInfo.mTintList); 24214 } 24215 24216 if (tintInfo.mHasTintMode) { 24217 mBackground.setTintBlendMode(tintInfo.mBlendMode); 24218 } 24219 24220 // The drawable (or one of its children) may not have been 24221 // stateful before applying the tint, so let's try again. 24222 if (mBackground.isStateful()) { 24223 mBackground.setState(getDrawableState()); 24224 } 24225 } 24226 } 24227 } 24228 24229 /** 24230 * Returns the drawable used as the foreground of this View. The 24231 * foreground drawable, if non-null, is always drawn on top of the view's content. 24232 * 24233 * @return a Drawable or null if no foreground was set 24234 * 24235 * @see #onDrawForeground(Canvas) 24236 */ 24237 @InspectableProperty getForeground()24238 public Drawable getForeground() { 24239 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24240 } 24241 24242 /** 24243 * Supply a Drawable that is to be rendered on top of all of the content in the view. 24244 * 24245 * @param foreground the Drawable to be drawn on top of the children 24246 * 24247 * @attr ref android.R.styleable#View_foreground 24248 */ setForeground(Drawable foreground)24249 public void setForeground(Drawable foreground) { 24250 if (mForegroundInfo == null) { 24251 if (foreground == null) { 24252 // Nothing to do. 24253 return; 24254 } 24255 mForegroundInfo = new ForegroundInfo(); 24256 } 24257 24258 if (foreground == mForegroundInfo.mDrawable) { 24259 // Nothing to do 24260 return; 24261 } 24262 24263 if (mForegroundInfo.mDrawable != null) { 24264 if (isAttachedToWindow()) { 24265 mForegroundInfo.mDrawable.setVisible(false, false); 24266 } 24267 mForegroundInfo.mDrawable.setCallback(null); 24268 unscheduleDrawable(mForegroundInfo.mDrawable); 24269 } 24270 24271 mForegroundInfo.mDrawable = foreground; 24272 mForegroundInfo.mBoundsChanged = true; 24273 if (foreground != null) { 24274 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24275 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24276 } 24277 foreground.setLayoutDirection(getLayoutDirection()); 24278 if (foreground.isStateful()) { 24279 foreground.setState(getDrawableState()); 24280 } 24281 applyForegroundTint(); 24282 if (isAttachedToWindow()) { 24283 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24284 } 24285 // Set callback last, since the view may still be initializing. 24286 foreground.setCallback(this); 24287 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 24288 && (mDefaultFocusHighlight == null)) { 24289 mPrivateFlags |= PFLAG_SKIP_DRAW; 24290 } 24291 requestLayout(); 24292 invalidate(); 24293 } 24294 24295 /** 24296 * Magic bit used to support features of framework-internal window decor implementation details. 24297 * This used to live exclusively in FrameLayout. 24298 * 24299 * @return true if the foreground should draw inside the padding region or false 24300 * if it should draw inset by the view's padding 24301 * @hide internal use only; only used by FrameLayout and internal screen layouts. 24302 */ isForegroundInsidePadding()24303 public boolean isForegroundInsidePadding() { 24304 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 24305 } 24306 24307 /** 24308 * Describes how the foreground is positioned. 24309 * 24310 * @return foreground gravity. 24311 * 24312 * @see #setForegroundGravity(int) 24313 * 24314 * @attr ref android.R.styleable#View_foregroundGravity 24315 */ 24316 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()24317 public int getForegroundGravity() { 24318 return mForegroundInfo != null ? mForegroundInfo.mGravity 24319 : Gravity.START | Gravity.TOP; 24320 } 24321 24322 /** 24323 * Describes how the foreground is positioned. Defaults to START and TOP. 24324 * 24325 * @param gravity see {@link android.view.Gravity} 24326 * 24327 * @see #getForegroundGravity() 24328 * 24329 * @attr ref android.R.styleable#View_foregroundGravity 24330 */ setForegroundGravity(int gravity)24331 public void setForegroundGravity(int gravity) { 24332 if (mForegroundInfo == null) { 24333 mForegroundInfo = new ForegroundInfo(); 24334 } 24335 24336 if (mForegroundInfo.mGravity != gravity) { 24337 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 24338 gravity |= Gravity.START; 24339 } 24340 24341 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 24342 gravity |= Gravity.TOP; 24343 } 24344 24345 mForegroundInfo.mGravity = gravity; 24346 requestLayout(); 24347 } 24348 } 24349 24350 /** 24351 * Applies a tint to the foreground drawable. Does not modify the current tint 24352 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 24353 * <p> 24354 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 24355 * mutate the drawable and apply the specified tint and tint mode using 24356 * {@link Drawable#setTintList(ColorStateList)}. 24357 * 24358 * @param tint the tint to apply, may be {@code null} to clear tint 24359 * 24360 * @attr ref android.R.styleable#View_foregroundTint 24361 * @see #getForegroundTintList() 24362 * @see Drawable#setTintList(ColorStateList) 24363 */ 24364 @RemotableViewMethod setForegroundTintList(@ullable ColorStateList tint)24365 public void setForegroundTintList(@Nullable ColorStateList tint) { 24366 if (mForegroundInfo == null) { 24367 mForegroundInfo = new ForegroundInfo(); 24368 } 24369 if (mForegroundInfo.mTintInfo == null) { 24370 mForegroundInfo.mTintInfo = new TintInfo(); 24371 } 24372 mForegroundInfo.mTintInfo.mTintList = tint; 24373 mForegroundInfo.mTintInfo.mHasTintList = true; 24374 24375 applyForegroundTint(); 24376 } 24377 24378 /** 24379 * Return the tint applied to the foreground drawable, if specified. 24380 * 24381 * @return the tint applied to the foreground drawable 24382 * @attr ref android.R.styleable#View_foregroundTint 24383 * @see #setForegroundTintList(ColorStateList) 24384 */ 24385 @InspectableProperty(name = "foregroundTint") 24386 @Nullable getForegroundTintList()24387 public ColorStateList getForegroundTintList() { 24388 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24389 ? mForegroundInfo.mTintInfo.mTintList : null; 24390 } 24391 24392 /** 24393 * Specifies the blending mode used to apply the tint specified by 24394 * {@link #setForegroundTintList(ColorStateList)}} to the background 24395 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 24396 * 24397 * @param tintMode the blending mode used to apply the tint, may be 24398 * {@code null} to clear tint 24399 * @attr ref android.R.styleable#View_foregroundTintMode 24400 * @see #getForegroundTintMode() 24401 * @see Drawable#setTintMode(PorterDuff.Mode) 24402 * 24403 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)24404 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 24405 BlendMode mode = null; 24406 if (tintMode != null) { 24407 mode = BlendMode.fromValue(tintMode.nativeInt); 24408 } 24409 setForegroundTintBlendMode(mode); 24410 } 24411 24412 /** 24413 * Specifies the blending mode used to apply the tint specified by 24414 * {@link #setForegroundTintList(ColorStateList)}} to the background 24415 * drawable. The default mode is {@link BlendMode#SRC_IN}. 24416 * 24417 * @param blendMode the blending mode used to apply the tint, may be 24418 * {@code null} to clear tint 24419 * @attr ref android.R.styleable#View_foregroundTintMode 24420 * @see #getForegroundTintMode() 24421 * @see Drawable#setTintBlendMode(BlendMode) 24422 */ 24423 @RemotableViewMethod setForegroundTintBlendMode(@ullable BlendMode blendMode)24424 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 24425 if (mForegroundInfo == null) { 24426 mForegroundInfo = new ForegroundInfo(); 24427 } 24428 if (mForegroundInfo.mTintInfo == null) { 24429 mForegroundInfo.mTintInfo = new TintInfo(); 24430 } 24431 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 24432 mForegroundInfo.mTintInfo.mHasTintMode = true; 24433 24434 applyForegroundTint(); 24435 } 24436 24437 /** 24438 * Return the blending mode used to apply the tint to the foreground 24439 * drawable, if specified. 24440 * 24441 * @return the blending mode used to apply the tint to the foreground 24442 * drawable 24443 * @attr ref android.R.styleable#View_foregroundTintMode 24444 * @see #setForegroundTintMode(PorterDuff.Mode) 24445 */ 24446 @InspectableProperty 24447 @Nullable getForegroundTintMode()24448 public PorterDuff.Mode getForegroundTintMode() { 24449 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24450 ? mForegroundInfo.mTintInfo.mBlendMode : null; 24451 if (blendMode != null) { 24452 return BlendMode.blendModeToPorterDuffMode(blendMode); 24453 } else { 24454 return null; 24455 } 24456 } 24457 24458 /** 24459 * Return the blending mode used to apply the tint to the foreground 24460 * drawable, if specified. 24461 * 24462 * @return the blending mode used to apply the tint to the foreground 24463 * drawable 24464 * @attr ref android.R.styleable#View_foregroundTintMode 24465 * @see #setForegroundTintBlendMode(BlendMode) 24466 * 24467 */ getForegroundTintBlendMode()24468 public @Nullable BlendMode getForegroundTintBlendMode() { 24469 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24470 ? mForegroundInfo.mTintInfo.mBlendMode : null; 24471 } 24472 applyForegroundTint()24473 private void applyForegroundTint() { 24474 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 24475 && mForegroundInfo.mTintInfo != null) { 24476 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 24477 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 24478 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 24479 24480 if (tintInfo.mHasTintList) { 24481 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 24482 } 24483 24484 if (tintInfo.mHasTintMode) { 24485 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 24486 } 24487 24488 // The drawable (or one of its children) may not have been 24489 // stateful before applying the tint, so let's try again. 24490 if (mForegroundInfo.mDrawable.isStateful()) { 24491 mForegroundInfo.mDrawable.setState(getDrawableState()); 24492 } 24493 } 24494 } 24495 } 24496 24497 /** 24498 * Get the drawable to be overlayed when a view is autofilled 24499 * 24500 * @return The drawable 24501 * 24502 * @throws IllegalStateException if the drawable could not be found. 24503 */ getAutofilledDrawable()24504 @Nullable private Drawable getAutofilledDrawable() { 24505 if (mAttachInfo == null) { 24506 return null; 24507 } 24508 // Lazily load the isAutofilled drawable. 24509 if (mAttachInfo.mAutofilledDrawable == null) { 24510 Context rootContext = getRootView().getContext(); 24511 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 24512 int attributeResourceId = a.getResourceId(0, 0); 24513 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 24514 a.recycle(); 24515 } 24516 24517 return mAttachInfo.mAutofilledDrawable; 24518 } 24519 24520 /** 24521 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 24522 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 24523 * 24524 * @param canvas The canvas to draw on 24525 */ drawAutofilledHighlight(@onNull Canvas canvas)24526 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 24527 if (isAutofilled() && !hideAutofillHighlight()) { 24528 Drawable autofilledHighlight = getAutofilledDrawable(); 24529 24530 if (autofilledHighlight != null) { 24531 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 24532 autofilledHighlight.draw(canvas); 24533 } 24534 } 24535 } 24536 24537 /** 24538 * Draw any foreground content for this view. 24539 * 24540 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 24541 * drawable or other view-specific decorations. The foreground is drawn on top of the 24542 * primary view content.</p> 24543 * 24544 * @param canvas canvas to draw into 24545 */ onDrawForeground(Canvas canvas)24546 public void onDrawForeground(Canvas canvas) { 24547 onDrawScrollIndicators(canvas); 24548 onDrawScrollBars(canvas); 24549 24550 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24551 if (foreground != null) { 24552 if (mForegroundInfo.mBoundsChanged) { 24553 mForegroundInfo.mBoundsChanged = false; 24554 final Rect selfBounds = mForegroundInfo.mSelfBounds; 24555 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 24556 24557 if (mForegroundInfo.mInsidePadding) { 24558 selfBounds.set(0, 0, getWidth(), getHeight()); 24559 } else { 24560 selfBounds.set(getPaddingLeft(), getPaddingTop(), 24561 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 24562 } 24563 24564 final int ld = getLayoutDirection(); 24565 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 24566 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 24567 foreground.setBounds(overlayBounds); 24568 } 24569 24570 foreground.draw(canvas); 24571 } 24572 } 24573 24574 /** 24575 * Sets the padding. The view may add on the space required to display 24576 * the scrollbars, depending on the style and visibility of the scrollbars. 24577 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 24578 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 24579 * from the values set in this call. 24580 * 24581 * @attr ref android.R.styleable#View_padding 24582 * @attr ref android.R.styleable#View_paddingBottom 24583 * @attr ref android.R.styleable#View_paddingLeft 24584 * @attr ref android.R.styleable#View_paddingRight 24585 * @attr ref android.R.styleable#View_paddingTop 24586 * @param left the left padding in pixels 24587 * @param top the top padding in pixels 24588 * @param right the right padding in pixels 24589 * @param bottom the bottom padding in pixels 24590 */ setPadding(int left, int top, int right, int bottom)24591 public void setPadding(int left, int top, int right, int bottom) { 24592 resetResolvedPaddingInternal(); 24593 24594 mUserPaddingStart = UNDEFINED_PADDING; 24595 mUserPaddingEnd = UNDEFINED_PADDING; 24596 24597 mUserPaddingLeftInitial = left; 24598 mUserPaddingRightInitial = right; 24599 24600 mLeftPaddingDefined = true; 24601 mRightPaddingDefined = true; 24602 24603 internalSetPadding(left, top, right, bottom); 24604 } 24605 24606 /** 24607 * @hide 24608 */ 24609 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)24610 protected void internalSetPadding(int left, int top, int right, int bottom) { 24611 mUserPaddingLeft = left; 24612 mUserPaddingRight = right; 24613 mUserPaddingBottom = bottom; 24614 24615 final int viewFlags = mViewFlags; 24616 boolean changed = false; 24617 24618 // Common case is there are no scroll bars. 24619 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 24620 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 24621 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 24622 ? 0 : getVerticalScrollbarWidth(); 24623 switch (mVerticalScrollbarPosition) { 24624 case SCROLLBAR_POSITION_DEFAULT: 24625 if (isLayoutRtl()) { 24626 left += offset; 24627 } else { 24628 right += offset; 24629 } 24630 break; 24631 case SCROLLBAR_POSITION_RIGHT: 24632 right += offset; 24633 break; 24634 case SCROLLBAR_POSITION_LEFT: 24635 left += offset; 24636 break; 24637 } 24638 } 24639 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 24640 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 24641 ? 0 : getHorizontalScrollbarHeight(); 24642 } 24643 } 24644 24645 if (mPaddingLeft != left) { 24646 changed = true; 24647 mPaddingLeft = left; 24648 } 24649 if (mPaddingTop != top) { 24650 changed = true; 24651 mPaddingTop = top; 24652 } 24653 if (mPaddingRight != right) { 24654 changed = true; 24655 mPaddingRight = right; 24656 } 24657 if (mPaddingBottom != bottom) { 24658 changed = true; 24659 mPaddingBottom = bottom; 24660 } 24661 24662 if (changed) { 24663 requestLayout(); 24664 invalidateOutline(); 24665 } 24666 } 24667 24668 /** 24669 * Sets the relative padding. The view may add on the space required to display 24670 * the scrollbars, depending on the style and visibility of the scrollbars. 24671 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 24672 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 24673 * from the values set in this call. 24674 * 24675 * @attr ref android.R.styleable#View_padding 24676 * @attr ref android.R.styleable#View_paddingBottom 24677 * @attr ref android.R.styleable#View_paddingStart 24678 * @attr ref android.R.styleable#View_paddingEnd 24679 * @attr ref android.R.styleable#View_paddingTop 24680 * @param start the start padding in pixels 24681 * @param top the top padding in pixels 24682 * @param end the end padding in pixels 24683 * @param bottom the bottom padding in pixels 24684 */ setPaddingRelative(int start, int top, int end, int bottom)24685 public void setPaddingRelative(int start, int top, int end, int bottom) { 24686 resetResolvedPaddingInternal(); 24687 24688 mUserPaddingStart = start; 24689 mUserPaddingEnd = end; 24690 mLeftPaddingDefined = true; 24691 mRightPaddingDefined = true; 24692 24693 switch(getLayoutDirection()) { 24694 case LAYOUT_DIRECTION_RTL: 24695 mUserPaddingLeftInitial = end; 24696 mUserPaddingRightInitial = start; 24697 internalSetPadding(end, top, start, bottom); 24698 break; 24699 case LAYOUT_DIRECTION_LTR: 24700 default: 24701 mUserPaddingLeftInitial = start; 24702 mUserPaddingRightInitial = end; 24703 internalSetPadding(start, top, end, bottom); 24704 } 24705 } 24706 24707 /** 24708 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 24709 * resource ID of the source layout. 24710 * 24711 * @return The layout resource id if this view was inflated from XML, otherwise 24712 * {@link Resources#ID_NULL}. 24713 */ 24714 @LayoutRes getSourceLayoutResId()24715 public int getSourceLayoutResId() { 24716 return mSourceLayoutId; 24717 } 24718 24719 /** 24720 * Returns the top padding of this view. 24721 * 24722 * @return the top padding in pixels 24723 */ 24724 @InspectableProperty getPaddingTop()24725 public int getPaddingTop() { 24726 return mPaddingTop; 24727 } 24728 24729 /** 24730 * Returns the bottom padding of this view. If there are inset and enabled 24731 * scrollbars, this value may include the space required to display the 24732 * scrollbars as well. 24733 * 24734 * @return the bottom padding in pixels 24735 */ 24736 @InspectableProperty getPaddingBottom()24737 public int getPaddingBottom() { 24738 return mPaddingBottom; 24739 } 24740 24741 /** 24742 * Returns the left padding of this view. If there are inset and enabled 24743 * scrollbars, this value may include the space required to display the 24744 * scrollbars as well. 24745 * 24746 * @return the left padding in pixels 24747 */ 24748 @InspectableProperty getPaddingLeft()24749 public int getPaddingLeft() { 24750 if (!isPaddingResolved()) { 24751 resolvePadding(); 24752 } 24753 return mPaddingLeft; 24754 } 24755 24756 /** 24757 * Returns the start padding of this view depending on its resolved layout direction. 24758 * If there are inset and enabled scrollbars, this value may include the space 24759 * required to display the scrollbars as well. 24760 * 24761 * @return the start padding in pixels 24762 */ getPaddingStart()24763 public int getPaddingStart() { 24764 if (!isPaddingResolved()) { 24765 resolvePadding(); 24766 } 24767 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24768 mPaddingRight : mPaddingLeft; 24769 } 24770 24771 /** 24772 * Returns the right padding of this view. If there are inset and enabled 24773 * scrollbars, this value may include the space required to display the 24774 * scrollbars as well. 24775 * 24776 * @return the right padding in pixels 24777 */ 24778 @InspectableProperty getPaddingRight()24779 public int getPaddingRight() { 24780 if (!isPaddingResolved()) { 24781 resolvePadding(); 24782 } 24783 return mPaddingRight; 24784 } 24785 24786 /** 24787 * Returns the end padding of this view depending on its resolved layout direction. 24788 * If there are inset and enabled scrollbars, this value may include the space 24789 * required to display the scrollbars as well. 24790 * 24791 * @return the end padding in pixels 24792 */ getPaddingEnd()24793 public int getPaddingEnd() { 24794 if (!isPaddingResolved()) { 24795 resolvePadding(); 24796 } 24797 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24798 mPaddingLeft : mPaddingRight; 24799 } 24800 24801 /** 24802 * Return if the padding has been set through relative values 24803 * {@link #setPaddingRelative(int, int, int, int)} or through 24804 * @attr ref android.R.styleable#View_paddingStart or 24805 * @attr ref android.R.styleable#View_paddingEnd 24806 * 24807 * @return true if the padding is relative or false if it is not. 24808 */ isPaddingRelative()24809 public boolean isPaddingRelative() { 24810 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 24811 } 24812 computeOpticalInsets()24813 Insets computeOpticalInsets() { 24814 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 24815 } 24816 24817 /** 24818 * @hide 24819 */ 24820 @UnsupportedAppUsage resetPaddingToInitialValues()24821 public void resetPaddingToInitialValues() { 24822 if (isRtlCompatibilityMode()) { 24823 mPaddingLeft = mUserPaddingLeftInitial; 24824 mPaddingRight = mUserPaddingRightInitial; 24825 return; 24826 } 24827 if (isLayoutRtl()) { 24828 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 24829 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 24830 } else { 24831 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 24832 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 24833 } 24834 } 24835 24836 /** 24837 * @hide 24838 */ getOpticalInsets()24839 public Insets getOpticalInsets() { 24840 if (mLayoutInsets == null) { 24841 mLayoutInsets = computeOpticalInsets(); 24842 } 24843 return mLayoutInsets; 24844 } 24845 24846 /** 24847 * Set this view's optical insets. 24848 * 24849 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 24850 * property. Views that compute their own optical insets should call it as part of measurement. 24851 * This method does not request layout. If you are setting optical insets outside of 24852 * measure/layout itself you will want to call requestLayout() yourself. 24853 * </p> 24854 * @hide 24855 */ setOpticalInsets(Insets insets)24856 public void setOpticalInsets(Insets insets) { 24857 mLayoutInsets = insets; 24858 } 24859 24860 /** 24861 * Changes the selection state of this view. A view can be selected or not. 24862 * Note that selection is not the same as focus. Views are typically 24863 * selected in the context of an AdapterView like ListView or GridView; 24864 * the selected view is the view that is highlighted. 24865 * 24866 * @param selected true if the view must be selected, false otherwise 24867 */ setSelected(boolean selected)24868 public void setSelected(boolean selected) { 24869 //noinspection DoubleNegation 24870 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 24871 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 24872 if (!selected) resetPressedState(); 24873 invalidate(true); 24874 refreshDrawableState(); 24875 dispatchSetSelected(selected); 24876 if (selected) { 24877 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 24878 } else { 24879 notifyViewAccessibilityStateChangedIfNeeded( 24880 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 24881 } 24882 } 24883 } 24884 24885 /** 24886 * Dispatch setSelected to all of this View's children. 24887 * 24888 * @see #setSelected(boolean) 24889 * 24890 * @param selected The new selected state 24891 */ dispatchSetSelected(boolean selected)24892 protected void dispatchSetSelected(boolean selected) { 24893 } 24894 24895 /** 24896 * Indicates the selection state of this view. 24897 * 24898 * @return true if the view is selected, false otherwise 24899 */ 24900 @ViewDebug.ExportedProperty 24901 @InspectableProperty(hasAttributeId = false) isSelected()24902 public boolean isSelected() { 24903 return (mPrivateFlags & PFLAG_SELECTED) != 0; 24904 } 24905 24906 /** 24907 * Changes the activated state of this view. A view can be activated or not. 24908 * Note that activation is not the same as selection. Selection is 24909 * a transient property, representing the view (hierarchy) the user is 24910 * currently interacting with. Activation is a longer-term state that the 24911 * user can move views in and out of. For example, in a list view with 24912 * single or multiple selection enabled, the views in the current selection 24913 * set are activated. (Um, yeah, we are deeply sorry about the terminology 24914 * here.) The activated state is propagated down to children of the view it 24915 * is set on. 24916 * 24917 * @param activated true if the view must be activated, false otherwise 24918 */ setActivated(boolean activated)24919 public void setActivated(boolean activated) { 24920 //noinspection DoubleNegation 24921 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 24922 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 24923 invalidate(true); 24924 refreshDrawableState(); 24925 dispatchSetActivated(activated); 24926 } 24927 } 24928 24929 /** 24930 * Dispatch setActivated to all of this View's children. 24931 * 24932 * @see #setActivated(boolean) 24933 * 24934 * @param activated The new activated state 24935 */ dispatchSetActivated(boolean activated)24936 protected void dispatchSetActivated(boolean activated) { 24937 } 24938 24939 /** 24940 * Indicates the activation state of this view. 24941 * 24942 * @return true if the view is activated, false otherwise 24943 */ 24944 @ViewDebug.ExportedProperty 24945 @InspectableProperty(hasAttributeId = false) isActivated()24946 public boolean isActivated() { 24947 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 24948 } 24949 24950 /** 24951 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 24952 * observer can be used to get notifications when global events, like 24953 * layout, happen. 24954 * 24955 * The returned ViewTreeObserver observer is not guaranteed to remain 24956 * valid for the lifetime of this View. If the caller of this method keeps 24957 * a long-lived reference to ViewTreeObserver, it should always check for 24958 * the return value of {@link ViewTreeObserver#isAlive()}. 24959 * 24960 * @return The ViewTreeObserver for this view's hierarchy. 24961 */ getViewTreeObserver()24962 public ViewTreeObserver getViewTreeObserver() { 24963 if (mAttachInfo != null) { 24964 return mAttachInfo.mTreeObserver; 24965 } 24966 if (mFloatingTreeObserver == null) { 24967 mFloatingTreeObserver = new ViewTreeObserver(mContext); 24968 } 24969 return mFloatingTreeObserver; 24970 } 24971 24972 /** 24973 * <p>Finds the topmost view in the current view hierarchy.</p> 24974 * 24975 * @return the topmost view containing this view 24976 */ getRootView()24977 public View getRootView() { 24978 if (mAttachInfo != null) { 24979 final View v = mAttachInfo.mRootView; 24980 if (v != null) { 24981 return v; 24982 } 24983 } 24984 24985 View parent = this; 24986 24987 while (parent.mParent != null && parent.mParent instanceof View) { 24988 parent = (View) parent.mParent; 24989 } 24990 24991 return parent; 24992 } 24993 24994 /** 24995 * Transforms a motion event from view-local coordinates to on-screen 24996 * coordinates. 24997 * 24998 * @param ev the view-local motion event 24999 * @return false if the transformation could not be applied 25000 * @hide 25001 */ 25002 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toGlobalMotionEvent(MotionEvent ev)25003 public boolean toGlobalMotionEvent(MotionEvent ev) { 25004 final AttachInfo info = mAttachInfo; 25005 if (info == null) { 25006 return false; 25007 } 25008 25009 final Matrix m = info.mTmpMatrix; 25010 m.set(Matrix.IDENTITY_MATRIX); 25011 transformMatrixToGlobal(m); 25012 ev.transform(m); 25013 return true; 25014 } 25015 25016 /** 25017 * Transforms a motion event from on-screen coordinates to view-local 25018 * coordinates. 25019 * 25020 * @param ev the on-screen motion event 25021 * @return false if the transformation could not be applied 25022 * @hide 25023 */ 25024 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toLocalMotionEvent(MotionEvent ev)25025 public boolean toLocalMotionEvent(MotionEvent ev) { 25026 final AttachInfo info = mAttachInfo; 25027 if (info == null) { 25028 return false; 25029 } 25030 25031 final Matrix m = info.mTmpMatrix; 25032 m.set(Matrix.IDENTITY_MATRIX); 25033 transformMatrixToLocal(m); 25034 ev.transform(m); 25035 return true; 25036 } 25037 25038 /** 25039 * Modifies the input matrix such that it maps view-local coordinates to 25040 * on-screen coordinates. 25041 * 25042 * @param matrix input matrix to modify 25043 */ transformMatrixToGlobal(@onNull Matrix matrix)25044 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 25045 final ViewParent parent = mParent; 25046 if (parent instanceof View) { 25047 final View vp = (View) parent; 25048 vp.transformMatrixToGlobal(matrix); 25049 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 25050 } else if (parent instanceof ViewRootImpl) { 25051 final ViewRootImpl vr = (ViewRootImpl) parent; 25052 vr.transformMatrixToGlobal(matrix); 25053 matrix.preTranslate(0, -vr.mCurScrollY); 25054 } 25055 25056 matrix.preTranslate(mLeft, mTop); 25057 25058 if (!hasIdentityMatrix()) { 25059 matrix.preConcat(getMatrix()); 25060 } 25061 } 25062 25063 /** 25064 * Modifies the input matrix such that it maps on-screen coordinates to 25065 * view-local coordinates. 25066 * 25067 * @param matrix input matrix to modify 25068 */ transformMatrixToLocal(@onNull Matrix matrix)25069 public void transformMatrixToLocal(@NonNull Matrix matrix) { 25070 final ViewParent parent = mParent; 25071 if (parent instanceof View) { 25072 final View vp = (View) parent; 25073 vp.transformMatrixToLocal(matrix); 25074 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 25075 } else if (parent instanceof ViewRootImpl) { 25076 final ViewRootImpl vr = (ViewRootImpl) parent; 25077 vr.transformMatrixToLocal(matrix); 25078 matrix.postTranslate(0, vr.mCurScrollY); 25079 } 25080 25081 matrix.postTranslate(-mLeft, -mTop); 25082 25083 if (!hasIdentityMatrix()) { 25084 matrix.postConcat(getInverseMatrix()); 25085 } 25086 } 25087 25088 /** 25089 * @hide 25090 */ 25091 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 25092 @ViewDebug.IntToString(from = 0, to = "x"), 25093 @ViewDebug.IntToString(from = 1, to = "y") 25094 }) 25095 @UnsupportedAppUsage getLocationOnScreen()25096 public int[] getLocationOnScreen() { 25097 int[] location = new int[2]; 25098 getLocationOnScreen(location); 25099 return location; 25100 } 25101 25102 /** 25103 * <p>Computes the coordinates of this view on the screen. The argument 25104 * must be an array of two integers. After the method returns, the array 25105 * contains the x and y location in that order.</p> 25106 * 25107 * @param outLocation an array of two integers in which to hold the coordinates 25108 */ getLocationOnScreen(@ize2) int[] outLocation)25109 public void getLocationOnScreen(@Size(2) int[] outLocation) { 25110 getLocationInWindow(outLocation); 25111 25112 final AttachInfo info = mAttachInfo; 25113 if (info != null) { 25114 outLocation[0] += info.mWindowLeft; 25115 outLocation[1] += info.mWindowTop; 25116 } 25117 } 25118 25119 /** 25120 * <p>Computes the coordinates of this view in its window. The argument 25121 * must be an array of two integers. After the method returns, the array 25122 * contains the x and y location in that order.</p> 25123 * 25124 * @param outLocation an array of two integers in which to hold the coordinates 25125 */ getLocationInWindow(@ize2) int[] outLocation)25126 public void getLocationInWindow(@Size(2) int[] outLocation) { 25127 if (outLocation == null || outLocation.length < 2) { 25128 throw new IllegalArgumentException("outLocation must be an array of two integers"); 25129 } 25130 25131 outLocation[0] = 0; 25132 outLocation[1] = 0; 25133 25134 transformFromViewToWindowSpace(outLocation); 25135 } 25136 25137 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)25138 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 25139 if (inOutLocation == null || inOutLocation.length < 2) { 25140 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 25141 } 25142 25143 if (mAttachInfo == null) { 25144 // When the view is not attached to a window, this method does not make sense 25145 inOutLocation[0] = inOutLocation[1] = 0; 25146 return; 25147 } 25148 25149 float position[] = mAttachInfo.mTmpTransformLocation; 25150 position[0] = inOutLocation[0]; 25151 position[1] = inOutLocation[1]; 25152 25153 if (!hasIdentityMatrix()) { 25154 getMatrix().mapPoints(position); 25155 } 25156 25157 position[0] += mLeft; 25158 position[1] += mTop; 25159 25160 ViewParent viewParent = mParent; 25161 while (viewParent instanceof View) { 25162 final View view = (View) viewParent; 25163 25164 position[0] -= view.mScrollX; 25165 position[1] -= view.mScrollY; 25166 25167 if (!view.hasIdentityMatrix()) { 25168 view.getMatrix().mapPoints(position); 25169 } 25170 25171 position[0] += view.mLeft; 25172 position[1] += view.mTop; 25173 25174 viewParent = view.mParent; 25175 } 25176 25177 if (viewParent instanceof ViewRootImpl) { 25178 // *cough* 25179 final ViewRootImpl vr = (ViewRootImpl) viewParent; 25180 position[1] -= vr.mCurScrollY; 25181 } 25182 25183 inOutLocation[0] = Math.round(position[0]); 25184 inOutLocation[1] = Math.round(position[1]); 25185 } 25186 25187 /** 25188 * @param id the id of the view to be found 25189 * @return the view of the specified id, null if cannot be found 25190 * @hide 25191 */ findViewTraversal(@dRes int id)25192 protected <T extends View> T findViewTraversal(@IdRes int id) { 25193 if (id == mID) { 25194 return (T) this; 25195 } 25196 return null; 25197 } 25198 25199 /** 25200 * @param tag the tag of the view to be found 25201 * @return the view of specified tag, null if cannot be found 25202 * @hide 25203 */ findViewWithTagTraversal(Object tag)25204 protected <T extends View> T findViewWithTagTraversal(Object tag) { 25205 if (tag != null && tag.equals(mTag)) { 25206 return (T) this; 25207 } 25208 return null; 25209 } 25210 25211 /** 25212 * @param predicate The predicate to evaluate. 25213 * @param childToSkip If not null, ignores this child during the recursive traversal. 25214 * @return The first view that matches the predicate or null. 25215 * @hide 25216 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)25217 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 25218 View childToSkip) { 25219 if (predicate.test(this)) { 25220 return (T) this; 25221 } 25222 return null; 25223 } 25224 25225 /** 25226 * Finds the first descendant view with the given ID, the view itself if 25227 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 25228 * (< 0) or there is no matching view in the hierarchy. 25229 * <p> 25230 * <strong>Note:</strong> In most cases -- depending on compiler support -- 25231 * the resulting view is automatically cast to the target class type. If 25232 * the target class type is unconstrained, an explicit cast may be 25233 * necessary. 25234 * 25235 * @param id the ID to search for 25236 * @return a view with given ID if found, or {@code null} otherwise 25237 * @see View#requireViewById(int) 25238 */ 25239 @Nullable findViewById(@dRes int id)25240 public final <T extends View> T findViewById(@IdRes int id) { 25241 if (id == NO_ID) { 25242 return null; 25243 } 25244 return findViewTraversal(id); 25245 } 25246 25247 /** 25248 * Finds the first descendant view with the given ID, the view itself if the ID matches 25249 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 25250 * matching view in the hierarchy. 25251 * <p> 25252 * <strong>Note:</strong> In most cases -- depending on compiler support -- 25253 * the resulting view is automatically cast to the target class type. If 25254 * the target class type is unconstrained, an explicit cast may be 25255 * necessary. 25256 * 25257 * @param id the ID to search for 25258 * @return a view with given ID 25259 * @see View#findViewById(int) 25260 */ 25261 @NonNull requireViewById(@dRes int id)25262 public final <T extends View> T requireViewById(@IdRes int id) { 25263 T view = findViewById(id); 25264 if (view == null) { 25265 throw new IllegalArgumentException("ID does not reference a View inside this View"); 25266 } 25267 return view; 25268 } 25269 25270 /** 25271 * Performs the traversal to find a view by its unique and stable accessibility id. 25272 * 25273 * <strong>Note:</strong>This method does not stop at the root namespace 25274 * boundary since the user can touch the screen at an arbitrary location 25275 * potentially crossing the root namespace boundary which will send an 25276 * accessibility event to accessibility services and they should be able 25277 * to obtain the event source. Also accessibility ids are guaranteed to be 25278 * unique in the window. 25279 * 25280 * @param accessibilityId The accessibility id. 25281 * @return The found view. 25282 * @hide 25283 */ findViewByAccessibilityIdTraversal(int accessibilityId)25284 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 25285 if (getAccessibilityViewId() == accessibilityId) { 25286 return (T) this; 25287 } 25288 return null; 25289 } 25290 25291 /** 25292 * Performs the traversal to find a view by its autofill id. 25293 * 25294 * <strong>Note:</strong>This method does not stop at the root namespace 25295 * boundary. 25296 * 25297 * @param autofillId The autofill id. 25298 * @return The found view. 25299 * @hide 25300 */ findViewByAutofillIdTraversal(int autofillId)25301 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 25302 if (getAutofillViewId() == autofillId) { 25303 return (T) this; 25304 } 25305 return null; 25306 } 25307 25308 /** 25309 * Look for a child view with the given tag. If this view has the given 25310 * tag, return this view. 25311 * 25312 * @param tag The tag to search for, using "tag.equals(getTag())". 25313 * @return The View that has the given tag in the hierarchy or null 25314 */ findViewWithTag(Object tag)25315 public final <T extends View> T findViewWithTag(Object tag) { 25316 if (tag == null) { 25317 return null; 25318 } 25319 return findViewWithTagTraversal(tag); 25320 } 25321 25322 /** 25323 * Look for a child view that matches the specified predicate. 25324 * If this view matches the predicate, return this view. 25325 * 25326 * @param predicate The predicate to evaluate. 25327 * @return The first view that matches the predicate or null. 25328 * @hide 25329 */ findViewByPredicate(Predicate<View> predicate)25330 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 25331 return findViewByPredicateTraversal(predicate, null); 25332 } 25333 25334 /** 25335 * Look for a child view that matches the specified predicate, 25336 * starting with the specified view and its descendents and then 25337 * recusively searching the ancestors and siblings of that view 25338 * until this view is reached. 25339 * 25340 * This method is useful in cases where the predicate does not match 25341 * a single unique view (perhaps multiple views use the same id) 25342 * and we are trying to find the view that is "closest" in scope to the 25343 * starting view. 25344 * 25345 * @param start The view to start from. 25346 * @param predicate The predicate to evaluate. 25347 * @return The first view that matches the predicate or null. 25348 * @hide 25349 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)25350 public final <T extends View> T findViewByPredicateInsideOut( 25351 View start, Predicate<View> predicate) { 25352 View childToSkip = null; 25353 for (;;) { 25354 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 25355 if (view != null || start == this) { 25356 return view; 25357 } 25358 25359 ViewParent parent = start.getParent(); 25360 if (parent == null || !(parent instanceof View)) { 25361 return null; 25362 } 25363 25364 childToSkip = start; 25365 start = (View) parent; 25366 } 25367 } 25368 25369 /** 25370 * Sets the identifier for this view. The identifier does not have to be 25371 * unique in this view's hierarchy. The identifier should be a positive 25372 * number. 25373 * 25374 * @see #NO_ID 25375 * @see #getId() 25376 * @see #findViewById(int) 25377 * 25378 * @param id a number used to identify the view 25379 * 25380 * @attr ref android.R.styleable#View_id 25381 */ setId(@dRes int id)25382 public void setId(@IdRes int id) { 25383 mID = id; 25384 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 25385 mID = generateViewId(); 25386 } 25387 } 25388 25389 /** 25390 * {@hide} 25391 * 25392 * @param isRoot true if the view belongs to the root namespace, false 25393 * otherwise 25394 */ 25395 @UnsupportedAppUsage 25396 @TestApi setIsRootNamespace(boolean isRoot)25397 public void setIsRootNamespace(boolean isRoot) { 25398 if (isRoot) { 25399 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 25400 } else { 25401 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 25402 } 25403 } 25404 25405 /** 25406 * {@hide} 25407 * 25408 * @return true if the view belongs to the root namespace, false otherwise 25409 */ 25410 @UnsupportedAppUsage isRootNamespace()25411 public boolean isRootNamespace() { 25412 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 25413 } 25414 25415 /** 25416 * Returns this view's identifier. 25417 * 25418 * @return a positive integer used to identify the view or {@link #NO_ID} 25419 * if the view has no ID 25420 * 25421 * @see #setId(int) 25422 * @see #findViewById(int) 25423 * @attr ref android.R.styleable#View_id 25424 */ 25425 @IdRes 25426 @ViewDebug.CapturedViewProperty 25427 @InspectableProperty getId()25428 public int getId() { 25429 return mID; 25430 } 25431 25432 /** 25433 * Get the identifier used for this view by the drawing system. 25434 * 25435 * @see RenderNode#getUniqueId() 25436 * @return A long that uniquely identifies this view's drawing component 25437 */ getUniqueDrawingId()25438 public long getUniqueDrawingId() { 25439 return mRenderNode.getUniqueId(); 25440 } 25441 25442 /** 25443 * Returns this view's tag. 25444 * 25445 * @return the Object stored in this view as a tag, or {@code null} if not 25446 * set 25447 * 25448 * @see #setTag(Object) 25449 * @see #getTag(int) 25450 */ 25451 @ViewDebug.ExportedProperty 25452 @InspectableProperty getTag()25453 public Object getTag() { 25454 return mTag; 25455 } 25456 25457 /** 25458 * Sets the tag associated with this view. A tag can be used to mark 25459 * a view in its hierarchy and does not have to be unique within the 25460 * hierarchy. Tags can also be used to store data within a view without 25461 * resorting to another data structure. 25462 * 25463 * @param tag an Object to tag the view with 25464 * 25465 * @see #getTag() 25466 * @see #setTag(int, Object) 25467 */ setTag(final Object tag)25468 public void setTag(final Object tag) { 25469 mTag = tag; 25470 } 25471 25472 /** 25473 * Returns the tag associated with this view and the specified key. 25474 * 25475 * @param key The key identifying the tag 25476 * 25477 * @return the Object stored in this view as a tag, or {@code null} if not 25478 * set 25479 * 25480 * @see #setTag(int, Object) 25481 * @see #getTag() 25482 */ getTag(int key)25483 public Object getTag(int key) { 25484 if (mKeyedTags != null) return mKeyedTags.get(key); 25485 return null; 25486 } 25487 25488 /** 25489 * Sets a tag associated with this view and a key. A tag can be used 25490 * to mark a view in its hierarchy and does not have to be unique within 25491 * the hierarchy. Tags can also be used to store data within a view 25492 * without resorting to another data structure. 25493 * 25494 * The specified key should be an id declared in the resources of the 25495 * application to ensure it is unique (see the <a 25496 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 25497 * Keys identified as belonging to 25498 * the Android framework or not associated with any package will cause 25499 * an {@link IllegalArgumentException} to be thrown. 25500 * 25501 * @param key The key identifying the tag 25502 * @param tag An Object to tag the view with 25503 * 25504 * @throws IllegalArgumentException If they specified key is not valid 25505 * 25506 * @see #setTag(Object) 25507 * @see #getTag(int) 25508 */ setTag(int key, final Object tag)25509 public void setTag(int key, final Object tag) { 25510 // If the package id is 0x00 or 0x01, it's either an undefined package 25511 // or a framework id 25512 if ((key >>> 24) < 2) { 25513 throw new IllegalArgumentException("The key must be an application-specific " 25514 + "resource id."); 25515 } 25516 25517 setKeyedTag(key, tag); 25518 } 25519 25520 /** 25521 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 25522 * framework id. 25523 * 25524 * @hide 25525 */ 25526 @UnsupportedAppUsage setTagInternal(int key, Object tag)25527 public void setTagInternal(int key, Object tag) { 25528 if ((key >>> 24) != 0x1) { 25529 throw new IllegalArgumentException("The key must be a framework-specific " 25530 + "resource id."); 25531 } 25532 25533 setKeyedTag(key, tag); 25534 } 25535 setKeyedTag(int key, Object tag)25536 private void setKeyedTag(int key, Object tag) { 25537 if (mKeyedTags == null) { 25538 mKeyedTags = new SparseArray<Object>(2); 25539 } 25540 25541 mKeyedTags.put(key, tag); 25542 } 25543 25544 /** 25545 * Prints information about this view in the log output, with the tag 25546 * {@link #VIEW_LOG_TAG}. 25547 * 25548 * @hide 25549 */ 25550 @UnsupportedAppUsage debug()25551 public void debug() { 25552 debug(0); 25553 } 25554 25555 /** 25556 * Prints information about this view in the log output, with the tag 25557 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 25558 * indentation defined by the <code>depth</code>. 25559 * 25560 * @param depth the indentation level 25561 * 25562 * @hide 25563 */ 25564 @UnsupportedAppUsage debug(int depth)25565 protected void debug(int depth) { 25566 String output = debugIndent(depth - 1); 25567 25568 output += "+ " + this; 25569 int id = getId(); 25570 if (id != -1) { 25571 output += " (id=" + id + ")"; 25572 } 25573 Object tag = getTag(); 25574 if (tag != null) { 25575 output += " (tag=" + tag + ")"; 25576 } 25577 Log.d(VIEW_LOG_TAG, output); 25578 25579 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 25580 output = debugIndent(depth) + " FOCUSED"; 25581 Log.d(VIEW_LOG_TAG, output); 25582 } 25583 25584 output = debugIndent(depth); 25585 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 25586 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 25587 + "} "; 25588 Log.d(VIEW_LOG_TAG, output); 25589 25590 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 25591 || mPaddingBottom != 0) { 25592 output = debugIndent(depth); 25593 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 25594 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 25595 Log.d(VIEW_LOG_TAG, output); 25596 } 25597 25598 output = debugIndent(depth); 25599 output += "mMeasureWidth=" + mMeasuredWidth + 25600 " mMeasureHeight=" + mMeasuredHeight; 25601 Log.d(VIEW_LOG_TAG, output); 25602 25603 output = debugIndent(depth); 25604 if (mLayoutParams == null) { 25605 output += "BAD! no layout params"; 25606 } else { 25607 output = mLayoutParams.debug(output); 25608 } 25609 Log.d(VIEW_LOG_TAG, output); 25610 25611 output = debugIndent(depth); 25612 output += "flags={"; 25613 output += View.printFlags(mViewFlags); 25614 output += "}"; 25615 Log.d(VIEW_LOG_TAG, output); 25616 25617 output = debugIndent(depth); 25618 output += "privateFlags={"; 25619 output += View.printPrivateFlags(mPrivateFlags); 25620 output += "}"; 25621 Log.d(VIEW_LOG_TAG, output); 25622 } 25623 25624 /** 25625 * Creates a string of whitespaces used for indentation. 25626 * 25627 * @param depth the indentation level 25628 * @return a String containing (depth * 2 + 3) * 2 white spaces 25629 * 25630 * @hide 25631 */ debugIndent(int depth)25632 protected static String debugIndent(int depth) { 25633 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 25634 for (int i = 0; i < (depth * 2) + 3; i++) { 25635 spaces.append(' ').append(' '); 25636 } 25637 return spaces.toString(); 25638 } 25639 25640 /** 25641 * <p>Return the offset of the widget's text baseline from the widget's top 25642 * boundary. If this widget does not support baseline alignment, this 25643 * method returns -1. </p> 25644 * 25645 * @return the offset of the baseline within the widget's bounds or -1 25646 * if baseline alignment is not supported 25647 */ 25648 @ViewDebug.ExportedProperty(category = "layout") 25649 @InspectableProperty getBaseline()25650 public int getBaseline() { 25651 return -1; 25652 } 25653 25654 /** 25655 * Returns whether the view hierarchy is currently undergoing a layout pass. This 25656 * information is useful to avoid situations such as calling {@link #requestLayout()} during 25657 * a layout pass. 25658 * 25659 * @return whether the view hierarchy is currently undergoing a layout pass 25660 */ isInLayout()25661 public boolean isInLayout() { 25662 ViewRootImpl viewRoot = getViewRootImpl(); 25663 return (viewRoot != null && viewRoot.isInLayout()); 25664 } 25665 25666 /** 25667 * Call this when something has changed which has invalidated the 25668 * layout of this view. This will schedule a layout pass of the view 25669 * tree. This should not be called while the view hierarchy is currently in a layout 25670 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 25671 * end of the current layout pass (and then layout will run again) or after the current 25672 * frame is drawn and the next layout occurs. 25673 * 25674 * <p>Subclasses which override this method should call the superclass method to 25675 * handle possible request-during-layout errors correctly.</p> 25676 */ 25677 @CallSuper requestLayout()25678 public void requestLayout() { 25679 if (mMeasureCache != null) mMeasureCache.clear(); 25680 25681 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 25682 // Only trigger request-during-layout logic if this is the view requesting it, 25683 // not the views in its parent hierarchy 25684 ViewRootImpl viewRoot = getViewRootImpl(); 25685 if (viewRoot != null && viewRoot.isInLayout()) { 25686 if (!viewRoot.requestLayoutDuringLayout(this)) { 25687 return; 25688 } 25689 } 25690 mAttachInfo.mViewRequestingLayout = this; 25691 } 25692 25693 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25694 mPrivateFlags |= PFLAG_INVALIDATED; 25695 25696 if (mParent != null && !mParent.isLayoutRequested()) { 25697 mParent.requestLayout(); 25698 } 25699 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 25700 mAttachInfo.mViewRequestingLayout = null; 25701 } 25702 } 25703 25704 /** 25705 * Forces this view to be laid out during the next layout pass. 25706 * This method does not call requestLayout() or forceLayout() 25707 * on the parent. 25708 */ forceLayout()25709 public void forceLayout() { 25710 if (mMeasureCache != null) mMeasureCache.clear(); 25711 25712 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25713 mPrivateFlags |= PFLAG_INVALIDATED; 25714 } 25715 25716 /** 25717 * <p> 25718 * This is called to find out how big a view should be. The parent 25719 * supplies constraint information in the width and height parameters. 25720 * </p> 25721 * 25722 * <p> 25723 * The actual measurement work of a view is performed in 25724 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 25725 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 25726 * </p> 25727 * 25728 * 25729 * @param widthMeasureSpec Horizontal space requirements as imposed by the 25730 * parent 25731 * @param heightMeasureSpec Vertical space requirements as imposed by the 25732 * parent 25733 * 25734 * @see #onMeasure(int, int) 25735 */ measure(int widthMeasureSpec, int heightMeasureSpec)25736 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 25737 boolean optical = isLayoutModeOptical(this); 25738 if (optical != isLayoutModeOptical(mParent)) { 25739 Insets insets = getOpticalInsets(); 25740 int oWidth = insets.left + insets.right; 25741 int oHeight = insets.top + insets.bottom; 25742 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 25743 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 25744 } 25745 25746 // Suppress sign extension for the low bytes 25747 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 25748 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 25749 25750 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 25751 25752 // Optimize layout by avoiding an extra EXACTLY pass when the view is 25753 // already measured as the correct size. In API 23 and below, this 25754 // extra pass is required to make LinearLayout re-distribute weight. 25755 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 25756 || heightMeasureSpec != mOldHeightMeasureSpec; 25757 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 25758 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 25759 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 25760 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 25761 final boolean needsLayout = specChanged 25762 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 25763 25764 if (forceLayout || needsLayout) { 25765 // first clears the measured dimension flag 25766 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 25767 25768 resolveRtlPropertiesIfNeeded(); 25769 25770 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 25771 if (cacheIndex < 0 || sIgnoreMeasureCache) { 25772 // measure ourselves, this should set the measured dimension flag back 25773 onMeasure(widthMeasureSpec, heightMeasureSpec); 25774 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25775 } else { 25776 long value = mMeasureCache.valueAt(cacheIndex); 25777 // Casting a long to int drops the high 32 bits, no mask needed 25778 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 25779 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25780 } 25781 25782 // flag not set, setMeasuredDimension() was not invoked, we raise 25783 // an exception to warn the developer 25784 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 25785 throw new IllegalStateException("View with id " + getId() + ": " 25786 + getClass().getName() + "#onMeasure() did not set the" 25787 + " measured dimension by calling" 25788 + " setMeasuredDimension()"); 25789 } 25790 25791 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 25792 } 25793 25794 mOldWidthMeasureSpec = widthMeasureSpec; 25795 mOldHeightMeasureSpec = heightMeasureSpec; 25796 25797 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 25798 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 25799 } 25800 25801 /** 25802 * <p> 25803 * Measure the view and its content to determine the measured width and the 25804 * measured height. This method is invoked by {@link #measure(int, int)} and 25805 * should be overridden by subclasses to provide accurate and efficient 25806 * measurement of their contents. 25807 * </p> 25808 * 25809 * <p> 25810 * <strong>CONTRACT:</strong> When overriding this method, you 25811 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 25812 * measured width and height of this view. Failure to do so will trigger an 25813 * <code>IllegalStateException</code>, thrown by 25814 * {@link #measure(int, int)}. Calling the superclass' 25815 * {@link #onMeasure(int, int)} is a valid use. 25816 * </p> 25817 * 25818 * <p> 25819 * The base class implementation of measure defaults to the background size, 25820 * unless a larger size is allowed by the MeasureSpec. Subclasses should 25821 * override {@link #onMeasure(int, int)} to provide better measurements of 25822 * their content. 25823 * </p> 25824 * 25825 * <p> 25826 * If this method is overridden, it is the subclass's responsibility to make 25827 * sure the measured height and width are at least the view's minimum height 25828 * and width ({@link #getSuggestedMinimumHeight()} and 25829 * {@link #getSuggestedMinimumWidth()}). 25830 * </p> 25831 * 25832 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 25833 * The requirements are encoded with 25834 * {@link android.view.View.MeasureSpec}. 25835 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 25836 * The requirements are encoded with 25837 * {@link android.view.View.MeasureSpec}. 25838 * 25839 * @see #getMeasuredWidth() 25840 * @see #getMeasuredHeight() 25841 * @see #setMeasuredDimension(int, int) 25842 * @see #getSuggestedMinimumHeight() 25843 * @see #getSuggestedMinimumWidth() 25844 * @see android.view.View.MeasureSpec#getMode(int) 25845 * @see android.view.View.MeasureSpec#getSize(int) 25846 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)25847 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 25848 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 25849 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 25850 } 25851 25852 /** 25853 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 25854 * measured width and measured height. Failing to do so will trigger an 25855 * exception at measurement time.</p> 25856 * 25857 * @param measuredWidth The measured width of this view. May be a complex 25858 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25859 * {@link #MEASURED_STATE_TOO_SMALL}. 25860 * @param measuredHeight The measured height of this view. May be a complex 25861 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25862 * {@link #MEASURED_STATE_TOO_SMALL}. 25863 */ setMeasuredDimension(int measuredWidth, int measuredHeight)25864 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 25865 boolean optical = isLayoutModeOptical(this); 25866 if (optical != isLayoutModeOptical(mParent)) { 25867 Insets insets = getOpticalInsets(); 25868 int opticalWidth = insets.left + insets.right; 25869 int opticalHeight = insets.top + insets.bottom; 25870 25871 measuredWidth += optical ? opticalWidth : -opticalWidth; 25872 measuredHeight += optical ? opticalHeight : -opticalHeight; 25873 } 25874 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 25875 } 25876 25877 /** 25878 * Sets the measured dimension without extra processing for things like optical bounds. 25879 * Useful for reapplying consistent values that have already been cooked with adjustments 25880 * for optical bounds, etc. such as those from the measurement cache. 25881 * 25882 * @param measuredWidth The measured width of this view. May be a complex 25883 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25884 * {@link #MEASURED_STATE_TOO_SMALL}. 25885 * @param measuredHeight The measured height of this view. May be a complex 25886 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25887 * {@link #MEASURED_STATE_TOO_SMALL}. 25888 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)25889 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 25890 mMeasuredWidth = measuredWidth; 25891 mMeasuredHeight = measuredHeight; 25892 25893 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 25894 } 25895 25896 /** 25897 * Merge two states as returned by {@link #getMeasuredState()}. 25898 * @param curState The current state as returned from a view or the result 25899 * of combining multiple views. 25900 * @param newState The new view state to combine. 25901 * @return Returns a new integer reflecting the combination of the two 25902 * states. 25903 */ combineMeasuredStates(int curState, int newState)25904 public static int combineMeasuredStates(int curState, int newState) { 25905 return curState | newState; 25906 } 25907 25908 /** 25909 * Version of {@link #resolveSizeAndState(int, int, int)} 25910 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 25911 */ resolveSize(int size, int measureSpec)25912 public static int resolveSize(int size, int measureSpec) { 25913 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 25914 } 25915 25916 /** 25917 * Utility to reconcile a desired size and state, with constraints imposed 25918 * by a MeasureSpec. Will take the desired size, unless a different size 25919 * is imposed by the constraints. The returned value is a compound integer, 25920 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 25921 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 25922 * resulting size is smaller than the size the view wants to be. 25923 * 25924 * @param size How big the view wants to be. 25925 * @param measureSpec Constraints imposed by the parent. 25926 * @param childMeasuredState Size information bit mask for the view's 25927 * children. 25928 * @return Size information bit mask as defined by 25929 * {@link #MEASURED_SIZE_MASK} and 25930 * {@link #MEASURED_STATE_TOO_SMALL}. 25931 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)25932 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 25933 final int specMode = MeasureSpec.getMode(measureSpec); 25934 final int specSize = MeasureSpec.getSize(measureSpec); 25935 final int result; 25936 switch (specMode) { 25937 case MeasureSpec.AT_MOST: 25938 if (specSize < size) { 25939 result = specSize | MEASURED_STATE_TOO_SMALL; 25940 } else { 25941 result = size; 25942 } 25943 break; 25944 case MeasureSpec.EXACTLY: 25945 result = specSize; 25946 break; 25947 case MeasureSpec.UNSPECIFIED: 25948 default: 25949 result = size; 25950 } 25951 return result | (childMeasuredState & MEASURED_STATE_MASK); 25952 } 25953 25954 /** 25955 * Utility to return a default size. Uses the supplied size if the 25956 * MeasureSpec imposed no constraints. Will get larger if allowed 25957 * by the MeasureSpec. 25958 * 25959 * @param size Default size for this view 25960 * @param measureSpec Constraints imposed by the parent 25961 * @return The size this view should be. 25962 */ getDefaultSize(int size, int measureSpec)25963 public static int getDefaultSize(int size, int measureSpec) { 25964 int result = size; 25965 int specMode = MeasureSpec.getMode(measureSpec); 25966 int specSize = MeasureSpec.getSize(measureSpec); 25967 25968 switch (specMode) { 25969 case MeasureSpec.UNSPECIFIED: 25970 result = size; 25971 break; 25972 case MeasureSpec.AT_MOST: 25973 case MeasureSpec.EXACTLY: 25974 result = specSize; 25975 break; 25976 } 25977 return result; 25978 } 25979 25980 /** 25981 * Returns the suggested minimum height that the view should use. This 25982 * returns the maximum of the view's minimum height 25983 * and the background's minimum height 25984 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 25985 * <p> 25986 * When being used in {@link #onMeasure(int, int)}, the caller should still 25987 * ensure the returned height is within the requirements of the parent. 25988 * 25989 * @return The suggested minimum height of the view. 25990 */ getSuggestedMinimumHeight()25991 protected int getSuggestedMinimumHeight() { 25992 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 25993 25994 } 25995 25996 /** 25997 * Returns the suggested minimum width that the view should use. This 25998 * returns the maximum of the view's minimum width 25999 * and the background's minimum width 26000 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 26001 * <p> 26002 * When being used in {@link #onMeasure(int, int)}, the caller should still 26003 * ensure the returned width is within the requirements of the parent. 26004 * 26005 * @return The suggested minimum width of the view. 26006 */ getSuggestedMinimumWidth()26007 protected int getSuggestedMinimumWidth() { 26008 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 26009 } 26010 26011 /** 26012 * Returns the minimum height of the view. 26013 * 26014 * @return the minimum height the view will try to be, in pixels 26015 * 26016 * @see #setMinimumHeight(int) 26017 * 26018 * @attr ref android.R.styleable#View_minHeight 26019 */ 26020 @InspectableProperty(name = "minHeight") getMinimumHeight()26021 public int getMinimumHeight() { 26022 return mMinHeight; 26023 } 26024 26025 /** 26026 * Sets the minimum height of the view. It is not guaranteed the view will 26027 * be able to achieve this minimum height (for example, if its parent layout 26028 * constrains it with less available height). 26029 * 26030 * @param minHeight The minimum height the view will try to be, in pixels 26031 * 26032 * @see #getMinimumHeight() 26033 * 26034 * @attr ref android.R.styleable#View_minHeight 26035 */ 26036 @RemotableViewMethod setMinimumHeight(int minHeight)26037 public void setMinimumHeight(int minHeight) { 26038 mMinHeight = minHeight; 26039 requestLayout(); 26040 } 26041 26042 /** 26043 * Returns the minimum width of the view. 26044 * 26045 * @return the minimum width the view will try to be, in pixels 26046 * 26047 * @see #setMinimumWidth(int) 26048 * 26049 * @attr ref android.R.styleable#View_minWidth 26050 */ 26051 @InspectableProperty(name = "minWidth") getMinimumWidth()26052 public int getMinimumWidth() { 26053 return mMinWidth; 26054 } 26055 26056 /** 26057 * Sets the minimum width of the view. It is not guaranteed the view will 26058 * be able to achieve this minimum width (for example, if its parent layout 26059 * constrains it with less available width). 26060 * 26061 * @param minWidth The minimum width the view will try to be, in pixels 26062 * 26063 * @see #getMinimumWidth() 26064 * 26065 * @attr ref android.R.styleable#View_minWidth 26066 */ 26067 @RemotableViewMethod setMinimumWidth(int minWidth)26068 public void setMinimumWidth(int minWidth) { 26069 mMinWidth = minWidth; 26070 requestLayout(); 26071 26072 } 26073 26074 /** 26075 * Get the animation currently associated with this view. 26076 * 26077 * @return The animation that is currently playing or 26078 * scheduled to play for this view. 26079 */ getAnimation()26080 public Animation getAnimation() { 26081 return mCurrentAnimation; 26082 } 26083 26084 /** 26085 * Start the specified animation now. 26086 * 26087 * @param animation the animation to start now 26088 */ startAnimation(Animation animation)26089 public void startAnimation(Animation animation) { 26090 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 26091 setAnimation(animation); 26092 invalidateParentCaches(); 26093 invalidate(true); 26094 } 26095 26096 /** 26097 * Cancels any animations for this view. 26098 */ clearAnimation()26099 public void clearAnimation() { 26100 if (mCurrentAnimation != null) { 26101 mCurrentAnimation.detach(); 26102 } 26103 mCurrentAnimation = null; 26104 invalidateParentIfNeeded(); 26105 } 26106 26107 /** 26108 * Sets the next animation to play for this view. 26109 * If you want the animation to play immediately, use 26110 * {@link #startAnimation(android.view.animation.Animation)} instead. 26111 * This method provides allows fine-grained 26112 * control over the start time and invalidation, but you 26113 * must make sure that 1) the animation has a start time set, and 26114 * 2) the view's parent (which controls animations on its children) 26115 * will be invalidated when the animation is supposed to 26116 * start. 26117 * 26118 * @param animation The next animation, or null. 26119 */ setAnimation(Animation animation)26120 public void setAnimation(Animation animation) { 26121 mCurrentAnimation = animation; 26122 26123 if (animation != null) { 26124 // If the screen is off assume the animation start time is now instead of 26125 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 26126 // would cause the animation to start when the screen turns back on 26127 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 26128 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 26129 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 26130 } 26131 animation.reset(); 26132 } 26133 } 26134 26135 /** 26136 * Invoked by a parent ViewGroup to notify the start of the animation 26137 * currently associated with this view. If you override this method, 26138 * always call super.onAnimationStart(); 26139 * 26140 * @see #setAnimation(android.view.animation.Animation) 26141 * @see #getAnimation() 26142 */ 26143 @CallSuper onAnimationStart()26144 protected void onAnimationStart() { 26145 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 26146 } 26147 26148 /** 26149 * Invoked by a parent ViewGroup to notify the end of the animation 26150 * currently associated with this view. If you override this method, 26151 * always call super.onAnimationEnd(); 26152 * 26153 * @see #setAnimation(android.view.animation.Animation) 26154 * @see #getAnimation() 26155 */ 26156 @CallSuper onAnimationEnd()26157 protected void onAnimationEnd() { 26158 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 26159 } 26160 26161 /** 26162 * Invoked if there is a Transform that involves alpha. Subclass that can 26163 * draw themselves with the specified alpha should return true, and then 26164 * respect that alpha when their onDraw() is called. If this returns false 26165 * then the view may be redirected to draw into an offscreen buffer to 26166 * fulfill the request, which will look fine, but may be slower than if the 26167 * subclass handles it internally. The default implementation returns false. 26168 * 26169 * @param alpha The alpha (0..255) to apply to the view's drawing 26170 * @return true if the view can draw with the specified alpha. 26171 */ onSetAlpha(int alpha)26172 protected boolean onSetAlpha(int alpha) { 26173 return false; 26174 } 26175 26176 /** 26177 * This is used by the ViewRoot to perform an optimization when 26178 * the view hierarchy contains one or several SurfaceView. 26179 * SurfaceView is always considered transparent, but its children are not, 26180 * therefore all View objects remove themselves from the global transparent 26181 * region (passed as a parameter to this function). 26182 * 26183 * @param region The transparent region for this ViewAncestor (window). 26184 * 26185 * @return Returns true if the effective visibility of the view at this 26186 * point is opaque, regardless of the transparent region; returns false 26187 * if it is possible for underlying windows to be seen behind the view. 26188 * 26189 */ gatherTransparentRegion(@ullable Region region)26190 public boolean gatherTransparentRegion(@Nullable Region region) { 26191 final AttachInfo attachInfo = mAttachInfo; 26192 if (region != null && attachInfo != null) { 26193 final int pflags = mPrivateFlags; 26194 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 26195 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 26196 // remove it from the transparent region. 26197 final int[] location = attachInfo.mTransparentLocation; 26198 getLocationInWindow(location); 26199 // When a view has Z value, then it will be better to leave some area below the view 26200 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 26201 // the bottom part needs more offset than the left, top and right parts due to the 26202 // spot light effects. 26203 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 26204 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 26205 location[0] + mRight - mLeft + shadowOffset, 26206 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 26207 } else { 26208 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 26209 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 26210 // the background drawable's non-transparent parts from this transparent region. 26211 applyDrawableToTransparentRegion(mBackground, region); 26212 } 26213 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 26214 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 26215 // Similarly, we remove the foreground drawable's non-transparent parts. 26216 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 26217 } 26218 if (mDefaultFocusHighlight != null 26219 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 26220 // Similarly, we remove the default focus highlight's non-transparent parts. 26221 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 26222 } 26223 } 26224 } 26225 return true; 26226 } 26227 26228 /** 26229 * Play a sound effect for this view. 26230 * 26231 * <p>The framework will play sound effects for some built in actions, such as 26232 * clicking, but you may wish to play these effects in your widget, 26233 * for instance, for internal navigation. 26234 * 26235 * <p>The sound effect will only be played if sound effects are enabled by the user, and 26236 * {@link #isSoundEffectsEnabled()} is true. 26237 * 26238 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}. 26239 */ playSoundEffect(@oundEffectConstants.SoundEffect int soundConstant)26240 public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { 26241 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 26242 return; 26243 } 26244 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 26245 } 26246 26247 /** 26248 * BZZZTT!!1! 26249 * 26250 * <p>Provide haptic feedback to the user for this view. 26251 * 26252 * <p>The framework will provide haptic feedback for some built in actions, 26253 * such as long presses, but you may wish to provide feedback for your 26254 * own widget. 26255 * 26256 * <p>The feedback will only be performed if 26257 * {@link #isHapticFeedbackEnabled()} is true. 26258 * 26259 * @param feedbackConstant One of the constants defined in 26260 * {@link HapticFeedbackConstants} 26261 */ performHapticFeedback(int feedbackConstant)26262 public boolean performHapticFeedback(int feedbackConstant) { 26263 return performHapticFeedback(feedbackConstant, 0); 26264 } 26265 26266 /** 26267 * BZZZTT!!1! 26268 * 26269 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 26270 * 26271 * @param feedbackConstant One of the constants defined in 26272 * {@link HapticFeedbackConstants} 26273 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 26274 */ performHapticFeedback(int feedbackConstant, int flags)26275 public boolean performHapticFeedback(int feedbackConstant, int flags) { 26276 if (mAttachInfo == null) { 26277 return false; 26278 } 26279 //noinspection SimplifiableIfStatement 26280 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 26281 && !isHapticFeedbackEnabled()) { 26282 return false; 26283 } 26284 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 26285 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 26286 } 26287 26288 /** 26289 * Request that the visibility of the status bar or other screen/window 26290 * decorations be changed. 26291 * 26292 * <p>This method is used to put the over device UI into temporary modes 26293 * where the user's attention is focused more on the application content, 26294 * by dimming or hiding surrounding system affordances. This is typically 26295 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 26296 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 26297 * to be placed behind the action bar (and with these flags other system 26298 * affordances) so that smooth transitions between hiding and showing them 26299 * can be done. 26300 * 26301 * <p>Two representative examples of the use of system UI visibility is 26302 * implementing a content browsing application (like a magazine reader) 26303 * and a video playing application. 26304 * 26305 * <p>The first code shows a typical implementation of a View in a content 26306 * browsing application. In this implementation, the application goes 26307 * into a content-oriented mode by hiding the status bar and action bar, 26308 * and putting the navigation elements into lights out mode. The user can 26309 * then interact with content while in this mode. Such an application should 26310 * provide an easy way for the user to toggle out of the mode (such as to 26311 * check information in the status bar or access notifications). In the 26312 * implementation here, this is done simply by tapping on the content. 26313 * 26314 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 26315 * content} 26316 * 26317 * <p>This second code sample shows a typical implementation of a View 26318 * in a video playing application. In this situation, while the video is 26319 * playing the application would like to go into a complete full-screen mode, 26320 * to use as much of the display as possible for the video. When in this state 26321 * the user can not interact with the application; the system intercepts 26322 * touching on the screen to pop the UI out of full screen mode. See 26323 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 26324 * 26325 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 26326 * content} 26327 * 26328 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26329 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 26330 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 26331 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 26332 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 26333 * 26334 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26335 * instead. 26336 */ 26337 @Deprecated setSystemUiVisibility(int visibility)26338 public void setSystemUiVisibility(int visibility) { 26339 if (visibility != mSystemUiVisibility) { 26340 mSystemUiVisibility = visibility; 26341 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 26342 mParent.recomputeViewAttributes(this); 26343 } 26344 } 26345 } 26346 26347 /** 26348 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 26349 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26350 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 26351 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 26352 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 26353 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 26354 * 26355 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26356 * instead. 26357 */ 26358 @Deprecated getSystemUiVisibility()26359 public int getSystemUiVisibility() { 26360 return mSystemUiVisibility; 26361 } 26362 26363 /** 26364 * Returns the current system UI visibility that is currently set for 26365 * the entire window. This is the combination of the 26366 * {@link #setSystemUiVisibility(int)} values supplied by all of the 26367 * views in the window. 26368 * 26369 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26370 * instead. 26371 */ 26372 @Deprecated getWindowSystemUiVisibility()26373 public int getWindowSystemUiVisibility() { 26374 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 26375 } 26376 26377 /** 26378 * Override to find out when the window's requested system UI visibility 26379 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 26380 * This is different from the callbacks received through 26381 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 26382 * in that this is only telling you about the local request of the window, 26383 * not the actual values applied by the system. 26384 * 26385 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26386 * instead. 26387 */ 26388 @Deprecated onWindowSystemUiVisibilityChanged(int visible)26389 public void onWindowSystemUiVisibilityChanged(int visible) { 26390 } 26391 26392 /** 26393 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 26394 * the view hierarchy. 26395 * 26396 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26397 * instead. 26398 */ 26399 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)26400 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 26401 onWindowSystemUiVisibilityChanged(visible); 26402 } 26403 26404 /** 26405 * Set a listener to receive callbacks when the visibility of the system bar changes. 26406 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 26407 * 26408 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 26409 * by setting a {@link OnApplyWindowInsetsListener} on this view. 26410 */ 26411 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)26412 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 26413 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 26414 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 26415 mParent.recomputeViewAttributes(this); 26416 } 26417 } 26418 26419 /** 26420 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 26421 * the view hierarchy. 26422 * 26423 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 26424 * by setting a {@link OnApplyWindowInsetsListener} on this view. 26425 */ 26426 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)26427 public void dispatchSystemUiVisibilityChanged(int visibility) { 26428 ListenerInfo li = mListenerInfo; 26429 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 26430 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 26431 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 26432 } 26433 } 26434 updateLocalSystemUiVisibility(int localValue, int localChanges)26435 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 26436 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 26437 if (val != mSystemUiVisibility) { 26438 setSystemUiVisibility(val); 26439 return true; 26440 } 26441 return false; 26442 } 26443 26444 /** @hide */ 26445 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setDisabledSystemUiVisibility(int flags)26446 public void setDisabledSystemUiVisibility(int flags) { 26447 if (mAttachInfo != null) { 26448 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 26449 mAttachInfo.mDisabledSystemUiVisibility = flags; 26450 if (mParent != null) { 26451 mParent.recomputeViewAttributes(this); 26452 } 26453 } 26454 } 26455 } 26456 26457 /** 26458 * This needs to be a better API before it is exposed. For now, only the root view will get 26459 * notified. 26460 * @hide 26461 */ onSystemBarAppearanceChanged(@indowInsetsController.Appearance int appearance)26462 public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { 26463 } 26464 26465 /** 26466 * Creates an image that the system displays during the drag and drop 26467 * operation. This is called a "drag shadow". The default implementation 26468 * for a DragShadowBuilder based on a View returns an image that has exactly the same 26469 * appearance as the given View. The default also positions the center of the drag shadow 26470 * directly under the touch point. If no View is provided (the constructor with no parameters 26471 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 26472 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 26473 * default is an invisible drag shadow. 26474 * <p> 26475 * You are not required to use the View you provide to the constructor as the basis of the 26476 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 26477 * anything you want as the drag shadow. 26478 * </p> 26479 * <p> 26480 * You pass a DragShadowBuilder object to the system when you start the drag. The system 26481 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 26482 * size and position of the drag shadow. It uses this data to construct a 26483 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 26484 * so that your application can draw the shadow image in the Canvas. 26485 * </p> 26486 * 26487 * <div class="special reference"> 26488 * <h3>Developer Guides</h3> 26489 * <p>For a guide to implementing drag and drop features, read the 26490 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 26491 * </div> 26492 */ 26493 public static class DragShadowBuilder { 26494 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 26495 private final WeakReference<View> mView; 26496 26497 /** 26498 * Constructs a shadow image builder based on a View. By default, the resulting drag 26499 * shadow will have the same appearance and dimensions as the View, with the touch point 26500 * over the center of the View. 26501 * @param view A View. Any View in scope can be used. 26502 */ DragShadowBuilder(View view)26503 public DragShadowBuilder(View view) { 26504 mView = new WeakReference<View>(view); 26505 } 26506 26507 /** 26508 * Construct a shadow builder object with no associated View. This 26509 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 26510 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 26511 * to supply the drag shadow's dimensions and appearance without 26512 * reference to any View object. 26513 */ DragShadowBuilder()26514 public DragShadowBuilder() { 26515 mView = new WeakReference<View>(null); 26516 } 26517 26518 /** 26519 * Returns the View object that had been passed to the 26520 * {@link #DragShadowBuilder(View)} 26521 * constructor. If that View parameter was {@code null} or if the 26522 * {@link #DragShadowBuilder()} 26523 * constructor was used to instantiate the builder object, this method will return 26524 * null. 26525 * 26526 * @return The View object associate with this builder object. 26527 */ 26528 @SuppressWarnings({"JavadocReference"}) getView()26529 final public View getView() { 26530 return mView.get(); 26531 } 26532 26533 /** 26534 * Provides the metrics for the shadow image. These include the dimensions of 26535 * the shadow image, and the point within that shadow that should 26536 * be centered under the touch location while dragging. 26537 * <p> 26538 * The default implementation sets the dimensions of the shadow to be the 26539 * same as the dimensions of the View itself and centers the shadow under 26540 * the touch point. 26541 * </p> 26542 * 26543 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 26544 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 26545 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 26546 * image. Since Android P, the width and height must be positive values. 26547 * 26548 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 26549 * shadow image that should be underneath the touch point during the drag and drop 26550 * operation. Your application must set {@link android.graphics.Point#x} to the 26551 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 26552 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)26553 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 26554 final View view = mView.get(); 26555 if (view != null) { 26556 outShadowSize.set(view.getWidth(), view.getHeight()); 26557 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 26558 } else { 26559 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 26560 } 26561 } 26562 26563 /** 26564 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 26565 * based on the dimensions it received from the 26566 * {@link #onProvideShadowMetrics(Point, Point)} callback. 26567 * 26568 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 26569 */ onDrawShadow(Canvas canvas)26570 public void onDrawShadow(Canvas canvas) { 26571 final View view = mView.get(); 26572 if (view != null) { 26573 view.draw(canvas); 26574 } else { 26575 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 26576 } 26577 } 26578 } 26579 26580 /** 26581 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 26582 * startDragAndDrop()} for newer platform versions. 26583 */ 26584 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)26585 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 26586 Object myLocalState, int flags) { 26587 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 26588 } 26589 26590 /** 26591 * Starts a drag and drop operation. When your application calls this method, it passes a 26592 * {@link android.view.View.DragShadowBuilder} object to the system. The 26593 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 26594 * to get metrics for the drag shadow, and then calls the object's 26595 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 26596 * <p> 26597 * Once the system has the drag shadow, it begins the drag and drop operation by sending 26598 * drag events to all the View objects in your application that are currently visible. It does 26599 * this either by calling the View object's drag listener (an implementation of 26600 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 26601 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 26602 * Both are passed a {@link android.view.DragEvent} object that has a 26603 * {@link android.view.DragEvent#getAction()} value of 26604 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 26605 * </p> 26606 * <p> 26607 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 26608 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 26609 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 26610 * to the View the user selected for dragging. 26611 * </p> 26612 * @param data A {@link android.content.ClipData} object pointing to the data to be 26613 * transferred by the drag and drop operation. 26614 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26615 * drag shadow. 26616 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 26617 * drop operation. When dispatching drag events to views in the same activity this object 26618 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 26619 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 26620 * will return null). 26621 * <p> 26622 * myLocalState is a lightweight mechanism for the sending information from the dragged View 26623 * to the target Views. For example, it can contain flags that differentiate between a 26624 * a copy operation and a move operation. 26625 * </p> 26626 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 26627 * flags, or any combination of the following: 26628 * <ul> 26629 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 26630 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 26631 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 26632 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 26633 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 26634 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 26635 * </ul> 26636 * @return {@code true} if the method completes successfully, or 26637 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 26638 * do a drag because of another ongoing operation or some other reasons. 26639 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)26640 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 26641 Object myLocalState, int flags) { 26642 if (ViewDebug.DEBUG_DRAG) { 26643 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 26644 } 26645 if (mAttachInfo == null) { 26646 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 26647 return false; 26648 } 26649 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 26650 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 26651 return false; 26652 } 26653 26654 if (data != null) { 26655 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 26656 } 26657 26658 Point shadowSize = new Point(); 26659 Point shadowTouchPoint = new Point(); 26660 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 26661 26662 if ((shadowSize.x < 0) || (shadowSize.y < 0) 26663 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 26664 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 26665 } 26666 26667 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 26668 // does not accept zero size surface. 26669 if (shadowSize.x == 0 || shadowSize.y == 0) { 26670 if (!sAcceptZeroSizeDragShadow) { 26671 throw new IllegalStateException("Drag shadow dimensions must be positive"); 26672 } 26673 shadowSize.x = 1; 26674 shadowSize.y = 1; 26675 } 26676 26677 if (ViewDebug.DEBUG_DRAG) { 26678 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 26679 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 26680 } 26681 26682 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 26683 final SurfaceSession session = new SurfaceSession(); 26684 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 26685 .setName("drag surface") 26686 .setParent(root.getSurfaceControl()) 26687 .setBufferSize(shadowSize.x, shadowSize.y) 26688 .setFormat(PixelFormat.TRANSLUCENT) 26689 .setCallsite("View.startDragAndDrop") 26690 .build(); 26691 final Surface surface = new Surface(); 26692 surface.copyFrom(surfaceControl); 26693 IBinder token = null; 26694 try { 26695 final Canvas canvas = isHardwareAccelerated() 26696 ? surface.lockHardwareCanvas() 26697 : surface.lockCanvas(null); 26698 try { 26699 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26700 shadowBuilder.onDrawShadow(canvas); 26701 } finally { 26702 surface.unlockCanvasAndPost(canvas); 26703 } 26704 26705 // repurpose 'shadowSize' for the last touch point 26706 root.getLastTouchPoint(shadowSize); 26707 26708 token = mAttachInfo.mSession.performDrag( 26709 mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(), 26710 shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data); 26711 if (ViewDebug.DEBUG_DRAG) { 26712 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 26713 } 26714 if (token != null) { 26715 if (mAttachInfo.mDragSurface != null) { 26716 mAttachInfo.mDragSurface.release(); 26717 } 26718 mAttachInfo.mDragSurface = surface; 26719 mAttachInfo.mDragToken = token; 26720 // Cache the local state object for delivery with DragEvents 26721 root.setLocalDragState(myLocalState); 26722 } 26723 return token != null; 26724 } catch (Exception e) { 26725 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 26726 return false; 26727 } finally { 26728 if (token == null) { 26729 surface.destroy(); 26730 } 26731 session.kill(); 26732 } 26733 } 26734 26735 /** 26736 * Cancels an ongoing drag and drop operation. 26737 * <p> 26738 * A {@link android.view.DragEvent} object with 26739 * {@link android.view.DragEvent#getAction()} value of 26740 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 26741 * {@link android.view.DragEvent#getResult()} value of {@code false} 26742 * will be sent to every 26743 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 26744 * even if they are not currently visible. 26745 * </p> 26746 * <p> 26747 * This method can be called on any View in the same window as the View on which 26748 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 26749 * was called. 26750 * </p> 26751 */ cancelDragAndDrop()26752 public final void cancelDragAndDrop() { 26753 if (ViewDebug.DEBUG_DRAG) { 26754 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 26755 } 26756 if (mAttachInfo == null) { 26757 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 26758 return; 26759 } 26760 if (mAttachInfo.mDragToken != null) { 26761 try { 26762 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 26763 } catch (Exception e) { 26764 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 26765 } 26766 mAttachInfo.mDragToken = null; 26767 } else { 26768 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 26769 } 26770 } 26771 26772 /** 26773 * Updates the drag shadow for the ongoing drag and drop operation. 26774 * 26775 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26776 * new drag shadow. 26777 */ updateDragShadow(DragShadowBuilder shadowBuilder)26778 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 26779 if (ViewDebug.DEBUG_DRAG) { 26780 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 26781 } 26782 if (mAttachInfo == null) { 26783 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 26784 return; 26785 } 26786 if (mAttachInfo.mDragToken != null) { 26787 try { 26788 Canvas canvas = isHardwareAccelerated() 26789 ? mAttachInfo.mDragSurface.lockHardwareCanvas() 26790 : mAttachInfo.mDragSurface.lockCanvas(null); 26791 try { 26792 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26793 shadowBuilder.onDrawShadow(canvas); 26794 } finally { 26795 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 26796 } 26797 } catch (Exception e) { 26798 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 26799 } 26800 } else { 26801 Log.e(VIEW_LOG_TAG, "No active drag"); 26802 } 26803 } 26804 26805 /** 26806 * Starts a move from {startX, startY}, the amount of the movement will be the offset 26807 * between {startX, startY} and the new cursor positon. 26808 * @param startX horizontal coordinate where the move started. 26809 * @param startY vertical coordinate where the move started. 26810 * @return whether moving was started successfully. 26811 * @hide 26812 */ startMovingTask(float startX, float startY)26813 public final boolean startMovingTask(float startX, float startY) { 26814 if (ViewDebug.DEBUG_POSITIONING) { 26815 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 26816 } 26817 try { 26818 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 26819 } catch (RemoteException e) { 26820 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 26821 } 26822 return false; 26823 } 26824 26825 /** 26826 * Finish a window move task. 26827 * @hide 26828 */ finishMovingTask()26829 public void finishMovingTask() { 26830 if (ViewDebug.DEBUG_POSITIONING) { 26831 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 26832 } 26833 try { 26834 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 26835 } catch (RemoteException e) { 26836 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 26837 } 26838 } 26839 26840 /** 26841 * Handles drag events sent by the system following a call to 26842 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 26843 * startDragAndDrop()}. 26844 *<p> 26845 * When the system calls this method, it passes a 26846 * {@link android.view.DragEvent} object. A call to 26847 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 26848 * in DragEvent. The method uses these to determine what is happening in the drag and drop 26849 * operation. 26850 * </p> 26851 * <p> 26852 * The default implementation returns false, except if an {@link OnReceiveContentListener} 26853 * is {@link #setOnReceiveContentListener set} for this view. If an 26854 * {@link OnReceiveContentListener} is set, the default implementation... 26855 * <ul> 26856 * <li>returns true for an 26857 * {@link android.view.DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event 26858 * <li>calls {@link #performReceiveContent} for an 26859 * {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event 26860 * <li>returns true for an {@link android.view.DragEvent#ACTION_DROP ACTION_DROP} event, if 26861 * the listener consumed some or all of the content 26862 * </ul> 26863 * </p> 26864 * 26865 * @param event The {@link android.view.DragEvent} sent by the system. 26866 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 26867 * in DragEvent, indicating the type of drag event represented by this object. 26868 * @return {@code true} if the method was successful, otherwise {@code false}. 26869 * <p> 26870 * The method should return {@code true} in response to an action type of 26871 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 26872 * operation. 26873 * </p> 26874 * <p> 26875 * The method should also return {@code true} in response to an action type of 26876 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 26877 * {@code false} if it didn't. 26878 * </p> 26879 * <p> 26880 * For all other events, the return value is ignored. 26881 * </p> 26882 */ onDragEvent(DragEvent event)26883 public boolean onDragEvent(DragEvent event) { 26884 if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { 26885 return false; 26886 } 26887 // Accept drag events by default if there's an OnReceiveContentListener set. 26888 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { 26889 return true; 26890 } 26891 if (event.getAction() == DragEvent.ACTION_DROP) { 26892 final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); 26893 if (permissions != null) { 26894 permissions.takeTransient(); 26895 } 26896 final ContentInfo payload = 26897 new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) 26898 .setDragAndDropPermissions(permissions) 26899 .build(); 26900 ContentInfo remainingPayload = performReceiveContent(payload); 26901 // Return true unless none of the payload was consumed. 26902 return remainingPayload != payload; 26903 } 26904 return false; 26905 } 26906 26907 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)26908 boolean dispatchDragEnterExitInPreN(DragEvent event) { 26909 return callDragEventHandler(event); 26910 } 26911 26912 /** 26913 * Detects if this View is enabled and has a drag event listener. 26914 * If both are true, then it calls the drag event listener with the 26915 * {@link android.view.DragEvent} it received. If the drag event listener returns 26916 * {@code true}, then dispatchDragEvent() returns {@code true}. 26917 * <p> 26918 * For all other cases, the method calls the 26919 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 26920 * method and returns its result. 26921 * </p> 26922 * <p> 26923 * This ensures that a drag event is always consumed, even if the View does not have a drag 26924 * event listener. However, if the View has a listener and the listener returns true, then 26925 * onDragEvent() is not called. 26926 * </p> 26927 */ dispatchDragEvent(DragEvent event)26928 public boolean dispatchDragEvent(DragEvent event) { 26929 event.mEventHandlerWasCalled = true; 26930 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 26931 event.mAction == DragEvent.ACTION_DROP) { 26932 // About to deliver an event with coordinates to this view. Notify that now this view 26933 // has drag focus. This will send exit/enter events as needed. 26934 getViewRootImpl().setDragFocus(this, event); 26935 } 26936 return callDragEventHandler(event); 26937 } 26938 callDragEventHandler(DragEvent event)26939 final boolean callDragEventHandler(DragEvent event) { 26940 final boolean result; 26941 26942 ListenerInfo li = mListenerInfo; 26943 //noinspection SimplifiableIfStatement 26944 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 26945 && li.mOnDragListener.onDrag(this, event)) { 26946 result = true; 26947 } else { 26948 result = onDragEvent(event); 26949 } 26950 26951 switch (event.mAction) { 26952 case DragEvent.ACTION_DRAG_ENTERED: { 26953 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 26954 refreshDrawableState(); 26955 } break; 26956 case DragEvent.ACTION_DRAG_EXITED: { 26957 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 26958 refreshDrawableState(); 26959 } break; 26960 case DragEvent.ACTION_DRAG_ENDED: { 26961 mPrivateFlags2 &= ~View.DRAG_MASK; 26962 refreshDrawableState(); 26963 } break; 26964 } 26965 26966 return result; 26967 } 26968 canAcceptDrag()26969 boolean canAcceptDrag() { 26970 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 26971 } 26972 26973 /** 26974 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 26975 * it is ever exposed at all. 26976 * @hide 26977 */ 26978 @UnsupportedAppUsage onCloseSystemDialogs(String reason)26979 public void onCloseSystemDialogs(String reason) { 26980 } 26981 26982 /** 26983 * Given a Drawable whose bounds have been set to draw into this view, 26984 * update a Region being computed for 26985 * {@link #gatherTransparentRegion(android.graphics.Region)} so 26986 * that any non-transparent parts of the Drawable are removed from the 26987 * given transparent region. 26988 * 26989 * @param dr The Drawable whose transparency is to be applied to the region. 26990 * @param region A Region holding the current transparency information, 26991 * where any parts of the region that are set are considered to be 26992 * transparent. On return, this region will be modified to have the 26993 * transparency information reduced by the corresponding parts of the 26994 * Drawable that are not transparent. 26995 * {@hide} 26996 */ 26997 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyDrawableToTransparentRegion(Drawable dr, Region region)26998 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 26999 if (DBG) { 27000 Log.i("View", "Getting transparent region for: " + this); 27001 } 27002 final Region r = dr.getTransparentRegion(); 27003 final Rect db = dr.getBounds(); 27004 final AttachInfo attachInfo = mAttachInfo; 27005 if (r != null && attachInfo != null) { 27006 final int w = getRight()-getLeft(); 27007 final int h = getBottom()-getTop(); 27008 if (db.left > 0) { 27009 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 27010 r.op(0, 0, db.left, h, Region.Op.UNION); 27011 } 27012 if (db.right < w) { 27013 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 27014 r.op(db.right, 0, w, h, Region.Op.UNION); 27015 } 27016 if (db.top > 0) { 27017 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 27018 r.op(0, 0, w, db.top, Region.Op.UNION); 27019 } 27020 if (db.bottom < h) { 27021 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 27022 r.op(0, db.bottom, w, h, Region.Op.UNION); 27023 } 27024 final int[] location = attachInfo.mTransparentLocation; 27025 getLocationInWindow(location); 27026 r.translate(location[0], location[1]); 27027 region.op(r, Region.Op.INTERSECT); 27028 } else { 27029 region.op(db, Region.Op.DIFFERENCE); 27030 } 27031 } 27032 checkForLongClick(long delay, float x, float y, int classification)27033 private void checkForLongClick(long delay, float x, float y, int classification) { 27034 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 27035 mHasPerformedLongPress = false; 27036 27037 if (mPendingCheckForLongPress == null) { 27038 mPendingCheckForLongPress = new CheckForLongPress(); 27039 } 27040 mPendingCheckForLongPress.setAnchor(x, y); 27041 mPendingCheckForLongPress.rememberWindowAttachCount(); 27042 mPendingCheckForLongPress.rememberPressedState(); 27043 mPendingCheckForLongPress.setClassification(classification); 27044 postDelayed(mPendingCheckForLongPress, delay); 27045 } 27046 } 27047 27048 /** 27049 * Inflate a view from an XML resource. This convenience method wraps the {@link 27050 * LayoutInflater} class, which provides a full range of options for view inflation. 27051 * 27052 * @param context The Context object for your activity or application. 27053 * @param resource The resource ID to inflate 27054 * @param root A view group that will be the parent. Used to properly inflate the 27055 * layout_* parameters. 27056 * @see LayoutInflater 27057 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)27058 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 27059 LayoutInflater factory = LayoutInflater.from(context); 27060 return factory.inflate(resource, root); 27061 } 27062 27063 /** 27064 * Scroll the view with standard behavior for scrolling beyond the normal 27065 * content boundaries. Views that call this method should override 27066 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 27067 * results of an over-scroll operation. 27068 * 27069 * Views can use this method to handle any touch or fling-based scrolling. 27070 * 27071 * @param deltaX Change in X in pixels 27072 * @param deltaY Change in Y in pixels 27073 * @param scrollX Current X scroll value in pixels before applying deltaX 27074 * @param scrollY Current Y scroll value in pixels before applying deltaY 27075 * @param scrollRangeX Maximum content scroll range along the X axis 27076 * @param scrollRangeY Maximum content scroll range along the Y axis 27077 * @param maxOverScrollX Number of pixels to overscroll by in either direction 27078 * along the X axis. 27079 * @param maxOverScrollY Number of pixels to overscroll by in either direction 27080 * along the Y axis. 27081 * @param isTouchEvent true if this scroll operation is the result of a touch event. 27082 * @return true if scrolling was clamped to an over-scroll boundary along either 27083 * axis, false otherwise. 27084 */ 27085 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)27086 protected boolean overScrollBy(int deltaX, int deltaY, 27087 int scrollX, int scrollY, 27088 int scrollRangeX, int scrollRangeY, 27089 int maxOverScrollX, int maxOverScrollY, 27090 boolean isTouchEvent) { 27091 final int overScrollMode = mOverScrollMode; 27092 final boolean canScrollHorizontal = 27093 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 27094 final boolean canScrollVertical = 27095 computeVerticalScrollRange() > computeVerticalScrollExtent(); 27096 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 27097 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 27098 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 27099 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 27100 27101 int newScrollX = scrollX + deltaX; 27102 if (!overScrollHorizontal) { 27103 maxOverScrollX = 0; 27104 } 27105 27106 int newScrollY = scrollY + deltaY; 27107 if (!overScrollVertical) { 27108 maxOverScrollY = 0; 27109 } 27110 27111 // Clamp values if at the limits and record 27112 final int left = -maxOverScrollX; 27113 final int right = maxOverScrollX + scrollRangeX; 27114 final int top = -maxOverScrollY; 27115 final int bottom = maxOverScrollY + scrollRangeY; 27116 27117 boolean clampedX = false; 27118 if (newScrollX > right) { 27119 newScrollX = right; 27120 clampedX = true; 27121 } else if (newScrollX < left) { 27122 newScrollX = left; 27123 clampedX = true; 27124 } 27125 27126 boolean clampedY = false; 27127 if (newScrollY > bottom) { 27128 newScrollY = bottom; 27129 clampedY = true; 27130 } else if (newScrollY < top) { 27131 newScrollY = top; 27132 clampedY = true; 27133 } 27134 27135 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 27136 27137 return clampedX || clampedY; 27138 } 27139 27140 /** 27141 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 27142 * respond to the results of an over-scroll operation. 27143 * 27144 * @param scrollX New X scroll value in pixels 27145 * @param scrollY New Y scroll value in pixels 27146 * @param clampedX True if scrollX was clamped to an over-scroll boundary 27147 * @param clampedY True if scrollY was clamped to an over-scroll boundary 27148 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)27149 protected void onOverScrolled(int scrollX, int scrollY, 27150 boolean clampedX, boolean clampedY) { 27151 // Intentionally empty. 27152 } 27153 27154 /** 27155 * Returns the over-scroll mode for this view. The result will be 27156 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 27157 * (allow over-scrolling only if the view content is larger than the container), 27158 * or {@link #OVER_SCROLL_NEVER}. 27159 * 27160 * @return This view's over-scroll mode. 27161 */ 27162 @InspectableProperty(enumMapping = { 27163 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 27164 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 27165 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 27166 }) getOverScrollMode()27167 public int getOverScrollMode() { 27168 return mOverScrollMode; 27169 } 27170 27171 /** 27172 * Set the over-scroll mode for this view. Valid over-scroll modes are 27173 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 27174 * (allow over-scrolling only if the view content is larger than the container), 27175 * or {@link #OVER_SCROLL_NEVER}. 27176 * 27177 * Setting the over-scroll mode of a view will have an effect only if the 27178 * view is capable of scrolling. 27179 * 27180 * @param overScrollMode The new over-scroll mode for this view. 27181 */ setOverScrollMode(int overScrollMode)27182 public void setOverScrollMode(int overScrollMode) { 27183 if (overScrollMode != OVER_SCROLL_ALWAYS && 27184 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 27185 overScrollMode != OVER_SCROLL_NEVER) { 27186 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 27187 } 27188 mOverScrollMode = overScrollMode; 27189 } 27190 27191 /** 27192 * Enable or disable nested scrolling for this view. 27193 * 27194 * <p>If this property is set to true the view will be permitted to initiate nested 27195 * scrolling operations with a compatible parent view in the current hierarchy. If this 27196 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 27197 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 27198 * the nested scroll.</p> 27199 * 27200 * @param enabled true to enable nested scrolling, false to disable 27201 * 27202 * @see #isNestedScrollingEnabled() 27203 */ setNestedScrollingEnabled(boolean enabled)27204 public void setNestedScrollingEnabled(boolean enabled) { 27205 if (enabled) { 27206 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 27207 } else { 27208 stopNestedScroll(); 27209 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 27210 } 27211 } 27212 27213 /** 27214 * Returns true if nested scrolling is enabled for this view. 27215 * 27216 * <p>If nested scrolling is enabled and this View class implementation supports it, 27217 * this view will act as a nested scrolling child view when applicable, forwarding data 27218 * about the scroll operation in progress to a compatible and cooperating nested scrolling 27219 * parent.</p> 27220 * 27221 * @return true if nested scrolling is enabled 27222 * 27223 * @see #setNestedScrollingEnabled(boolean) 27224 */ 27225 @InspectableProperty isNestedScrollingEnabled()27226 public boolean isNestedScrollingEnabled() { 27227 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 27228 PFLAG3_NESTED_SCROLLING_ENABLED; 27229 } 27230 27231 /** 27232 * Begin a nestable scroll operation along the given axes. 27233 * 27234 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 27235 * 27236 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 27237 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 27238 * In the case of touch scrolling the nested scroll will be terminated automatically in 27239 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 27240 * In the event of programmatic scrolling the caller must explicitly call 27241 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 27242 * 27243 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 27244 * If it returns false the caller may ignore the rest of this contract until the next scroll. 27245 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 27246 * 27247 * <p>At each incremental step of the scroll the caller should invoke 27248 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 27249 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 27250 * parent at least partially consumed the scroll and the caller should adjust the amount it 27251 * scrolls by.</p> 27252 * 27253 * <p>After applying the remainder of the scroll delta the caller should invoke 27254 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 27255 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 27256 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 27257 * </p> 27258 * 27259 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 27260 * {@link #SCROLL_AXIS_VERTICAL}. 27261 * @return true if a cooperative parent was found and nested scrolling has been enabled for 27262 * the current gesture. 27263 * 27264 * @see #stopNestedScroll() 27265 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 27266 * @see #dispatchNestedScroll(int, int, int, int, int[]) 27267 */ startNestedScroll(int axes)27268 public boolean startNestedScroll(int axes) { 27269 if (hasNestedScrollingParent()) { 27270 // Already in progress 27271 return true; 27272 } 27273 if (isNestedScrollingEnabled()) { 27274 ViewParent p = getParent(); 27275 View child = this; 27276 while (p != null) { 27277 try { 27278 if (p.onStartNestedScroll(child, this, axes)) { 27279 mNestedScrollingParent = p; 27280 p.onNestedScrollAccepted(child, this, axes); 27281 return true; 27282 } 27283 } catch (AbstractMethodError e) { 27284 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 27285 "method onStartNestedScroll", e); 27286 // Allow the search upward to continue 27287 } 27288 if (p instanceof View) { 27289 child = (View) p; 27290 } 27291 p = p.getParent(); 27292 } 27293 } 27294 return false; 27295 } 27296 27297 /** 27298 * Stop a nested scroll in progress. 27299 * 27300 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 27301 * 27302 * @see #startNestedScroll(int) 27303 */ stopNestedScroll()27304 public void stopNestedScroll() { 27305 if (mNestedScrollingParent != null) { 27306 mNestedScrollingParent.onStopNestedScroll(this); 27307 mNestedScrollingParent = null; 27308 } 27309 } 27310 27311 /** 27312 * Returns true if this view has a nested scrolling parent. 27313 * 27314 * <p>The presence of a nested scrolling parent indicates that this view has initiated 27315 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 27316 * 27317 * @return whether this view has a nested scrolling parent 27318 */ hasNestedScrollingParent()27319 public boolean hasNestedScrollingParent() { 27320 return mNestedScrollingParent != null; 27321 } 27322 27323 /** 27324 * Dispatch one step of a nested scroll in progress. 27325 * 27326 * <p>Implementations of views that support nested scrolling should call this to report 27327 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 27328 * is not currently in progress or nested scrolling is not 27329 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 27330 * 27331 * <p>Compatible View implementations should also call 27332 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 27333 * consuming a component of the scroll event themselves.</p> 27334 * 27335 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 27336 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 27337 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 27338 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 27339 * @param offsetInWindow Optional. If not null, on return this will contain the offset 27340 * in local view coordinates of this view from before this operation 27341 * to after it completes. View implementations may use this to adjust 27342 * expected input coordinate tracking. 27343 * @return true if the event was dispatched, false if it could not be dispatched. 27344 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 27345 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)27346 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 27347 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 27348 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27349 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 27350 int startX = 0; 27351 int startY = 0; 27352 if (offsetInWindow != null) { 27353 getLocationInWindow(offsetInWindow); 27354 startX = offsetInWindow[0]; 27355 startY = offsetInWindow[1]; 27356 } 27357 27358 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 27359 dxUnconsumed, dyUnconsumed); 27360 27361 if (offsetInWindow != null) { 27362 getLocationInWindow(offsetInWindow); 27363 offsetInWindow[0] -= startX; 27364 offsetInWindow[1] -= startY; 27365 } 27366 return true; 27367 } else if (offsetInWindow != null) { 27368 // No motion, no dispatch. Keep offsetInWindow up to date. 27369 offsetInWindow[0] = 0; 27370 offsetInWindow[1] = 0; 27371 } 27372 } 27373 return false; 27374 } 27375 27376 /** 27377 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 27378 * 27379 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 27380 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 27381 * scrolling operation to consume some or all of the scroll operation before the child view 27382 * consumes it.</p> 27383 * 27384 * @param dx Horizontal scroll distance in pixels 27385 * @param dy Vertical scroll distance in pixels 27386 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 27387 * and consumed[1] the consumed dy. 27388 * @param offsetInWindow Optional. If not null, on return this will contain the offset 27389 * in local view coordinates of this view from before this operation 27390 * to after it completes. View implementations may use this to adjust 27391 * expected input coordinate tracking. 27392 * @return true if the parent consumed some or all of the scroll delta 27393 * @see #dispatchNestedScroll(int, int, int, int, int[]) 27394 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)27395 public boolean dispatchNestedPreScroll(int dx, int dy, 27396 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 27397 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27398 if (dx != 0 || dy != 0) { 27399 int startX = 0; 27400 int startY = 0; 27401 if (offsetInWindow != null) { 27402 getLocationInWindow(offsetInWindow); 27403 startX = offsetInWindow[0]; 27404 startY = offsetInWindow[1]; 27405 } 27406 27407 if (consumed == null) { 27408 if (mTempNestedScrollConsumed == null) { 27409 mTempNestedScrollConsumed = new int[2]; 27410 } 27411 consumed = mTempNestedScrollConsumed; 27412 } 27413 consumed[0] = 0; 27414 consumed[1] = 0; 27415 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 27416 27417 if (offsetInWindow != null) { 27418 getLocationInWindow(offsetInWindow); 27419 offsetInWindow[0] -= startX; 27420 offsetInWindow[1] -= startY; 27421 } 27422 return consumed[0] != 0 || consumed[1] != 0; 27423 } else if (offsetInWindow != null) { 27424 offsetInWindow[0] = 0; 27425 offsetInWindow[1] = 0; 27426 } 27427 } 27428 return false; 27429 } 27430 27431 /** 27432 * Dispatch a fling to a nested scrolling parent. 27433 * 27434 * <p>This method should be used to indicate that a nested scrolling child has detected 27435 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 27436 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 27437 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 27438 * along a scrollable axis.</p> 27439 * 27440 * <p>If a nested scrolling child view would normally fling but it is at the edge of 27441 * its own content, it can use this method to delegate the fling to its nested scrolling 27442 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 27443 * 27444 * @param velocityX Horizontal fling velocity in pixels per second 27445 * @param velocityY Vertical fling velocity in pixels per second 27446 * @param consumed true if the child consumed the fling, false otherwise 27447 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 27448 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)27449 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 27450 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27451 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 27452 } 27453 return false; 27454 } 27455 27456 /** 27457 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 27458 * 27459 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 27460 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 27461 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 27462 * before the child view consumes it. If this method returns <code>true</code>, a nested 27463 * parent view consumed the fling and this view should not scroll as a result.</p> 27464 * 27465 * <p>For a better user experience, only one view in a nested scrolling chain should consume 27466 * the fling at a time. If a parent view consumed the fling this method will return false. 27467 * Custom view implementations should account for this in two ways:</p> 27468 * 27469 * <ul> 27470 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 27471 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 27472 * position regardless.</li> 27473 * <li>If a nested parent does consume the fling, this view should not scroll at all, 27474 * even to settle back to a valid idle position.</li> 27475 * </ul> 27476 * 27477 * <p>Views should also not offer fling velocities to nested parent views along an axis 27478 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 27479 * should not offer a horizontal fling velocity to its parents since scrolling along that 27480 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 27481 * 27482 * @param velocityX Horizontal fling velocity in pixels per second 27483 * @param velocityY Vertical fling velocity in pixels per second 27484 * @return true if a nested scrolling parent consumed the fling 27485 */ dispatchNestedPreFling(float velocityX, float velocityY)27486 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 27487 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27488 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 27489 } 27490 return false; 27491 } 27492 27493 /** 27494 * Gets a scale factor that determines the distance the view should scroll 27495 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 27496 * @return The vertical scroll scale factor. 27497 * @hide 27498 */ 27499 @UnsupportedAppUsage getVerticalScrollFactor()27500 protected float getVerticalScrollFactor() { 27501 if (mVerticalScrollFactor == 0) { 27502 TypedValue outValue = new TypedValue(); 27503 if (!mContext.getTheme().resolveAttribute( 27504 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 27505 throw new IllegalStateException( 27506 "Expected theme to define listPreferredItemHeight."); 27507 } 27508 mVerticalScrollFactor = outValue.getDimension( 27509 mContext.getResources().getDisplayMetrics()); 27510 } 27511 return mVerticalScrollFactor; 27512 } 27513 27514 /** 27515 * Gets a scale factor that determines the distance the view should scroll 27516 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 27517 * @return The horizontal scroll scale factor. 27518 * @hide 27519 */ 27520 @UnsupportedAppUsage getHorizontalScrollFactor()27521 protected float getHorizontalScrollFactor() { 27522 // TODO: Should use something else. 27523 return getVerticalScrollFactor(); 27524 } 27525 27526 /** 27527 * Return the value specifying the text direction or policy that was set with 27528 * {@link #setTextDirection(int)}. 27529 * 27530 * @return the defined text direction. It can be one of: 27531 * 27532 * {@link #TEXT_DIRECTION_INHERIT}, 27533 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27534 * {@link #TEXT_DIRECTION_ANY_RTL}, 27535 * {@link #TEXT_DIRECTION_LTR}, 27536 * {@link #TEXT_DIRECTION_RTL}, 27537 * {@link #TEXT_DIRECTION_LOCALE}, 27538 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27539 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 27540 * 27541 * @attr ref android.R.styleable#View_textDirection 27542 * 27543 * @hide 27544 */ 27545 @ViewDebug.ExportedProperty(category = "text", mapping = { 27546 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 27547 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 27548 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 27549 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 27550 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 27551 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 27552 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 27553 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 27554 }) 27555 @InspectableProperty(hasAttributeId = false, enumMapping = { 27556 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 27557 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 27558 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 27559 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 27560 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 27561 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 27562 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 27563 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 27564 }) 27565 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextDirection()27566 public int getRawTextDirection() { 27567 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 27568 } 27569 27570 /** 27571 * Set the text direction. 27572 * 27573 * @param textDirection the direction to set. Should be one of: 27574 * 27575 * {@link #TEXT_DIRECTION_INHERIT}, 27576 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27577 * {@link #TEXT_DIRECTION_ANY_RTL}, 27578 * {@link #TEXT_DIRECTION_LTR}, 27579 * {@link #TEXT_DIRECTION_RTL}, 27580 * {@link #TEXT_DIRECTION_LOCALE} 27581 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27582 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 27583 * 27584 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 27585 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 27586 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 27587 * 27588 * @attr ref android.R.styleable#View_textDirection 27589 */ setTextDirection(int textDirection)27590 public void setTextDirection(int textDirection) { 27591 if (getRawTextDirection() != textDirection) { 27592 // Reset the current text direction and the resolved one 27593 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 27594 resetResolvedTextDirection(); 27595 // Set the new text direction 27596 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 27597 // Do resolution 27598 resolveTextDirection(); 27599 // Notify change 27600 onRtlPropertiesChanged(getLayoutDirection()); 27601 // Refresh 27602 requestLayout(); 27603 invalidate(true); 27604 } 27605 } 27606 27607 /** 27608 * Return the resolved text direction. 27609 * 27610 * @return the resolved text direction. Returns one of: 27611 * 27612 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27613 * {@link #TEXT_DIRECTION_ANY_RTL}, 27614 * {@link #TEXT_DIRECTION_LTR}, 27615 * {@link #TEXT_DIRECTION_RTL}, 27616 * {@link #TEXT_DIRECTION_LOCALE}, 27617 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27618 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 27619 * 27620 * @attr ref android.R.styleable#View_textDirection 27621 */ 27622 @ViewDebug.ExportedProperty(category = "text", mapping = { 27623 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 27624 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 27625 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 27626 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 27627 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 27628 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 27629 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 27630 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 27631 }) 27632 @InspectableProperty(hasAttributeId = false, enumMapping = { 27633 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 27634 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 27635 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 27636 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 27637 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 27638 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 27639 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 27640 }) getTextDirection()27641 public int getTextDirection() { 27642 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 27643 } 27644 27645 /** 27646 * Resolve the text direction. 27647 * 27648 * @return true if resolution has been done, false otherwise. 27649 * 27650 * @hide 27651 */ resolveTextDirection()27652 public boolean resolveTextDirection() { 27653 // Reset any previous text direction resolution 27654 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27655 27656 if (hasRtlSupport()) { 27657 // Set resolved text direction flag depending on text direction flag 27658 final int textDirection = getRawTextDirection(); 27659 switch(textDirection) { 27660 case TEXT_DIRECTION_INHERIT: 27661 if (!canResolveTextDirection()) { 27662 // We cannot do the resolution if there is no parent, so use the default one 27663 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27664 // Resolution will need to happen again later 27665 return false; 27666 } 27667 27668 // Parent has not yet resolved, so we still return the default 27669 try { 27670 if (!mParent.isTextDirectionResolved()) { 27671 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27672 // Resolution will need to happen again later 27673 return false; 27674 } 27675 } catch (AbstractMethodError e) { 27676 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27677 " does not fully implement ViewParent", e); 27678 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 27679 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27680 return true; 27681 } 27682 27683 // Set current resolved direction to the same value as the parent's one 27684 int parentResolvedDirection; 27685 try { 27686 parentResolvedDirection = mParent.getTextDirection(); 27687 } catch (AbstractMethodError e) { 27688 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27689 " does not fully implement ViewParent", e); 27690 parentResolvedDirection = TEXT_DIRECTION_LTR; 27691 } 27692 switch (parentResolvedDirection) { 27693 case TEXT_DIRECTION_FIRST_STRONG: 27694 case TEXT_DIRECTION_ANY_RTL: 27695 case TEXT_DIRECTION_LTR: 27696 case TEXT_DIRECTION_RTL: 27697 case TEXT_DIRECTION_LOCALE: 27698 case TEXT_DIRECTION_FIRST_STRONG_LTR: 27699 case TEXT_DIRECTION_FIRST_STRONG_RTL: 27700 mPrivateFlags2 |= 27701 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 27702 break; 27703 default: 27704 // Default resolved direction is "first strong" heuristic 27705 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27706 } 27707 break; 27708 case TEXT_DIRECTION_FIRST_STRONG: 27709 case TEXT_DIRECTION_ANY_RTL: 27710 case TEXT_DIRECTION_LTR: 27711 case TEXT_DIRECTION_RTL: 27712 case TEXT_DIRECTION_LOCALE: 27713 case TEXT_DIRECTION_FIRST_STRONG_LTR: 27714 case TEXT_DIRECTION_FIRST_STRONG_RTL: 27715 // Resolved direction is the same as text direction 27716 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 27717 break; 27718 default: 27719 // Default resolved direction is "first strong" heuristic 27720 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27721 } 27722 } else { 27723 // Default resolved direction is "first strong" heuristic 27724 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27725 } 27726 27727 // Set to resolved 27728 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 27729 return true; 27730 } 27731 27732 /** 27733 * Check if text direction resolution can be done. 27734 * 27735 * @return true if text direction resolution can be done otherwise return false. 27736 */ canResolveTextDirection()27737 public boolean canResolveTextDirection() { 27738 switch (getRawTextDirection()) { 27739 case TEXT_DIRECTION_INHERIT: 27740 if (mParent != null) { 27741 try { 27742 return mParent.canResolveTextDirection(); 27743 } catch (AbstractMethodError e) { 27744 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27745 " does not fully implement ViewParent", e); 27746 } 27747 } 27748 return false; 27749 27750 default: 27751 return true; 27752 } 27753 } 27754 27755 /** 27756 * Reset resolved text direction. Text direction will be resolved during a call to 27757 * {@link #onMeasure(int, int)}. 27758 * 27759 * @hide 27760 */ 27761 @TestApi resetResolvedTextDirection()27762 public void resetResolvedTextDirection() { 27763 // Reset any previous text direction resolution 27764 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27765 // Set to default value 27766 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27767 } 27768 27769 /** 27770 * @return true if text direction is inherited. 27771 * 27772 * @hide 27773 */ isTextDirectionInherited()27774 public boolean isTextDirectionInherited() { 27775 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 27776 } 27777 27778 /** 27779 * @return true if text direction is resolved. 27780 */ isTextDirectionResolved()27781 public boolean isTextDirectionResolved() { 27782 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 27783 } 27784 27785 /** 27786 * Return the value specifying the text alignment or policy that was set with 27787 * {@link #setTextAlignment(int)}. 27788 * 27789 * @return the defined text alignment. It can be one of: 27790 * 27791 * {@link #TEXT_ALIGNMENT_INHERIT}, 27792 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27793 * {@link #TEXT_ALIGNMENT_CENTER}, 27794 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27795 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27796 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27797 * {@link #TEXT_ALIGNMENT_VIEW_END} 27798 * 27799 * @attr ref android.R.styleable#View_textAlignment 27800 * 27801 * @hide 27802 */ 27803 @ViewDebug.ExportedProperty(category = "text", mapping = { 27804 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27805 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27806 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27807 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27808 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27809 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27810 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27811 }) 27812 @InspectableProperty(hasAttributeId = false, enumMapping = { 27813 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 27814 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27815 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27816 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27817 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27818 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27819 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27820 }) 27821 @TextAlignment 27822 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextAlignment()27823 public int getRawTextAlignment() { 27824 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 27825 } 27826 27827 /** 27828 * Set the text alignment. 27829 * 27830 * @param textAlignment The text alignment to set. Should be one of 27831 * 27832 * {@link #TEXT_ALIGNMENT_INHERIT}, 27833 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27834 * {@link #TEXT_ALIGNMENT_CENTER}, 27835 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27836 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27837 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27838 * {@link #TEXT_ALIGNMENT_VIEW_END} 27839 * 27840 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 27841 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 27842 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 27843 * 27844 * @attr ref android.R.styleable#View_textAlignment 27845 */ setTextAlignment(@extAlignment int textAlignment)27846 public void setTextAlignment(@TextAlignment int textAlignment) { 27847 if (textAlignment != getRawTextAlignment()) { 27848 // Reset the current and resolved text alignment 27849 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 27850 resetResolvedTextAlignment(); 27851 // Set the new text alignment 27852 mPrivateFlags2 |= 27853 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 27854 // Do resolution 27855 resolveTextAlignment(); 27856 // Notify change 27857 onRtlPropertiesChanged(getLayoutDirection()); 27858 // Refresh 27859 requestLayout(); 27860 invalidate(true); 27861 } 27862 } 27863 27864 /** 27865 * Return the resolved text alignment. 27866 * 27867 * @return the resolved text alignment. Returns one of: 27868 * 27869 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27870 * {@link #TEXT_ALIGNMENT_CENTER}, 27871 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27872 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27873 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27874 * {@link #TEXT_ALIGNMENT_VIEW_END} 27875 * 27876 * @attr ref android.R.styleable#View_textAlignment 27877 */ 27878 @ViewDebug.ExportedProperty(category = "text", mapping = { 27879 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27880 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27881 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27882 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27883 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27884 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27885 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27886 }) 27887 @InspectableProperty(enumMapping = { 27888 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27889 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27890 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27891 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27892 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27893 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27894 }) 27895 @TextAlignment getTextAlignment()27896 public int getTextAlignment() { 27897 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 27898 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 27899 } 27900 27901 /** 27902 * Resolve the text alignment. 27903 * 27904 * @return true if resolution has been done, false otherwise. 27905 * 27906 * @hide 27907 */ resolveTextAlignment()27908 public boolean resolveTextAlignment() { 27909 // Reset any previous text alignment resolution 27910 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 27911 27912 if (hasRtlSupport()) { 27913 // Set resolved text alignment flag depending on text alignment flag 27914 final int textAlignment = getRawTextAlignment(); 27915 switch (textAlignment) { 27916 case TEXT_ALIGNMENT_INHERIT: 27917 // Check if we can resolve the text alignment 27918 if (!canResolveTextAlignment()) { 27919 // We cannot do the resolution if there is no parent so use the default 27920 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27921 // Resolution will need to happen again later 27922 return false; 27923 } 27924 27925 // Parent has not yet resolved, so we still return the default 27926 try { 27927 if (!mParent.isTextAlignmentResolved()) { 27928 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27929 // Resolution will need to happen again later 27930 return false; 27931 } 27932 } catch (AbstractMethodError e) { 27933 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27934 " does not fully implement ViewParent", e); 27935 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 27936 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27937 return true; 27938 } 27939 27940 int parentResolvedTextAlignment; 27941 try { 27942 parentResolvedTextAlignment = mParent.getTextAlignment(); 27943 } catch (AbstractMethodError e) { 27944 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27945 " does not fully implement ViewParent", e); 27946 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 27947 } 27948 switch (parentResolvedTextAlignment) { 27949 case TEXT_ALIGNMENT_GRAVITY: 27950 case TEXT_ALIGNMENT_TEXT_START: 27951 case TEXT_ALIGNMENT_TEXT_END: 27952 case TEXT_ALIGNMENT_CENTER: 27953 case TEXT_ALIGNMENT_VIEW_START: 27954 case TEXT_ALIGNMENT_VIEW_END: 27955 // Resolved text alignment is the same as the parent resolved 27956 // text alignment 27957 mPrivateFlags2 |= 27958 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 27959 break; 27960 default: 27961 // Use default resolved text alignment 27962 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27963 } 27964 break; 27965 case TEXT_ALIGNMENT_GRAVITY: 27966 case TEXT_ALIGNMENT_TEXT_START: 27967 case TEXT_ALIGNMENT_TEXT_END: 27968 case TEXT_ALIGNMENT_CENTER: 27969 case TEXT_ALIGNMENT_VIEW_START: 27970 case TEXT_ALIGNMENT_VIEW_END: 27971 // Resolved text alignment is the same as text alignment 27972 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 27973 break; 27974 default: 27975 // Use default resolved text alignment 27976 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27977 } 27978 } else { 27979 // Use default resolved text alignment 27980 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27981 } 27982 27983 // Set the resolved 27984 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 27985 return true; 27986 } 27987 27988 /** 27989 * Check if text alignment resolution can be done. 27990 * 27991 * @return true if text alignment resolution can be done otherwise return false. 27992 */ canResolveTextAlignment()27993 public boolean canResolveTextAlignment() { 27994 switch (getRawTextAlignment()) { 27995 case TEXT_DIRECTION_INHERIT: 27996 if (mParent != null) { 27997 try { 27998 return mParent.canResolveTextAlignment(); 27999 } catch (AbstractMethodError e) { 28000 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 28001 " does not fully implement ViewParent", e); 28002 } 28003 } 28004 return false; 28005 28006 default: 28007 return true; 28008 } 28009 } 28010 28011 /** 28012 * Reset resolved text alignment. Text alignment will be resolved during a call to 28013 * {@link #onMeasure(int, int)}. 28014 * 28015 * @hide 28016 */ 28017 @TestApi resetResolvedTextAlignment()28018 public void resetResolvedTextAlignment() { 28019 // Reset any previous text alignment resolution 28020 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 28021 // Set to default 28022 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 28023 } 28024 28025 /** 28026 * @return true if text alignment is inherited. 28027 * 28028 * @hide 28029 */ isTextAlignmentInherited()28030 public boolean isTextAlignmentInherited() { 28031 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 28032 } 28033 28034 /** 28035 * @return true if text alignment is resolved. 28036 */ isTextAlignmentResolved()28037 public boolean isTextAlignmentResolved() { 28038 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 28039 } 28040 28041 /** 28042 * Generate a value suitable for use in {@link #setId(int)}. 28043 * This value will not collide with ID values generated at build time by aapt for R.id. 28044 * 28045 * @return a generated ID value 28046 */ generateViewId()28047 public static int generateViewId() { 28048 for (;;) { 28049 final int result = sNextGeneratedId.get(); 28050 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 28051 int newValue = result + 1; 28052 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 28053 if (sNextGeneratedId.compareAndSet(result, newValue)) { 28054 return result; 28055 } 28056 } 28057 } 28058 isViewIdGenerated(int id)28059 private static boolean isViewIdGenerated(int id) { 28060 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 28061 } 28062 28063 /** 28064 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 28065 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 28066 * a normal View or a ViewGroup with 28067 * {@link android.view.ViewGroup#isTransitionGroup()} true. 28068 * @hide 28069 */ captureTransitioningViews(List<View> transitioningViews)28070 public void captureTransitioningViews(List<View> transitioningViews) { 28071 if (getVisibility() == View.VISIBLE) { 28072 transitioningViews.add(this); 28073 } 28074 } 28075 28076 /** 28077 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 28078 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 28079 * @hide 28080 */ findNamedViews(Map<String, View> namedElements)28081 public void findNamedViews(Map<String, View> namedElements) { 28082 if (getVisibility() == VISIBLE || mGhostView != null) { 28083 String transitionName = getTransitionName(); 28084 if (transitionName != null) { 28085 namedElements.put(transitionName, this); 28086 } 28087 } 28088 } 28089 28090 /** 28091 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 28092 * The default implementation does not care the location or event types, but some subclasses 28093 * may use it (such as WebViews). 28094 * @param event The MotionEvent from a mouse 28095 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 28096 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 28097 * @see PointerIcon 28098 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)28099 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 28100 final float x = event.getX(pointerIndex); 28101 final float y = event.getY(pointerIndex); 28102 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 28103 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 28104 } 28105 return mPointerIcon; 28106 } 28107 28108 /** 28109 * Set the pointer icon for the current view. 28110 * Passing {@code null} will restore the pointer icon to its default value. 28111 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 28112 */ setPointerIcon(PointerIcon pointerIcon)28113 public void setPointerIcon(PointerIcon pointerIcon) { 28114 mPointerIcon = pointerIcon; 28115 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 28116 return; 28117 } 28118 try { 28119 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 28120 } catch (RemoteException e) { 28121 } 28122 } 28123 28124 /** 28125 * Gets the pointer icon for the current view. 28126 */ 28127 @InspectableProperty getPointerIcon()28128 public PointerIcon getPointerIcon() { 28129 return mPointerIcon; 28130 } 28131 28132 /** 28133 * Checks pointer capture status. 28134 * 28135 * @return true if the view has pointer capture. 28136 * @see #requestPointerCapture() 28137 * @see #hasPointerCapture() 28138 */ hasPointerCapture()28139 public boolean hasPointerCapture() { 28140 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28141 if (viewRootImpl == null) { 28142 return false; 28143 } 28144 return viewRootImpl.hasPointerCapture(); 28145 } 28146 28147 /** 28148 * Requests pointer capture mode. 28149 * <p> 28150 * When the window has pointer capture, the mouse pointer icon will disappear and will not 28151 * change its position. Enabling pointer capture will change the behavior of input devices in 28152 * the following ways: 28153 * <ul> 28154 * <li>Events from a mouse will be delivered with the source 28155 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be 28156 * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li> 28157 * 28158 * <li>Events from a touchpad will be delivered with the source 28159 * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers 28160 * on the touchpad will be available through {@link MotionEvent#getX(int)} and 28161 * {@link MotionEvent#getY(int)}, and their relative movements are stored in 28162 * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li> 28163 * 28164 * <li>Events from other types of devices, such as touchscreens, will not be affected.</li> 28165 * </ul> 28166 * <p> 28167 * Events captured through pointer capture will be dispatched to 28168 * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an 28169 * {@link OnCapturedPointerListener} is set, and otherwise to 28170 * {@link #onCapturedPointerEvent(MotionEvent)}. 28171 * <p> 28172 * If the window already has pointer capture, this call does nothing. 28173 * <p> 28174 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 28175 * automatically when the window loses focus. 28176 * 28177 * @see #releasePointerCapture() 28178 * @see #hasPointerCapture() 28179 * @see #onPointerCaptureChange(boolean) 28180 */ requestPointerCapture()28181 public void requestPointerCapture() { 28182 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28183 if (viewRootImpl != null) { 28184 viewRootImpl.requestPointerCapture(true); 28185 } 28186 } 28187 28188 28189 /** 28190 * Releases the pointer capture. 28191 * <p> 28192 * If the window does not have pointer capture, this call will do nothing. 28193 * @see #requestPointerCapture() 28194 * @see #hasPointerCapture() 28195 * @see #onPointerCaptureChange(boolean) 28196 */ releasePointerCapture()28197 public void releasePointerCapture() { 28198 final ViewRootImpl viewRootImpl = getViewRootImpl(); 28199 if (viewRootImpl != null) { 28200 viewRootImpl.requestPointerCapture(false); 28201 } 28202 } 28203 28204 /** 28205 * Called when the window has just acquired or lost pointer capture. 28206 * 28207 * @param hasCapture True if the view now has pointerCapture, false otherwise. 28208 */ 28209 @CallSuper onPointerCaptureChange(boolean hasCapture)28210 public void onPointerCaptureChange(boolean hasCapture) { 28211 } 28212 28213 /** 28214 * @see #onPointerCaptureChange 28215 */ dispatchPointerCaptureChanged(boolean hasCapture)28216 public void dispatchPointerCaptureChanged(boolean hasCapture) { 28217 onPointerCaptureChange(hasCapture); 28218 } 28219 28220 /** 28221 * Implement this method to handle captured pointer events 28222 * 28223 * @param event The captured pointer event. 28224 * @return True if the event was handled, false otherwise. 28225 * @see #requestPointerCapture() 28226 */ onCapturedPointerEvent(MotionEvent event)28227 public boolean onCapturedPointerEvent(MotionEvent event) { 28228 return false; 28229 } 28230 28231 /** 28232 * Interface definition for a callback to be invoked when a captured pointer event 28233 * is being dispatched this view. The callback will be invoked before the event is 28234 * given to the view. 28235 */ 28236 public interface OnCapturedPointerListener { 28237 /** 28238 * Called when a captured pointer event is dispatched to a view. 28239 * @param view The view this event has been dispatched to. 28240 * @param event The captured event. 28241 * @return True if the listener has consumed the event, false otherwise. 28242 */ onCapturedPointer(View view, MotionEvent event)28243 boolean onCapturedPointer(View view, MotionEvent event); 28244 } 28245 28246 /** 28247 * Set a listener to receive callbacks when the pointer capture state of a view changes. 28248 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 28249 */ setOnCapturedPointerListener(OnCapturedPointerListener l)28250 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 28251 getListenerInfo().mOnCapturedPointerListener = l; 28252 } 28253 28254 // Properties 28255 // 28256 /** 28257 * A Property wrapper around the <code>alpha</code> functionality handled by the 28258 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 28259 */ 28260 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 28261 @Override 28262 public void setValue(View object, float value) { 28263 object.setAlpha(value); 28264 } 28265 28266 @Override 28267 public Float get(View object) { 28268 return object.getAlpha(); 28269 } 28270 }; 28271 28272 /** 28273 * A Property wrapper around the <code>translationX</code> functionality handled by the 28274 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 28275 */ 28276 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 28277 @Override 28278 public void setValue(View object, float value) { 28279 object.setTranslationX(value); 28280 } 28281 28282 @Override 28283 public Float get(View object) { 28284 return object.getTranslationX(); 28285 } 28286 }; 28287 28288 /** 28289 * A Property wrapper around the <code>translationY</code> functionality handled by the 28290 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 28291 */ 28292 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 28293 @Override 28294 public void setValue(View object, float value) { 28295 object.setTranslationY(value); 28296 } 28297 28298 @Override 28299 public Float get(View object) { 28300 return object.getTranslationY(); 28301 } 28302 }; 28303 28304 /** 28305 * A Property wrapper around the <code>translationZ</code> functionality handled by the 28306 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 28307 */ 28308 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 28309 @Override 28310 public void setValue(View object, float value) { 28311 object.setTranslationZ(value); 28312 } 28313 28314 @Override 28315 public Float get(View object) { 28316 return object.getTranslationZ(); 28317 } 28318 }; 28319 28320 /** 28321 * A Property wrapper around the <code>x</code> functionality handled by the 28322 * {@link View#setX(float)} and {@link View#getX()} methods. 28323 */ 28324 public static final Property<View, Float> X = new FloatProperty<View>("x") { 28325 @Override 28326 public void setValue(View object, float value) { 28327 object.setX(value); 28328 } 28329 28330 @Override 28331 public Float get(View object) { 28332 return object.getX(); 28333 } 28334 }; 28335 28336 /** 28337 * A Property wrapper around the <code>y</code> functionality handled by the 28338 * {@link View#setY(float)} and {@link View#getY()} methods. 28339 */ 28340 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 28341 @Override 28342 public void setValue(View object, float value) { 28343 object.setY(value); 28344 } 28345 28346 @Override 28347 public Float get(View object) { 28348 return object.getY(); 28349 } 28350 }; 28351 28352 /** 28353 * A Property wrapper around the <code>z</code> functionality handled by the 28354 * {@link View#setZ(float)} and {@link View#getZ()} methods. 28355 */ 28356 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 28357 @Override 28358 public void setValue(View object, float value) { 28359 object.setZ(value); 28360 } 28361 28362 @Override 28363 public Float get(View object) { 28364 return object.getZ(); 28365 } 28366 }; 28367 28368 /** 28369 * A Property wrapper around the <code>rotation</code> functionality handled by the 28370 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 28371 */ 28372 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 28373 @Override 28374 public void setValue(View object, float value) { 28375 object.setRotation(value); 28376 } 28377 28378 @Override 28379 public Float get(View object) { 28380 return object.getRotation(); 28381 } 28382 }; 28383 28384 /** 28385 * A Property wrapper around the <code>rotationX</code> functionality handled by the 28386 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 28387 */ 28388 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 28389 @Override 28390 public void setValue(View object, float value) { 28391 object.setRotationX(value); 28392 } 28393 28394 @Override 28395 public Float get(View object) { 28396 return object.getRotationX(); 28397 } 28398 }; 28399 28400 /** 28401 * A Property wrapper around the <code>rotationY</code> functionality handled by the 28402 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 28403 */ 28404 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 28405 @Override 28406 public void setValue(View object, float value) { 28407 object.setRotationY(value); 28408 } 28409 28410 @Override 28411 public Float get(View object) { 28412 return object.getRotationY(); 28413 } 28414 }; 28415 28416 /** 28417 * A Property wrapper around the <code>scaleX</code> functionality handled by the 28418 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 28419 */ 28420 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 28421 @Override 28422 public void setValue(View object, float value) { 28423 object.setScaleX(value); 28424 } 28425 28426 @Override 28427 public Float get(View object) { 28428 return object.getScaleX(); 28429 } 28430 }; 28431 28432 /** 28433 * A Property wrapper around the <code>scaleY</code> functionality handled by the 28434 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 28435 */ 28436 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 28437 @Override 28438 public void setValue(View object, float value) { 28439 object.setScaleY(value); 28440 } 28441 28442 @Override 28443 public Float get(View object) { 28444 return object.getScaleY(); 28445 } 28446 }; 28447 28448 /** 28449 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 28450 * Each MeasureSpec represents a requirement for either the width or the height. 28451 * A MeasureSpec is comprised of a size and a mode. There are three possible 28452 * modes: 28453 * <dl> 28454 * <dt>UNSPECIFIED</dt> 28455 * <dd> 28456 * The parent has not imposed any constraint on the child. It can be whatever size 28457 * it wants. 28458 * </dd> 28459 * 28460 * <dt>EXACTLY</dt> 28461 * <dd> 28462 * The parent has determined an exact size for the child. The child is going to be 28463 * given those bounds regardless of how big it wants to be. 28464 * </dd> 28465 * 28466 * <dt>AT_MOST</dt> 28467 * <dd> 28468 * The child can be as large as it wants up to the specified size. 28469 * </dd> 28470 * </dl> 28471 * 28472 * MeasureSpecs are implemented as ints to reduce object allocation. This class 28473 * is provided to pack and unpack the <size, mode> tuple into the int. 28474 */ 28475 public static class MeasureSpec { 28476 private static final int MODE_SHIFT = 30; 28477 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 28478 28479 /** @hide */ 28480 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 28481 @Retention(RetentionPolicy.SOURCE) 28482 public @interface MeasureSpecMode {} 28483 28484 /** 28485 * Measure specification mode: The parent has not imposed any constraint 28486 * on the child. It can be whatever size it wants. 28487 */ 28488 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 28489 28490 /** 28491 * Measure specification mode: The parent has determined an exact size 28492 * for the child. The child is going to be given those bounds regardless 28493 * of how big it wants to be. 28494 */ 28495 public static final int EXACTLY = 1 << MODE_SHIFT; 28496 28497 /** 28498 * Measure specification mode: The child can be as large as it wants up 28499 * to the specified size. 28500 */ 28501 public static final int AT_MOST = 2 << MODE_SHIFT; 28502 28503 /** 28504 * Creates a measure specification based on the supplied size and mode. 28505 * 28506 * The mode must always be one of the following: 28507 * <ul> 28508 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 28509 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 28510 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 28511 * </ul> 28512 * 28513 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 28514 * implementation was such that the order of arguments did not matter 28515 * and overflow in either value could impact the resulting MeasureSpec. 28516 * {@link android.widget.RelativeLayout} was affected by this bug. 28517 * Apps targeting API levels greater than 17 will get the fixed, more strict 28518 * behavior.</p> 28519 * 28520 * @param size the size of the measure specification 28521 * @param mode the mode of the measure specification 28522 * @return the measure specification based on size and mode 28523 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)28524 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 28525 @MeasureSpecMode int mode) { 28526 if (sUseBrokenMakeMeasureSpec) { 28527 return size + mode; 28528 } else { 28529 return (size & ~MODE_MASK) | (mode & MODE_MASK); 28530 } 28531 } 28532 28533 /** 28534 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 28535 * will automatically get a size of 0. Older apps expect this. 28536 * 28537 * @hide internal use only for compatibility with system widgets and older apps 28538 */ 28539 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)28540 public static int makeSafeMeasureSpec(int size, int mode) { 28541 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 28542 return 0; 28543 } 28544 return makeMeasureSpec(size, mode); 28545 } 28546 28547 /** 28548 * Extracts the mode from the supplied measure specification. 28549 * 28550 * @param measureSpec the measure specification to extract the mode from 28551 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 28552 * {@link android.view.View.MeasureSpec#AT_MOST} or 28553 * {@link android.view.View.MeasureSpec#EXACTLY} 28554 */ 28555 @MeasureSpecMode getMode(int measureSpec)28556 public static int getMode(int measureSpec) { 28557 //noinspection ResourceType 28558 return (measureSpec & MODE_MASK); 28559 } 28560 28561 /** 28562 * Extracts the size from the supplied measure specification. 28563 * 28564 * @param measureSpec the measure specification to extract the size from 28565 * @return the size in pixels defined in the supplied measure specification 28566 */ getSize(int measureSpec)28567 public static int getSize(int measureSpec) { 28568 return (measureSpec & ~MODE_MASK); 28569 } 28570 adjust(int measureSpec, int delta)28571 static int adjust(int measureSpec, int delta) { 28572 final int mode = getMode(measureSpec); 28573 int size = getSize(measureSpec); 28574 if (mode == UNSPECIFIED) { 28575 // No need to adjust size for UNSPECIFIED mode. 28576 return makeMeasureSpec(size, UNSPECIFIED); 28577 } 28578 size += delta; 28579 if (size < 0) { 28580 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 28581 ") spec: " + toString(measureSpec) + " delta: " + delta); 28582 size = 0; 28583 } 28584 return makeMeasureSpec(size, mode); 28585 } 28586 28587 /** 28588 * Returns a String representation of the specified measure 28589 * specification. 28590 * 28591 * @param measureSpec the measure specification to convert to a String 28592 * @return a String with the following format: "MeasureSpec: MODE SIZE" 28593 */ toString(int measureSpec)28594 public static String toString(int measureSpec) { 28595 int mode = getMode(measureSpec); 28596 int size = getSize(measureSpec); 28597 28598 StringBuilder sb = new StringBuilder("MeasureSpec: "); 28599 28600 if (mode == UNSPECIFIED) 28601 sb.append("UNSPECIFIED "); 28602 else if (mode == EXACTLY) 28603 sb.append("EXACTLY "); 28604 else if (mode == AT_MOST) 28605 sb.append("AT_MOST "); 28606 else 28607 sb.append(mode).append(" "); 28608 28609 sb.append(size); 28610 return sb.toString(); 28611 } 28612 } 28613 28614 private final class CheckForLongPress implements Runnable { 28615 private int mOriginalWindowAttachCount; 28616 private float mX; 28617 private float mY; 28618 private boolean mOriginalPressedState; 28619 /** 28620 * The classification of the long click being checked: one of the 28621 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 28622 */ 28623 private int mClassification; 28624 28625 @UnsupportedAppUsage CheckForLongPress()28626 private CheckForLongPress() { 28627 } 28628 28629 @Override run()28630 public void run() { 28631 if ((mOriginalPressedState == isPressed()) && (mParent != null) 28632 && mOriginalWindowAttachCount == mWindowAttachCount) { 28633 recordGestureClassification(mClassification); 28634 if (performLongClick(mX, mY)) { 28635 mHasPerformedLongPress = true; 28636 } 28637 } 28638 } 28639 setAnchor(float x, float y)28640 public void setAnchor(float x, float y) { 28641 mX = x; 28642 mY = y; 28643 } 28644 rememberWindowAttachCount()28645 public void rememberWindowAttachCount() { 28646 mOriginalWindowAttachCount = mWindowAttachCount; 28647 } 28648 rememberPressedState()28649 public void rememberPressedState() { 28650 mOriginalPressedState = isPressed(); 28651 } 28652 setClassification(int classification)28653 public void setClassification(int classification) { 28654 mClassification = classification; 28655 } 28656 } 28657 28658 private final class CheckForTap implements Runnable { 28659 public float x; 28660 public float y; 28661 28662 @Override run()28663 public void run() { 28664 mPrivateFlags &= ~PFLAG_PREPRESSED; 28665 setPressed(true, x, y); 28666 final long delay = 28667 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 28668 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 28669 } 28670 } 28671 28672 private final class PerformClick implements Runnable { 28673 @Override run()28674 public void run() { 28675 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 28676 performClickInternal(); 28677 } 28678 } 28679 28680 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)28681 private void recordGestureClassification(int classification) { 28682 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 28683 return; 28684 } 28685 // To avoid negatively impacting View performance, the latency and displacement metrics 28686 // are omitted. 28687 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 28688 classification); 28689 } 28690 28691 /** 28692 * This method returns a ViewPropertyAnimator object, which can be used to animate 28693 * specific properties on this View. 28694 * 28695 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 28696 */ animate()28697 public ViewPropertyAnimator animate() { 28698 if (mAnimator == null) { 28699 mAnimator = new ViewPropertyAnimator(this); 28700 } 28701 return mAnimator; 28702 } 28703 28704 /** 28705 * Sets the name of the View to be used to identify Views in Transitions. 28706 * Names should be unique in the View hierarchy. 28707 * 28708 * @param transitionName The name of the View to uniquely identify it for Transitions. 28709 */ setTransitionName(String transitionName)28710 public final void setTransitionName(String transitionName) { 28711 mTransitionName = transitionName; 28712 } 28713 28714 /** 28715 * Returns the name of the View to be used to identify Views in Transitions. 28716 * Names should be unique in the View hierarchy. 28717 * 28718 * <p>This returns null if the View has not been given a name.</p> 28719 * 28720 * @return The name used of the View to be used to identify Views in Transitions or null 28721 * if no name has been given. 28722 */ 28723 @ViewDebug.ExportedProperty 28724 @InspectableProperty getTransitionName()28725 public String getTransitionName() { 28726 return mTransitionName; 28727 } 28728 28729 /** 28730 * @hide 28731 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)28732 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 28733 // Do nothing. 28734 } 28735 28736 /** 28737 * Interface definition for a callback to be invoked when a hardware key event is 28738 * dispatched to this view. The callback will be invoked before the key event is 28739 * given to the view. This is only useful for hardware keyboards; a software input 28740 * method has no obligation to trigger this listener. 28741 */ 28742 public interface OnKeyListener { 28743 /** 28744 * Called when a hardware key is dispatched to a view. This allows listeners to 28745 * get a chance to respond before the target view. 28746 * <p>Key presses in software keyboards will generally NOT trigger this method, 28747 * although some may elect to do so in some situations. Do not assume a 28748 * software input method has to be key-based; even if it is, it may use key presses 28749 * in a different way than you expect, so there is no way to reliably catch soft 28750 * input key presses. 28751 * 28752 * @param v The view the key has been dispatched to. 28753 * @param keyCode The code for the physical key that was pressed 28754 * @param event The KeyEvent object containing full information about 28755 * the event. 28756 * @return True if the listener has consumed the event, false otherwise. 28757 */ onKey(View v, int keyCode, KeyEvent event)28758 boolean onKey(View v, int keyCode, KeyEvent event); 28759 } 28760 28761 /** 28762 * Interface definition for a callback to be invoked when a hardware key event hasn't 28763 * been handled by the view hierarchy. 28764 */ 28765 public interface OnUnhandledKeyEventListener { 28766 /** 28767 * Called when a hardware key is dispatched to a view after being unhandled during normal 28768 * {@link KeyEvent} dispatch. 28769 * 28770 * @param v The view the key has been dispatched to. 28771 * @param event The KeyEvent object containing information about the event. 28772 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 28773 */ onUnhandledKeyEvent(View v, KeyEvent event)28774 boolean onUnhandledKeyEvent(View v, KeyEvent event); 28775 } 28776 28777 /** 28778 * Interface definition for a callback to be invoked when a touch event is 28779 * dispatched to this view. The callback will be invoked before the touch 28780 * event is given to the view. 28781 */ 28782 public interface OnTouchListener { 28783 /** 28784 * Called when a touch event is dispatched to a view. This allows listeners to 28785 * get a chance to respond before the target view. 28786 * 28787 * @param v The view the touch event has been dispatched to. 28788 * @param event The MotionEvent object containing full information about 28789 * the event. 28790 * @return True if the listener has consumed the event, false otherwise. 28791 */ onTouch(View v, MotionEvent event)28792 boolean onTouch(View v, MotionEvent event); 28793 } 28794 28795 /** 28796 * Interface definition for a callback to be invoked when a hover event is 28797 * dispatched to this view. The callback will be invoked before the hover 28798 * event is given to the view. 28799 */ 28800 public interface OnHoverListener { 28801 /** 28802 * Called when a hover event is dispatched to a view. This allows listeners to 28803 * get a chance to respond before the target view. 28804 * 28805 * @param v The view the hover event has been dispatched to. 28806 * @param event The MotionEvent object containing full information about 28807 * the event. 28808 * @return True if the listener has consumed the event, false otherwise. 28809 */ onHover(View v, MotionEvent event)28810 boolean onHover(View v, MotionEvent event); 28811 } 28812 28813 /** 28814 * Interface definition for a callback to be invoked when a generic motion event is 28815 * dispatched to this view. The callback will be invoked before the generic motion 28816 * event is given to the view. 28817 */ 28818 public interface OnGenericMotionListener { 28819 /** 28820 * Called when a generic motion event is dispatched to a view. This allows listeners to 28821 * get a chance to respond before the target view. 28822 * 28823 * @param v The view the generic motion event has been dispatched to. 28824 * @param event The MotionEvent object containing full information about 28825 * the event. 28826 * @return True if the listener has consumed the event, false otherwise. 28827 */ onGenericMotion(View v, MotionEvent event)28828 boolean onGenericMotion(View v, MotionEvent event); 28829 } 28830 28831 /** 28832 * Interface definition for a callback to be invoked when a view has been clicked and held. 28833 */ 28834 public interface OnLongClickListener { 28835 /** 28836 * Called when a view has been clicked and held. 28837 * 28838 * @param v The view that was clicked and held. 28839 * 28840 * @return true if the callback consumed the long click, false otherwise. 28841 */ onLongClick(View v)28842 boolean onLongClick(View v); 28843 } 28844 28845 /** 28846 * Interface definition for a callback to be invoked when a drag is being dispatched 28847 * to this view. The callback will be invoked before the hosting view's own 28848 * onDrag(event) method. If the listener wants to fall back to the hosting view's 28849 * onDrag(event) behavior, it should return 'false' from this callback. 28850 * 28851 * <div class="special reference"> 28852 * <h3>Developer Guides</h3> 28853 * <p>For a guide to implementing drag and drop features, read the 28854 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 28855 * </div> 28856 */ 28857 public interface OnDragListener { 28858 /** 28859 * Called when a drag event is dispatched to a view. This allows listeners 28860 * to get a chance to override base View behavior. 28861 * 28862 * @param v The View that received the drag event. 28863 * @param event The {@link android.view.DragEvent} object for the drag event. 28864 * @return {@code true} if the drag event was handled successfully, or {@code false} 28865 * if the drag event was not handled. Note that {@code false} will trigger the View 28866 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 28867 */ onDrag(View v, DragEvent event)28868 boolean onDrag(View v, DragEvent event); 28869 } 28870 28871 /** 28872 * Interface definition for a callback to be invoked when the focus state of 28873 * a view changed. 28874 */ 28875 public interface OnFocusChangeListener { 28876 /** 28877 * Called when the focus state of a view has changed. 28878 * 28879 * @param v The view whose state has changed. 28880 * @param hasFocus The new focus state of v. 28881 */ onFocusChange(View v, boolean hasFocus)28882 void onFocusChange(View v, boolean hasFocus); 28883 } 28884 28885 /** 28886 * Interface definition for a callback to be invoked when a view is clicked. 28887 */ 28888 public interface OnClickListener { 28889 /** 28890 * Called when a view has been clicked. 28891 * 28892 * @param v The view that was clicked. 28893 */ onClick(View v)28894 void onClick(View v); 28895 } 28896 28897 /** 28898 * Interface definition for a callback to be invoked when a view is context clicked. 28899 */ 28900 public interface OnContextClickListener { 28901 /** 28902 * Called when a view is context clicked. 28903 * 28904 * @param v The view that has been context clicked. 28905 * @return true if the callback consumed the context click, false otherwise. 28906 */ onContextClick(View v)28907 boolean onContextClick(View v); 28908 } 28909 28910 /** 28911 * Interface definition for a callback to be invoked when the context menu 28912 * for this view is being built. 28913 */ 28914 public interface OnCreateContextMenuListener { 28915 /** 28916 * Called when the context menu for this view is being built. It is not 28917 * safe to hold onto the menu after this method returns. 28918 * 28919 * @param menu The context menu that is being built 28920 * @param v The view for which the context menu is being built 28921 * @param menuInfo Extra information about the item for which the 28922 * context menu should be shown. This information will vary 28923 * depending on the class of v. 28924 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)28925 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 28926 } 28927 28928 /** 28929 * Interface definition for a callback to be invoked when the status bar changes 28930 * visibility. This reports <strong>global</strong> changes to the system UI 28931 * state, not what the application is requesting. 28932 * 28933 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 28934 * 28935 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 28936 * by setting a {@link OnApplyWindowInsetsListener} on this view. 28937 */ 28938 @Deprecated 28939 public interface OnSystemUiVisibilityChangeListener { 28940 /** 28941 * Called when the status bar changes visibility because of a call to 28942 * {@link View#setSystemUiVisibility(int)}. 28943 * 28944 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 28945 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 28946 * This tells you the <strong>global</strong> state of these UI visibility 28947 * flags, not what your app is currently applying. 28948 */ onSystemUiVisibilityChange(int visibility)28949 public void onSystemUiVisibilityChange(int visibility); 28950 } 28951 28952 /** 28953 * Interface definition for a callback to be invoked when this view is attached 28954 * or detached from its window. 28955 */ 28956 public interface OnAttachStateChangeListener { 28957 /** 28958 * Called when the view is attached to a window. 28959 * @param v The view that was attached 28960 */ onViewAttachedToWindow(View v)28961 public void onViewAttachedToWindow(View v); 28962 /** 28963 * Called when the view is detached from a window. 28964 * @param v The view that was detached 28965 */ onViewDetachedFromWindow(View v)28966 public void onViewDetachedFromWindow(View v); 28967 } 28968 28969 /** 28970 * Listener for applying window insets on a view in a custom way. 28971 * 28972 * <p>Apps may choose to implement this interface if they want to apply custom policy 28973 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 28974 * is set, its 28975 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 28976 * method will be called instead of the View's own 28977 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 28978 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 28979 * the View's normal behavior as part of its own.</p> 28980 */ 28981 public interface OnApplyWindowInsetsListener { 28982 /** 28983 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 28984 * on a View, this listener method will be called instead of the view's own 28985 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 28986 * 28987 * @param v The view applying window insets 28988 * @param insets The insets to apply 28989 * @return The insets supplied, minus any insets that were consumed 28990 */ onApplyWindowInsets(View v, WindowInsets insets)28991 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 28992 } 28993 28994 private final class UnsetPressedState implements Runnable { 28995 @Override run()28996 public void run() { 28997 setPressed(false); 28998 } 28999 } 29000 29001 /** 29002 * When a view becomes invisible checks if autofill considers the view invisible too. This 29003 * happens after the regular removal operation to make sure the operation is finished by the 29004 * time this is called. 29005 */ 29006 private static class VisibilityChangeForAutofillHandler extends Handler { 29007 private final AutofillManager mAfm; 29008 private final View mView; 29009 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)29010 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 29011 @NonNull View view) { 29012 mAfm = afm; 29013 mView = view; 29014 } 29015 29016 @Override handleMessage(Message msg)29017 public void handleMessage(Message msg) { 29018 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 29019 } 29020 } 29021 29022 /** 29023 * Base class for derived classes that want to save and restore their own 29024 * state in {@link android.view.View#onSaveInstanceState()}. 29025 */ 29026 public static class BaseSavedState extends AbsSavedState { 29027 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 29028 static final int IS_AUTOFILLED = 0b10; 29029 static final int AUTOFILL_ID = 0b100; 29030 29031 // Flags that describe what data in this state is valid 29032 int mSavedData; 29033 String mStartActivityRequestWhoSaved; 29034 boolean mIsAutofilled; 29035 boolean mHideHighlight; 29036 int mAutofillViewId; 29037 29038 /** 29039 * Constructor used when reading from a parcel. Reads the state of the superclass. 29040 * 29041 * @param source parcel to read from 29042 */ BaseSavedState(Parcel source)29043 public BaseSavedState(Parcel source) { 29044 this(source, null); 29045 } 29046 29047 /** 29048 * Constructor used when reading from a parcel using a given class loader. 29049 * Reads the state of the superclass. 29050 * 29051 * @param source parcel to read from 29052 * @param loader ClassLoader to use for reading 29053 */ BaseSavedState(Parcel source, ClassLoader loader)29054 public BaseSavedState(Parcel source, ClassLoader loader) { 29055 super(source, loader); 29056 mSavedData = source.readInt(); 29057 mStartActivityRequestWhoSaved = source.readString(); 29058 mIsAutofilled = source.readBoolean(); 29059 mHideHighlight = source.readBoolean(); 29060 mAutofillViewId = source.readInt(); 29061 } 29062 29063 /** 29064 * Constructor called by derived classes when creating their SavedState objects 29065 * 29066 * @param superState The state of the superclass of this view 29067 */ BaseSavedState(Parcelable superState)29068 public BaseSavedState(Parcelable superState) { 29069 super(superState); 29070 } 29071 29072 @Override writeToParcel(Parcel out, int flags)29073 public void writeToParcel(Parcel out, int flags) { 29074 super.writeToParcel(out, flags); 29075 29076 out.writeInt(mSavedData); 29077 out.writeString(mStartActivityRequestWhoSaved); 29078 out.writeBoolean(mIsAutofilled); 29079 out.writeBoolean(mHideHighlight); 29080 out.writeInt(mAutofillViewId); 29081 } 29082 29083 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 29084 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 29085 @Override 29086 public BaseSavedState createFromParcel(Parcel in) { 29087 return new BaseSavedState(in); 29088 } 29089 29090 @Override 29091 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 29092 return new BaseSavedState(in, loader); 29093 } 29094 29095 @Override 29096 public BaseSavedState[] newArray(int size) { 29097 return new BaseSavedState[size]; 29098 } 29099 }; 29100 } 29101 29102 /** 29103 * A set of information given to a view when it is attached to its parent 29104 * window. 29105 */ 29106 final static class AttachInfo { 29107 29108 interface Callbacks { playSoundEffect(int effectId)29109 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)29110 boolean performHapticFeedback(int effectId, boolean always); 29111 } 29112 29113 /** 29114 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 29115 * to a Handler. This class contains the target (View) to invalidate and 29116 * the coordinates of the dirty rectangle. 29117 * 29118 * For performance purposes, this class also implements a pool of up to 29119 * POOL_LIMIT objects that get reused. This reduces memory allocations 29120 * whenever possible. 29121 */ 29122 static class InvalidateInfo { 29123 29124 @UnsupportedAppUsage InvalidateInfo()29125 InvalidateInfo() { 29126 } 29127 29128 private static final int POOL_LIMIT = 10; 29129 29130 private static final SynchronizedPool<InvalidateInfo> sPool = 29131 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 29132 29133 @UnsupportedAppUsage 29134 View target; 29135 29136 @UnsupportedAppUsage 29137 int left; 29138 @UnsupportedAppUsage 29139 int top; 29140 @UnsupportedAppUsage 29141 int right; 29142 @UnsupportedAppUsage 29143 int bottom; 29144 obtain()29145 public static InvalidateInfo obtain() { 29146 InvalidateInfo instance = sPool.acquire(); 29147 return (instance != null) ? instance : new InvalidateInfo(); 29148 } 29149 recycle()29150 public void recycle() { 29151 target = null; 29152 sPool.release(this); 29153 } 29154 } 29155 29156 @UnsupportedAppUsage 29157 final IWindowSession mSession; 29158 29159 @UnsupportedAppUsage 29160 final IWindow mWindow; 29161 29162 final IBinder mWindowToken; 29163 29164 Display mDisplay; 29165 29166 final Callbacks mRootCallbacks; 29167 29168 IWindowId mIWindowId; 29169 WindowId mWindowId; 29170 29171 /** 29172 * The top view of the hierarchy. 29173 */ 29174 View mRootView; 29175 29176 IBinder mPanelParentWindowToken; 29177 29178 boolean mHardwareAccelerated; 29179 boolean mHardwareAccelerationRequested; 29180 ThreadedRenderer mThreadedRenderer; 29181 List<RenderNode> mPendingAnimatingRenderNodes; 29182 29183 /** 29184 * The state of the display to which the window is attached, as reported 29185 * by {@link Display#getState()}. Note that the display state constants 29186 * declared by {@link Display} do not exactly line up with the screen state 29187 * constants declared by {@link View} (there are more display states than 29188 * screen states). 29189 */ 29190 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29191 int mDisplayState = Display.STATE_UNKNOWN; 29192 29193 /** 29194 * Scale factor used by the compatibility mode 29195 */ 29196 @UnsupportedAppUsage 29197 float mApplicationScale; 29198 29199 /** 29200 * Indicates whether the application is in compatibility mode 29201 */ 29202 @UnsupportedAppUsage 29203 boolean mScalingRequired; 29204 29205 /** 29206 * Left position of this view's window 29207 */ 29208 int mWindowLeft; 29209 29210 /** 29211 * Top position of this view's window 29212 */ 29213 int mWindowTop; 29214 29215 /** 29216 * Indicates whether views need to use 32-bit drawing caches 29217 */ 29218 boolean mUse32BitDrawingCache; 29219 29220 /** 29221 * For windows that are full-screen but using insets to layout inside 29222 * of the screen decorations, these are the current insets for the 29223 * content of the window. 29224 */ 29225 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 29226 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 29227 final Rect mContentInsets = new Rect(); 29228 29229 /** 29230 * For windows that are full-screen but using insets to layout inside 29231 * of the screen decorations, these are the current insets for the 29232 * actual visible parts of the window. 29233 */ 29234 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 29235 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 29236 final Rect mVisibleInsets = new Rect(); 29237 29238 /** 29239 * For windows that are full-screen but using insets to layout inside 29240 * of the screen decorations, these are the current insets for the 29241 * stable system windows. 29242 */ 29243 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 29244 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 29245 final Rect mStableInsets = new Rect(); 29246 29247 /** 29248 * Current caption insets to the display coordinate. 29249 */ 29250 final Rect mCaptionInsets = new Rect(); 29251 29252 /** 29253 * In multi-window we force show the system bars. Because we don't want that the surface 29254 * size changes in this mode, we instead have a flag whether the system bars sizes should 29255 * always be consumed, so the app is treated like there are no virtual system bars at all. 29256 */ 29257 boolean mAlwaysConsumeSystemBars; 29258 29259 /** 29260 * The internal insets given by this window. This value is 29261 * supplied by the client (through 29262 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 29263 * be given to the window manager when changed to be used in laying 29264 * out windows behind it. 29265 */ 29266 @UnsupportedAppUsage 29267 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 29268 = new ViewTreeObserver.InternalInsetsInfo(); 29269 29270 /** 29271 * Set to true when mGivenInternalInsets is non-empty. 29272 */ 29273 boolean mHasNonEmptyGivenInternalInsets; 29274 29275 /** 29276 * All views in the window's hierarchy that serve as scroll containers, 29277 * used to determine if the window can be resized or must be panned 29278 * to adjust for a soft input area. 29279 */ 29280 @UnsupportedAppUsage 29281 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 29282 29283 @UnsupportedAppUsage 29284 final KeyEvent.DispatcherState mKeyDispatchState 29285 = new KeyEvent.DispatcherState(); 29286 29287 /** 29288 * Indicates whether the view's window currently has the focus. 29289 */ 29290 @UnsupportedAppUsage 29291 boolean mHasWindowFocus; 29292 29293 /** 29294 * The current visibility of the window. 29295 */ 29296 int mWindowVisibility; 29297 29298 /** 29299 * Indicates the time at which drawing started to occur. 29300 */ 29301 @UnsupportedAppUsage 29302 long mDrawingTime; 29303 29304 /** 29305 * Indicates whether the view's window is currently in touch mode. 29306 */ 29307 @UnsupportedAppUsage 29308 boolean mInTouchMode; 29309 29310 /** 29311 * Indicates whether the view has requested unbuffered input dispatching for the current 29312 * event stream. 29313 */ 29314 boolean mUnbufferedDispatchRequested; 29315 29316 /** 29317 * Indicates that ViewAncestor should trigger a global layout change 29318 * the next time it performs a traversal 29319 */ 29320 @UnsupportedAppUsage 29321 boolean mRecomputeGlobalAttributes; 29322 29323 /** 29324 * Always report new attributes at next traversal. 29325 */ 29326 boolean mForceReportNewAttributes; 29327 29328 /** 29329 * Set during a traveral if any views want to keep the screen on. 29330 */ 29331 @UnsupportedAppUsage 29332 boolean mKeepScreenOn; 29333 29334 /** 29335 * Set during a traveral if the light center needs to be updated. 29336 */ 29337 boolean mNeedsUpdateLightCenter; 29338 29339 /** 29340 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 29341 */ 29342 int mSystemUiVisibility; 29343 29344 /** 29345 * Hack to force certain system UI visibility flags to be cleared. 29346 */ 29347 int mDisabledSystemUiVisibility; 29348 29349 /** 29350 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 29351 * attached. 29352 */ 29353 boolean mHasSystemUiListeners; 29354 29355 /** 29356 * Set if the visibility of any views has changed. 29357 */ 29358 @UnsupportedAppUsage 29359 boolean mViewVisibilityChanged; 29360 29361 /** 29362 * Set to true if a view has been scrolled. 29363 */ 29364 @UnsupportedAppUsage 29365 boolean mViewScrollChanged; 29366 29367 /** 29368 * Set to true if a pointer event is currently being handled. 29369 */ 29370 boolean mHandlingPointerEvent; 29371 29372 /** 29373 * The offset of this view's window when it's on an embedded display that is re-parented 29374 * to another window. 29375 */ 29376 final Point mLocationInParentDisplay = new Point(); 29377 29378 /** 29379 * The screen matrix of this view when it's on a {@link SurfaceControlViewHost} that is 29380 * embedded within a SurfaceView. 29381 */ 29382 Matrix mScreenMatrixInEmbeddedHierarchy; 29383 29384 /** 29385 * Global to the view hierarchy used as a temporary for dealing with 29386 * x/y points in the transparent region computations. 29387 */ 29388 final int[] mTransparentLocation = new int[2]; 29389 29390 /** 29391 * Global to the view hierarchy used as a temporary for dealing with 29392 * x/y points in the ViewGroup.invalidateChild implementation. 29393 */ 29394 final int[] mInvalidateChildLocation = new int[2]; 29395 29396 /** 29397 * Global to the view hierarchy used as a temporary for dealing with 29398 * computing absolute on-screen location. 29399 */ 29400 final int[] mTmpLocation = new int[2]; 29401 29402 /** 29403 * Global to the view hierarchy used as a temporary for dealing with 29404 * x/y location when view is transformed. 29405 */ 29406 final float[] mTmpTransformLocation = new float[2]; 29407 29408 /** 29409 * The view tree observer used to dispatch global events like 29410 * layout, pre-draw, touch mode change, etc. 29411 */ 29412 @UnsupportedAppUsage 29413 final ViewTreeObserver mTreeObserver; 29414 29415 /** 29416 * A Canvas used by the view hierarchy to perform bitmap caching. 29417 */ 29418 Canvas mCanvas; 29419 29420 /** 29421 * The view root impl. 29422 */ 29423 final ViewRootImpl mViewRootImpl; 29424 29425 /** 29426 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 29427 * handler can be used to pump events in the UI events queue. 29428 */ 29429 @UnsupportedAppUsage 29430 final Handler mHandler; 29431 29432 /** 29433 * Temporary for use in computing invalidate rectangles while 29434 * calling up the hierarchy. 29435 */ 29436 final Rect mTmpInvalRect = new Rect(); 29437 29438 /** 29439 * Temporary for use in computing hit areas with transformed views 29440 */ 29441 final RectF mTmpTransformRect = new RectF(); 29442 29443 /** 29444 * Temporary for use in computing hit areas with transformed views 29445 */ 29446 final RectF mTmpTransformRect1 = new RectF(); 29447 29448 /** 29449 * Temporary list of rectanges. 29450 */ 29451 final List<RectF> mTmpRectList = new ArrayList<>(); 29452 29453 /** 29454 * Temporary for use in transforming invalidation rect 29455 */ 29456 final Matrix mTmpMatrix = new Matrix(); 29457 29458 /** 29459 * Temporary for use in transforming invalidation rect 29460 */ 29461 final Transformation mTmpTransformation = new Transformation(); 29462 29463 /** 29464 * Temporary for use in querying outlines from OutlineProviders 29465 */ 29466 final Outline mTmpOutline = new Outline(); 29467 29468 /** 29469 * Temporary list for use in collecting focusable descendents of a view. 29470 */ 29471 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 29472 29473 /** 29474 * The id of the window for accessibility purposes. 29475 */ 29476 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 29477 29478 /** 29479 * Flags related to accessibility processing. 29480 * 29481 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 29482 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 29483 */ 29484 int mAccessibilityFetchFlags; 29485 29486 /** 29487 * The drawable for highlighting accessibility focus. 29488 */ 29489 Drawable mAccessibilityFocusDrawable; 29490 29491 /** 29492 * The drawable for highlighting autofilled views. 29493 * 29494 * @see #isAutofilled() 29495 */ 29496 Drawable mAutofilledDrawable; 29497 29498 /** 29499 * Show where the margins, bounds and layout bounds are for each view. 29500 */ 29501 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 29502 29503 /** 29504 * Point used to compute visible regions. 29505 */ 29506 final Point mPoint = new Point(); 29507 29508 /** 29509 * Used to track which View originated a requestLayout() call, used when 29510 * requestLayout() is called during layout. 29511 */ 29512 View mViewRequestingLayout; 29513 29514 /** 29515 * Used to track the identity of the current drag operation. 29516 */ 29517 IBinder mDragToken; 29518 29519 /** 29520 * The drag shadow surface for the current drag operation. 29521 */ 29522 public Surface mDragSurface; 29523 29524 29525 /** 29526 * The view that currently has a tooltip displayed. 29527 */ 29528 View mTooltipHost; 29529 29530 /** 29531 * The initial structure has been reported so the view is ready to report updates. 29532 */ 29533 boolean mReadyForContentCaptureUpdates; 29534 29535 /** 29536 * Map(keyed by session) of content capture events that need to be notified after the view 29537 * hierarchy is traversed: value is either the view itself for appearead events, or its 29538 * autofill id for disappeared. 29539 */ 29540 SparseArray<ArrayList<Object>> mContentCaptureEvents; 29541 29542 /** 29543 * Cached reference to the {@link ContentCaptureManager}. 29544 */ 29545 ContentCaptureManager mContentCaptureManager; 29546 29547 /** 29548 * Listener used to fit content on window level. 29549 */ 29550 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 29551 29552 /** 29553 * The leash token of this view's parent when it's in an embedded hierarchy that is 29554 * re-parented to another window. 29555 */ 29556 IBinder mLeashedParentToken; 29557 29558 /** 29559 * The accessibility view id of this view's parent when it's in an embedded 29560 * hierarchy that is re-parented to another window. 29561 */ 29562 int mLeashedParentAccessibilityViewId; 29563 29564 /** 29565 * 29566 */ 29567 ScrollCaptureInternal mScrollCaptureInternal; 29568 29569 /** 29570 * Creates a new set of attachment information with the specified 29571 * events handler and thread. 29572 * 29573 * @param handler the events handler the view must use 29574 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)29575 AttachInfo(IWindowSession session, IWindow window, Display display, 29576 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 29577 Context context) { 29578 mSession = session; 29579 mWindow = window; 29580 mWindowToken = window.asBinder(); 29581 mDisplay = display; 29582 mViewRootImpl = viewRootImpl; 29583 mHandler = handler; 29584 mRootCallbacks = effectPlayer; 29585 mTreeObserver = new ViewTreeObserver(context); 29586 } 29587 29588 @Nullable getContentCaptureManager(@onNull Context context)29589 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 29590 if (mContentCaptureManager != null) { 29591 return mContentCaptureManager; 29592 } 29593 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 29594 return mContentCaptureManager; 29595 } 29596 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)29597 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 29598 if (mContentCaptureManager == null) { 29599 return; 29600 } 29601 29602 ArrayList<Object> events = ensureEvents( 29603 mContentCaptureManager.getMainContentCaptureSession()); 29604 events.add(insets); 29605 } 29606 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)29607 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 29608 @NonNull View view, boolean appeared) { 29609 ArrayList<Object> events = ensureEvents(session); 29610 events.add(appeared ? view : view.getAutofillId()); 29611 } 29612 29613 @NonNull ensureEvents(@onNull ContentCaptureSession session)29614 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 29615 if (mContentCaptureEvents == null) { 29616 // Most of the time there will be just one session, so intial capacity is 1 29617 mContentCaptureEvents = new SparseArray<>(1); 29618 } 29619 int sessionId = session.getId(); 29620 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 29621 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 29622 if (events == null) { 29623 events = new ArrayList<>(); 29624 mContentCaptureEvents.put(sessionId, events); 29625 } 29626 29627 return events; 29628 } 29629 29630 @Nullable getScrollCaptureInternal()29631 ScrollCaptureInternal getScrollCaptureInternal() { 29632 if (mScrollCaptureInternal != null) { 29633 mScrollCaptureInternal = new ScrollCaptureInternal(); 29634 } 29635 return mScrollCaptureInternal; 29636 } 29637 getRootSurfaceControl()29638 AttachedSurfaceControl getRootSurfaceControl() { 29639 return mViewRootImpl; 29640 } 29641 dump(String prefix, PrintWriter writer)29642 public void dump(String prefix, PrintWriter writer) { 29643 String innerPrefix = prefix + " "; 29644 writer.println(prefix + "AttachInfo:"); 29645 writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); 29646 writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); 29647 writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); 29648 writer.println(innerPrefix + "mUnbufferedDispatchRequested=" 29649 + mUnbufferedDispatchRequested); 29650 } 29651 } 29652 29653 /** 29654 * <p>ScrollabilityCache holds various fields used by a View when scrolling 29655 * is supported. This avoids keeping too many unused fields in most 29656 * instances of View.</p> 29657 */ 29658 private static class ScrollabilityCache implements Runnable { 29659 29660 /** 29661 * Scrollbars are not visible 29662 */ 29663 public static final int OFF = 0; 29664 29665 /** 29666 * Scrollbars are visible 29667 */ 29668 public static final int ON = 1; 29669 29670 /** 29671 * Scrollbars are fading away 29672 */ 29673 public static final int FADING = 2; 29674 29675 public boolean fadeScrollBars; 29676 29677 public int fadingEdgeLength; 29678 public int scrollBarDefaultDelayBeforeFade; 29679 public int scrollBarFadeDuration; 29680 29681 public int scrollBarSize; 29682 public int scrollBarMinTouchTarget; 29683 @UnsupportedAppUsage 29684 public ScrollBarDrawable scrollBar; 29685 public float[] interpolatorValues; 29686 @UnsupportedAppUsage 29687 public View host; 29688 29689 public final Paint paint; 29690 public final Matrix matrix; 29691 public Shader shader; 29692 29693 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 29694 29695 private static final float[] OPAQUE = { 255 }; 29696 private static final float[] TRANSPARENT = { 0.0f }; 29697 29698 /** 29699 * When fading should start. This time moves into the future every time 29700 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 29701 */ 29702 public long fadeStartTime; 29703 29704 29705 /** 29706 * The current state of the scrollbars: ON, OFF, or FADING 29707 */ 29708 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29709 public int state = OFF; 29710 29711 private int mLastColor; 29712 29713 public final Rect mScrollBarBounds = new Rect(); 29714 public final Rect mScrollBarTouchBounds = new Rect(); 29715 29716 public static final int NOT_DRAGGING = 0; 29717 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 29718 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 29719 public int mScrollBarDraggingState = NOT_DRAGGING; 29720 29721 public float mScrollBarDraggingPos = 0; 29722 ScrollabilityCache(ViewConfiguration configuration, View host)29723 public ScrollabilityCache(ViewConfiguration configuration, View host) { 29724 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 29725 scrollBarSize = configuration.getScaledScrollBarSize(); 29726 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 29727 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 29728 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 29729 29730 paint = new Paint(); 29731 matrix = new Matrix(); 29732 // use use a height of 1, and then wack the matrix each time we 29733 // actually use it. 29734 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 29735 paint.setShader(shader); 29736 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 29737 29738 this.host = host; 29739 } 29740 setFadeColor(int color)29741 public void setFadeColor(int color) { 29742 if (color != mLastColor) { 29743 mLastColor = color; 29744 29745 if (color != 0) { 29746 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 29747 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 29748 paint.setShader(shader); 29749 // Restore the default transfer mode (src_over) 29750 paint.setXfermode(null); 29751 } else { 29752 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 29753 paint.setShader(shader); 29754 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 29755 } 29756 } 29757 } 29758 run()29759 public void run() { 29760 long now = AnimationUtils.currentAnimationTimeMillis(); 29761 if (now >= fadeStartTime) { 29762 29763 // the animation fades the scrollbars out by changing 29764 // the opacity (alpha) from fully opaque to fully 29765 // transparent 29766 int nextFrame = (int) now; 29767 int framesCount = 0; 29768 29769 Interpolator interpolator = scrollBarInterpolator; 29770 29771 // Start opaque 29772 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 29773 29774 // End transparent 29775 nextFrame += scrollBarFadeDuration; 29776 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 29777 29778 state = FADING; 29779 29780 // Kick off the fade animation 29781 host.invalidate(true); 29782 } 29783 } 29784 } 29785 29786 private class SendAccessibilityEventThrottle implements Runnable { 29787 public volatile boolean mIsPending; 29788 private AccessibilityEvent mAccessibilityEvent; 29789 post(AccessibilityEvent accessibilityEvent)29790 public void post(AccessibilityEvent accessibilityEvent) { 29791 updateWithAccessibilityEvent(accessibilityEvent); 29792 if (!mIsPending) { 29793 mIsPending = true; 29794 postDelayed(this, 29795 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 29796 } 29797 } 29798 29799 @Override run()29800 public void run() { 29801 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 29802 requestParentSendAccessibilityEvent(mAccessibilityEvent); 29803 } 29804 reset(); 29805 } 29806 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)29807 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 29808 mAccessibilityEvent = accessibilityEvent; 29809 } 29810 reset()29811 public void reset() { 29812 mIsPending = false; 29813 mAccessibilityEvent = null; 29814 } 29815 29816 } 29817 29818 /** 29819 * Resuable callback for sending 29820 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 29821 */ 29822 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 29823 public int mDeltaX; 29824 public int mDeltaY; 29825 29826 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)29827 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 29828 super.updateWithAccessibilityEvent(accessibilityEvent); 29829 mDeltaX += accessibilityEvent.getScrollDeltaX(); 29830 mDeltaY += accessibilityEvent.getScrollDeltaY(); 29831 accessibilityEvent.setScrollDeltaX(mDeltaX); 29832 accessibilityEvent.setScrollDeltaY(mDeltaY); 29833 } 29834 29835 @Override reset()29836 public void reset() { 29837 super.reset(); 29838 mDeltaX = 0; 29839 mDeltaY = 0; 29840 } 29841 } 29842 /** 29843 * Remove the pending callback for sending a throttled accessibility event. 29844 */ 29845 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)29846 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 29847 if (callback == null || !callback.mIsPending) return; 29848 removeCallbacks(callback); 29849 callback.reset(); 29850 } 29851 29852 /** 29853 * <p> 29854 * This class represents a delegate that can be registered in a {@link View} 29855 * to enhance accessibility support via composition rather via inheritance. 29856 * It is specifically targeted to widget developers that extend basic View 29857 * classes i.e. classes in package android.view, that would like their 29858 * applications to be backwards compatible. 29859 * </p> 29860 * <div class="special reference"> 29861 * <h3>Developer Guides</h3> 29862 * <p>For more information about making applications accessible, read the 29863 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 29864 * developer guide.</p> 29865 * </div> 29866 * <p> 29867 * A scenario in which a developer would like to use an accessibility delegate 29868 * is overriding a method introduced in a later API version than the minimal API 29869 * version supported by the application. For example, the method 29870 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 29871 * in API version 4 when the accessibility APIs were first introduced. If a 29872 * developer would like their application to run on API version 4 devices (assuming 29873 * all other APIs used by the application are version 4 or lower) and take advantage 29874 * of this method, instead of overriding the method which would break the application's 29875 * backwards compatibility, they can override the corresponding method in this 29876 * delegate and register the delegate in the target View if the API version of 29877 * the system is high enough, i.e. the API version is the same as or higher than the API 29878 * version that introduced 29879 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 29880 * </p> 29881 * <p> 29882 * Here is an example implementation: 29883 * </p> 29884 * <code><pre><p> 29885 * if (Build.VERSION.SDK_INT >= 14) { 29886 * // If the API version is equal of higher than the version in 29887 * // which onInitializeAccessibilityNodeInfo was introduced we 29888 * // register a delegate with a customized implementation. 29889 * View view = findViewById(R.id.view_id); 29890 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 29891 * public void onInitializeAccessibilityNodeInfo(View host, 29892 * AccessibilityNodeInfo info) { 29893 * // Let the default implementation populate the info. 29894 * super.onInitializeAccessibilityNodeInfo(host, info); 29895 * // Set some other information. 29896 * info.setEnabled(host.isEnabled()); 29897 * } 29898 * }); 29899 * } 29900 * </code></pre></p> 29901 * <p> 29902 * This delegate contains methods that correspond to the accessibility methods 29903 * in View. If a delegate has been specified the implementation in View hands 29904 * off handling to the corresponding method in this delegate. The default 29905 * implementation the delegate methods behaves exactly as the corresponding 29906 * method in View for the case of no accessibility delegate been set. Hence, 29907 * to customize the behavior of a View method, clients can override only the 29908 * corresponding delegate method without altering the behavior of the rest 29909 * accessibility related methods of the host view. 29910 * </p> 29911 * <p> 29912 * <strong>Note:</strong> On platform versions prior to 29913 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 29914 * views in the {@code android.widget.*} package are called <i>before</i> 29915 * host methods. This prevents certain properties such as class name from 29916 * being modified by overriding 29917 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 29918 * as any changes will be overwritten by the host class. 29919 * <p> 29920 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 29921 * methods are called <i>after</i> host methods, which all properties to be 29922 * modified without being overwritten by the host class. 29923 */ 29924 public static class AccessibilityDelegate { 29925 29926 /** 29927 * Sends an accessibility event of the given type. If accessibility is not 29928 * enabled this method has no effect. 29929 * <p> 29930 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 29931 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 29932 * been set. 29933 * </p> 29934 * 29935 * @param host The View hosting the delegate. 29936 * @param eventType The type of the event to send. 29937 * 29938 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 29939 */ sendAccessibilityEvent(View host, int eventType)29940 public void sendAccessibilityEvent(View host, int eventType) { 29941 host.sendAccessibilityEventInternal(eventType); 29942 } 29943 29944 /** 29945 * Performs the specified accessibility action on the view. For 29946 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 29947 * <p> 29948 * The default implementation behaves as 29949 * {@link View#performAccessibilityAction(int, Bundle) 29950 * View#performAccessibilityAction(int, Bundle)} for the case of 29951 * no accessibility delegate been set. 29952 * </p> 29953 * 29954 * @param action The action to perform. 29955 * @return Whether the action was performed. 29956 * 29957 * @see View#performAccessibilityAction(int, Bundle) 29958 * View#performAccessibilityAction(int, Bundle) 29959 */ performAccessibilityAction(View host, int action, Bundle args)29960 public boolean performAccessibilityAction(View host, int action, Bundle args) { 29961 return host.performAccessibilityActionInternal(action, args); 29962 } 29963 29964 /** 29965 * Sends an accessibility event. This method behaves exactly as 29966 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 29967 * empty {@link AccessibilityEvent} and does not perform a check whether 29968 * accessibility is enabled. 29969 * <p> 29970 * The default implementation behaves as 29971 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29972 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 29973 * the case of no accessibility delegate been set. 29974 * </p> 29975 * 29976 * @param host The View hosting the delegate. 29977 * @param event The event to send. 29978 * 29979 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29980 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29981 */ sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)29982 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 29983 host.sendAccessibilityEventUncheckedInternal(event); 29984 } 29985 29986 /** 29987 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 29988 * to its children for adding their text content to the event. 29989 * <p> 29990 * The default implementation behaves as 29991 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29992 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 29993 * the case of no accessibility delegate been set. 29994 * </p> 29995 * 29996 * @param host The View hosting the delegate. 29997 * @param event The event. 29998 * @return True if the event population was completed. 29999 * 30000 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30001 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 30002 */ dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)30003 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 30004 return host.dispatchPopulateAccessibilityEventInternal(event); 30005 } 30006 30007 /** 30008 * Gives a chance to the host View to populate the accessibility event with its 30009 * text content. 30010 * <p> 30011 * The default implementation behaves as 30012 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 30013 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 30014 * the case of no accessibility delegate been set. 30015 * </p> 30016 * 30017 * @param host The View hosting the delegate. 30018 * @param event The accessibility event which to populate. 30019 * 30020 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 30021 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 30022 */ onPopulateAccessibilityEvent(View host, AccessibilityEvent event)30023 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 30024 host.onPopulateAccessibilityEventInternal(event); 30025 } 30026 30027 /** 30028 * Initializes an {@link AccessibilityEvent} with information about the 30029 * the host View which is the event source. 30030 * <p> 30031 * The default implementation behaves as 30032 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 30033 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 30034 * the case of no accessibility delegate been set. 30035 * </p> 30036 * 30037 * @param host The View hosting the delegate. 30038 * @param event The event to initialize. 30039 * 30040 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 30041 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 30042 */ onInitializeAccessibilityEvent(View host, AccessibilityEvent event)30043 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 30044 host.onInitializeAccessibilityEventInternal(event); 30045 } 30046 30047 /** 30048 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 30049 * <p> 30050 * The default implementation behaves as 30051 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30052 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 30053 * the case of no accessibility delegate been set. 30054 * </p> 30055 * 30056 * @param host The View hosting the delegate. 30057 * @param info The instance to initialize. 30058 * 30059 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30060 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 30061 */ onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)30062 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 30063 host.onInitializeAccessibilityNodeInfoInternal(info); 30064 } 30065 30066 /** 30067 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 30068 * additional data. 30069 * <p> 30070 * This method only needs to be implemented if the View offers to provide additional data. 30071 * </p> 30072 * <p> 30073 * The default implementation behaves as 30074 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 30075 * for the case where no accessibility delegate is set. 30076 * </p> 30077 * 30078 * @param host The View hosting the delegate. Never {@code null}. 30079 * @param info The info to which to add the extra data. Never {@code null}. 30080 * @param extraDataKey A key specifying the type of extra data to add to the info. The 30081 * extra data should be added to the {@link Bundle} returned by 30082 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 30083 * {@code null}. 30084 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 30085 * May be {@code null} if the if the service provided no arguments. 30086 * 30087 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 30088 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)30089 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 30090 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 30091 @Nullable Bundle arguments) { 30092 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 30093 } 30094 30095 /** 30096 * Called when a child of the host View has requested sending an 30097 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 30098 * to augment the event. 30099 * <p> 30100 * The default implementation behaves as 30101 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30102 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 30103 * the case of no accessibility delegate been set. 30104 * </p> 30105 * 30106 * @param host The View hosting the delegate. 30107 * @param child The child which requests sending the event. 30108 * @param event The event to be sent. 30109 * @return True if the event should be sent 30110 * 30111 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30112 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 30113 */ onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)30114 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 30115 AccessibilityEvent event) { 30116 return host.onRequestSendAccessibilityEventInternal(child, event); 30117 } 30118 30119 /** 30120 * Gets the provider for managing a virtual view hierarchy rooted at this View 30121 * and reported to {@link android.accessibilityservice.AccessibilityService}s 30122 * that explore the window content. 30123 * <p> 30124 * The default implementation behaves as 30125 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 30126 * the case of no accessibility delegate been set. 30127 * </p> 30128 * 30129 * @return The provider. 30130 * 30131 * @see AccessibilityNodeProvider 30132 */ getAccessibilityNodeProvider(View host)30133 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 30134 return null; 30135 } 30136 30137 /** 30138 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 30139 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 30140 * This method is responsible for obtaining an accessibility node info from a 30141 * pool of reusable instances and calling 30142 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 30143 * view to initialize the former. 30144 * <p> 30145 * <strong>Note:</strong> The client is responsible for recycling the obtained 30146 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 30147 * creation. 30148 * </p> 30149 * <p> 30150 * The default implementation behaves as 30151 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 30152 * the case of no accessibility delegate been set. 30153 * </p> 30154 * @return A populated {@link AccessibilityNodeInfo}. 30155 * 30156 * @see AccessibilityNodeInfo 30157 * 30158 * @hide 30159 */ 30160 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) createAccessibilityNodeInfo(View host)30161 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 30162 return host.createAccessibilityNodeInfoInternal(); 30163 } 30164 } 30165 30166 private static class MatchIdPredicate implements Predicate<View> { 30167 public int mId; 30168 30169 @Override test(View view)30170 public boolean test(View view) { 30171 return (view.mID == mId); 30172 } 30173 } 30174 30175 private static class MatchLabelForPredicate implements Predicate<View> { 30176 private int mLabeledId; 30177 30178 @Override test(View view)30179 public boolean test(View view) { 30180 return (view.mLabelForId == mLabeledId); 30181 } 30182 } 30183 30184 30185 /** 30186 * Returns the current scroll capture hint for this view. 30187 * 30188 * @return the current scroll capture hint 30189 */ 30190 @ScrollCaptureHint getScrollCaptureHint()30191 public int getScrollCaptureHint() { 30192 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 30193 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 30194 } 30195 30196 /** 30197 * Sets the scroll capture hint for this View. These flags affect the search for a potential 30198 * scroll capture targets. 30199 * 30200 * @param hint the scrollCaptureHint flags value to set 30201 */ setScrollCaptureHint(@crollCaptureHint int hint)30202 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 30203 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 30204 // Since include/exclude are mutually exclusive, exclude takes precedence. 30205 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 30206 hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; 30207 } 30208 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 30209 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 30210 } 30211 30212 /** 30213 * Sets the callback to receive scroll capture requests. This component is the adapter between 30214 * the scroll capture API and application UI code. If no callback is set, the system may provide 30215 * an implementation. Any value provided here will take precedence over a system version. 30216 * <p> 30217 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 30218 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 30219 * <p> 30220 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 30221 * setting a custom callback to help ensure it is selected as the target. 30222 * 30223 * @param callback the new callback to assign 30224 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)30225 public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 30226 getListenerInfo().mScrollCaptureCallback = callback; 30227 } 30228 30229 /** {@hide} */ 30230 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)30231 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 30232 @NonNull Point windowOffset) { 30233 if (mAttachInfo == null) { 30234 return null; 30235 } 30236 if (mAttachInfo.mScrollCaptureInternal == null) { 30237 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 30238 } 30239 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 30240 windowOffset); 30241 } 30242 30243 /** 30244 * Dispatch a scroll capture search request down the view hierarchy. 30245 * 30246 * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to 30247 * the parent 30248 * @param windowOffset the offset of this view within the window 30249 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 30250 * results.accept} may be called zero or more times on the calling 30251 * thread before onScrollCaptureSearch returns 30252 */ dispatchScrollCaptureSearch( @onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)30253 public void dispatchScrollCaptureSearch( 30254 @NonNull Rect localVisibleRect, @NonNull Point windowOffset, 30255 @NonNull Consumer<ScrollCaptureTarget> targets) { 30256 onScrollCaptureSearch(localVisibleRect, windowOffset, targets); 30257 } 30258 30259 /** 30260 * Called when scroll capture is requested, to search for appropriate content to scroll. If 30261 * applicable, this view adds itself to the provided list for consideration, subject to the 30262 * flags set by {@link #setScrollCaptureHint}. 30263 * 30264 * @param localVisibleRect the local visible rect of this view 30265 * @param windowOffset the offset of localVisibleRect within the window 30266 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 30267 * results.accept} may be called zero or more times on the calling 30268 * thread before onScrollCaptureSearch returns 30269 * @throws IllegalStateException if this view is not attached to a window 30270 */ onScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)30271 public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, 30272 @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { 30273 int hint = getScrollCaptureHint(); 30274 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 30275 return; 30276 } 30277 boolean rectIsVisible = true; 30278 30279 // Apply clipBounds if present. 30280 if (mClipBounds != null) { 30281 rectIsVisible = localVisibleRect.intersect(mClipBounds); 30282 } 30283 if (!rectIsVisible) { 30284 return; 30285 } 30286 30287 // Get a callback provided by the framework, library or application. 30288 ScrollCaptureCallback callback = 30289 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 30290 30291 // Try framework support for standard scrolling containers. 30292 if (callback == null) { 30293 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 30294 } 30295 30296 // If found, then add it to the list. 30297 if (callback != null) { 30298 // Add to the list for consideration 30299 Point offset = new Point(windowOffset.x, windowOffset.y); 30300 Rect rect = new Rect(localVisibleRect); 30301 targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); 30302 } 30303 } 30304 30305 /** 30306 * Dump all private flags in readable format, useful for documentation and 30307 * consistency checking. 30308 */ dumpFlags()30309 private static void dumpFlags() { 30310 final HashMap<String, String> found = Maps.newHashMap(); 30311 try { 30312 for (Field field : View.class.getDeclaredFields()) { 30313 final int modifiers = field.getModifiers(); 30314 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 30315 if (field.getType().equals(int.class)) { 30316 final int value = field.getInt(null); 30317 dumpFlag(found, field.getName(), value); 30318 } else if (field.getType().equals(int[].class)) { 30319 final int[] values = (int[]) field.get(null); 30320 for (int i = 0; i < values.length; i++) { 30321 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 30322 } 30323 } 30324 } 30325 } 30326 } catch (IllegalAccessException e) { 30327 throw new RuntimeException(e); 30328 } 30329 30330 final ArrayList<String> keys = Lists.newArrayList(); 30331 keys.addAll(found.keySet()); 30332 Collections.sort(keys); 30333 for (String key : keys) { 30334 Log.d(VIEW_LOG_TAG, found.get(key)); 30335 } 30336 } 30337 dumpFlag(HashMap<String, String> found, String name, int value)30338 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 30339 // Sort flags by prefix, then by bits, always keeping unique keys 30340 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 30341 final int prefix = name.indexOf('_'); 30342 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 30343 final String output = bits + " " + name; 30344 found.put(key, output); 30345 } 30346 30347 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)30348 public void encode(@NonNull ViewHierarchyEncoder stream) { 30349 stream.beginObject(this); 30350 encodeProperties(stream); 30351 stream.endObject(); 30352 } 30353 30354 /** {@hide} */ 30355 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)30356 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 30357 Object resolveId = ViewDebug.resolveId(getContext(), mID); 30358 if (resolveId instanceof String) { 30359 stream.addProperty("id", (String) resolveId); 30360 } else { 30361 stream.addProperty("id", mID); 30362 } 30363 30364 stream.addProperty("misc:transformation.alpha", 30365 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 30366 stream.addProperty("misc:transitionName", getTransitionName()); 30367 30368 // layout 30369 stream.addProperty("layout:left", mLeft); 30370 stream.addProperty("layout:right", mRight); 30371 stream.addProperty("layout:top", mTop); 30372 stream.addProperty("layout:bottom", mBottom); 30373 stream.addProperty("layout:width", getWidth()); 30374 stream.addProperty("layout:height", getHeight()); 30375 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 30376 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 30377 stream.addProperty("layout:hasTransientState", hasTransientState()); 30378 stream.addProperty("layout:baseline", getBaseline()); 30379 30380 // layout params 30381 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 30382 if (layoutParams != null) { 30383 stream.addPropertyKey("layoutParams"); 30384 layoutParams.encode(stream); 30385 } 30386 30387 // scrolling 30388 stream.addProperty("scrolling:scrollX", mScrollX); 30389 stream.addProperty("scrolling:scrollY", mScrollY); 30390 30391 // padding 30392 stream.addProperty("padding:paddingLeft", mPaddingLeft); 30393 stream.addProperty("padding:paddingRight", mPaddingRight); 30394 stream.addProperty("padding:paddingTop", mPaddingTop); 30395 stream.addProperty("padding:paddingBottom", mPaddingBottom); 30396 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 30397 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 30398 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 30399 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 30400 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 30401 30402 // measurement 30403 stream.addProperty("measurement:minHeight", mMinHeight); 30404 stream.addProperty("measurement:minWidth", mMinWidth); 30405 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 30406 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 30407 30408 // drawing 30409 stream.addProperty("drawing:elevation", getElevation()); 30410 stream.addProperty("drawing:translationX", getTranslationX()); 30411 stream.addProperty("drawing:translationY", getTranslationY()); 30412 stream.addProperty("drawing:translationZ", getTranslationZ()); 30413 stream.addProperty("drawing:rotation", getRotation()); 30414 stream.addProperty("drawing:rotationX", getRotationX()); 30415 stream.addProperty("drawing:rotationY", getRotationY()); 30416 stream.addProperty("drawing:scaleX", getScaleX()); 30417 stream.addProperty("drawing:scaleY", getScaleY()); 30418 stream.addProperty("drawing:pivotX", getPivotX()); 30419 stream.addProperty("drawing:pivotY", getPivotY()); 30420 stream.addProperty("drawing:clipBounds", 30421 mClipBounds == null ? null : mClipBounds.toString()); 30422 stream.addProperty("drawing:opaque", isOpaque()); 30423 stream.addProperty("drawing:alpha", getAlpha()); 30424 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 30425 stream.addProperty("drawing:shadow", hasShadow()); 30426 stream.addProperty("drawing:solidColor", getSolidColor()); 30427 stream.addProperty("drawing:layerType", mLayerType); 30428 stream.addProperty("drawing:willNotDraw", willNotDraw()); 30429 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 30430 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 30431 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 30432 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 30433 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 30434 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 30435 30436 // focus 30437 stream.addProperty("focus:hasFocus", hasFocus()); 30438 stream.addProperty("focus:isFocused", isFocused()); 30439 stream.addProperty("focus:focusable", getFocusable()); 30440 stream.addProperty("focus:isFocusable", isFocusable()); 30441 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 30442 30443 stream.addProperty("misc:clickable", isClickable()); 30444 stream.addProperty("misc:pressed", isPressed()); 30445 stream.addProperty("misc:selected", isSelected()); 30446 stream.addProperty("misc:touchMode", isInTouchMode()); 30447 stream.addProperty("misc:hovered", isHovered()); 30448 stream.addProperty("misc:activated", isActivated()); 30449 30450 stream.addProperty("misc:visibility", getVisibility()); 30451 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 30452 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 30453 30454 stream.addProperty("misc:enabled", isEnabled()); 30455 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 30456 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 30457 30458 // theme attributes 30459 Resources.Theme theme = getContext().getTheme(); 30460 if (theme != null) { 30461 stream.addPropertyKey("theme"); 30462 theme.encode(stream); 30463 } 30464 30465 // view attribute information 30466 int n = mAttributes != null ? mAttributes.length : 0; 30467 stream.addProperty("meta:__attrCount__", n/2); 30468 for (int i = 0; i < n; i += 2) { 30469 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 30470 } 30471 30472 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 30473 30474 // text 30475 stream.addProperty("text:textDirection", getTextDirection()); 30476 stream.addProperty("text:textAlignment", getTextAlignment()); 30477 30478 // accessibility 30479 CharSequence contentDescription = getContentDescription(); 30480 stream.addUserProperty("accessibility:contentDescription", 30481 contentDescription == null ? "" : contentDescription.toString()); 30482 stream.addProperty("accessibility:labelFor", getLabelFor()); 30483 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 30484 } 30485 30486 /** 30487 * Determine if this view is rendered on a round wearable device and is the main view 30488 * on the screen. 30489 */ shouldDrawRoundScrollbar()30490 boolean shouldDrawRoundScrollbar() { 30491 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 30492 return false; 30493 } 30494 30495 final View rootView = getRootView(); 30496 final WindowInsets insets = getRootWindowInsets(); 30497 30498 int height = getHeight(); 30499 int width = getWidth(); 30500 int displayHeight = rootView.getHeight(); 30501 int displayWidth = rootView.getWidth(); 30502 30503 if (height != displayHeight || width != displayWidth) { 30504 return false; 30505 } 30506 30507 getLocationInWindow(mAttachInfo.mTmpLocation); 30508 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 30509 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 30510 } 30511 30512 /** 30513 * Sets the tooltip text which will be displayed in a small popup next to the view. 30514 * <p> 30515 * The tooltip will be displayed: 30516 * <ul> 30517 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 30518 * menu). </li> 30519 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 30520 * </ul> 30521 * <p> 30522 * <strong>Note:</strong> Do not override this method, as it will have no 30523 * effect on the text displayed in the tooltip. 30524 * 30525 * @param tooltipText the tooltip text, or null if no tooltip is required 30526 * @see #getTooltipText() 30527 * @attr ref android.R.styleable#View_tooltipText 30528 */ setTooltipText(@ullable CharSequence tooltipText)30529 public void setTooltipText(@Nullable CharSequence tooltipText) { 30530 if (TextUtils.isEmpty(tooltipText)) { 30531 setFlags(0, TOOLTIP); 30532 hideTooltip(); 30533 mTooltipInfo = null; 30534 } else { 30535 setFlags(TOOLTIP, TOOLTIP); 30536 if (mTooltipInfo == null) { 30537 mTooltipInfo = new TooltipInfo(); 30538 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 30539 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 30540 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 30541 mTooltipInfo.clearAnchorPos(); 30542 } 30543 mTooltipInfo.mTooltipText = tooltipText; 30544 } 30545 } 30546 30547 /** 30548 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 30549 */ 30550 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)30551 public void setTooltip(@Nullable CharSequence tooltipText) { 30552 setTooltipText(tooltipText); 30553 } 30554 30555 /** 30556 * Returns the view's tooltip text. 30557 * 30558 * <strong>Note:</strong> Do not override this method, as it will have no 30559 * effect on the text displayed in the tooltip. You must call 30560 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 30561 * 30562 * @return the tooltip text 30563 * @see #setTooltipText(CharSequence) 30564 * @attr ref android.R.styleable#View_tooltipText 30565 */ 30566 @InspectableProperty 30567 @Nullable getTooltipText()30568 public CharSequence getTooltipText() { 30569 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 30570 } 30571 30572 /** 30573 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 30574 */ 30575 @Nullable getTooltip()30576 public CharSequence getTooltip() { 30577 return getTooltipText(); 30578 } 30579 showTooltip(int x, int y, boolean fromLongClick)30580 private boolean showTooltip(int x, int y, boolean fromLongClick) { 30581 if (mAttachInfo == null || mTooltipInfo == null) { 30582 return false; 30583 } 30584 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 30585 return false; 30586 } 30587 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 30588 return false; 30589 } 30590 hideTooltip(); 30591 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 30592 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 30593 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 30594 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 30595 mAttachInfo.mTooltipHost = this; 30596 // The available accessibility actions have changed 30597 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 30598 return true; 30599 } 30600 30601 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hideTooltip()30602 void hideTooltip() { 30603 if (mTooltipInfo == null) { 30604 return; 30605 } 30606 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30607 if (mTooltipInfo.mTooltipPopup == null) { 30608 return; 30609 } 30610 mTooltipInfo.mTooltipPopup.hide(); 30611 mTooltipInfo.mTooltipPopup = null; 30612 mTooltipInfo.mTooltipFromLongClick = false; 30613 mTooltipInfo.clearAnchorPos(); 30614 if (mAttachInfo != null) { 30615 mAttachInfo.mTooltipHost = null; 30616 } 30617 // The available accessibility actions have changed 30618 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 30619 } 30620 showLongClickTooltip(int x, int y)30621 private boolean showLongClickTooltip(int x, int y) { 30622 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30623 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30624 return showTooltip(x, y, true); 30625 } 30626 showHoverTooltip()30627 private boolean showHoverTooltip() { 30628 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 30629 } 30630 dispatchTooltipHoverEvent(MotionEvent event)30631 boolean dispatchTooltipHoverEvent(MotionEvent event) { 30632 if (mTooltipInfo == null) { 30633 return false; 30634 } 30635 switch(event.getAction()) { 30636 case MotionEvent.ACTION_HOVER_MOVE: 30637 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 30638 break; 30639 } 30640 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 30641 if (mTooltipInfo.mTooltipPopup == null) { 30642 // Schedule showing the tooltip after a timeout. 30643 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30644 postDelayed(mTooltipInfo.mShowTooltipRunnable, 30645 ViewConfiguration.getHoverTooltipShowTimeout()); 30646 } 30647 30648 // Hide hover-triggered tooltip after a period of inactivity. 30649 // Match the timeout used by NativeInputManager to hide the mouse pointer 30650 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 30651 final int timeout; 30652 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 30653 == SYSTEM_UI_FLAG_LOW_PROFILE) { 30654 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 30655 } else { 30656 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 30657 } 30658 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30659 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 30660 } 30661 return true; 30662 30663 case MotionEvent.ACTION_HOVER_EXIT: 30664 mTooltipInfo.clearAnchorPos(); 30665 if (!mTooltipInfo.mTooltipFromLongClick) { 30666 hideTooltip(); 30667 } 30668 break; 30669 } 30670 return false; 30671 } 30672 handleTooltipKey(KeyEvent event)30673 void handleTooltipKey(KeyEvent event) { 30674 switch (event.getAction()) { 30675 case KeyEvent.ACTION_DOWN: 30676 if (event.getRepeatCount() == 0) { 30677 hideTooltip(); 30678 } 30679 break; 30680 30681 case KeyEvent.ACTION_UP: 30682 handleTooltipUp(); 30683 break; 30684 } 30685 } 30686 handleTooltipUp()30687 private void handleTooltipUp() { 30688 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 30689 return; 30690 } 30691 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30692 postDelayed(mTooltipInfo.mHideTooltipRunnable, 30693 ViewConfiguration.getLongPressTooltipHideTimeout()); 30694 } 30695 getFocusableAttribute(TypedArray attributes)30696 private int getFocusableAttribute(TypedArray attributes) { 30697 TypedValue val = new TypedValue(); 30698 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 30699 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 30700 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 30701 } else { 30702 return val.data; 30703 } 30704 } else { 30705 return FOCUSABLE_AUTO; 30706 } 30707 } 30708 30709 /** 30710 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 30711 * is not showing. 30712 * @hide 30713 */ 30714 @TestApi getTooltipView()30715 public View getTooltipView() { 30716 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 30717 return null; 30718 } 30719 return mTooltipInfo.mTooltipPopup.getContentView(); 30720 } 30721 30722 /** 30723 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 30724 * @hide 30725 */ 30726 @TestApi isDefaultFocusHighlightEnabled()30727 public static boolean isDefaultFocusHighlightEnabled() { 30728 return sUseDefaultFocusHighlight; 30729 } 30730 30731 /** 30732 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 30733 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 30734 * (visually on-top views first). 30735 * 30736 * @param evt the previously unhandled {@link KeyEvent}. 30737 * @return the {@link View} which consumed the event or {@code null} if not consumed. 30738 */ dispatchUnhandledKeyEvent(KeyEvent evt)30739 View dispatchUnhandledKeyEvent(KeyEvent evt) { 30740 if (onUnhandledKeyEvent(evt)) { 30741 return this; 30742 } 30743 return null; 30744 } 30745 30746 /** 30747 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 30748 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 30749 * this will dispatch into all the listeners registered via 30750 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 30751 * order (most recently added will receive events first). 30752 * 30753 * @param event An unhandled event. 30754 * @return {@code true} if the event was handled, {@code false} otherwise. 30755 * @see #addOnUnhandledKeyEventListener 30756 */ onUnhandledKeyEvent(@onNull KeyEvent event)30757 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 30758 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 30759 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 30760 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 30761 return true; 30762 } 30763 } 30764 } 30765 return false; 30766 } 30767 hasUnhandledKeyListener()30768 boolean hasUnhandledKeyListener() { 30769 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 30770 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 30771 } 30772 30773 /** 30774 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 30775 * UI thread. 30776 * 30777 * @param listener a receiver of unhandled {@link KeyEvent}s. 30778 * @see #removeOnUnhandledKeyEventListener 30779 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)30780 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 30781 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 30782 if (listeners == null) { 30783 listeners = new ArrayList<>(); 30784 getListenerInfo().mUnhandledKeyListeners = listeners; 30785 } 30786 listeners.add(listener); 30787 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 30788 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 30789 } 30790 } 30791 30792 /** 30793 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 30794 * UI thread. 30795 * 30796 * @param listener a receiver of unhandled {@link KeyEvent}s. 30797 * @see #addOnUnhandledKeyEventListener 30798 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)30799 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 30800 if (mListenerInfo != null) { 30801 if (mListenerInfo.mUnhandledKeyListeners != null 30802 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 30803 mListenerInfo.mUnhandledKeyListeners.remove(listener); 30804 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 30805 mListenerInfo.mUnhandledKeyListeners = null; 30806 if (mParent instanceof ViewGroup) { 30807 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 30808 } 30809 } 30810 } 30811 } 30812 } 30813 30814 /** 30815 * Set the view to be detached or not detached. 30816 * 30817 * @param detached Whether the view is detached. 30818 * 30819 * @hide 30820 */ setDetached(boolean detached)30821 protected void setDetached(boolean detached) { 30822 if (detached) { 30823 mPrivateFlags4 |= PFLAG4_DETACHED; 30824 } else { 30825 mPrivateFlags4 &= ~PFLAG4_DETACHED; 30826 } 30827 } 30828 30829 /** 30830 * Collects a {@link ViewTranslationRequest} which represents the content to be translated in 30831 * the view. 30832 * 30833 * <p>The default implementation does nothing.</p> 30834 * 30835 * @param supportedFormats the supported translation formats. For now, the only possible value 30836 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 30837 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be used to 30838 * collect the information to be translated in the view. The {@code requestsCollector} only 30839 * accepts one request; an IllegalStateException is thrown if more than one 30840 * {@link ViewTranslationRequest} is submitted to it. The {@link AutofillId} must be set on the 30841 * {@link ViewTranslationRequest}. 30842 */ onCreateViewTranslationRequest(@onNull @ataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)30843 public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, 30844 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 30845 } 30846 30847 /** 30848 * Collects {@link ViewTranslationRequest}s which represents the content to be translated 30849 * for the virtual views in the host view. This is called if this view returned a virtual 30850 * view structure from {@link #onProvideContentCaptureStructure} and the system determined that 30851 * those virtual views were relevant for translation. 30852 * 30853 * <p>The default implementation does nothing.</p> 30854 * 30855 * @param virtualIds the virtual view ids which represents the virtual views in the host 30856 * view. 30857 * @param supportedFormats the supported translation formats. For now, the only possible value 30858 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 30859 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called 30860 * multiple times to collect the information to be translated in the host view. One 30861 * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must 30862 * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this 30863 * Consumer after the method returns. 30864 */ 30865 @SuppressLint("NullableCollection") onCreateVirtualViewTranslationRequests(@onNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)30866 public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, 30867 @NonNull @DataFormat int[] supportedFormats, 30868 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 30869 // no-op 30870 } 30871 30872 /** 30873 * Returns a {@link ViewTranslationCallback} that is used to display the translated information 30874 * or {@code null} if this View doesn't support translation. 30875 * 30876 * @hide 30877 */ 30878 @Nullable getViewTranslationCallback()30879 public ViewTranslationCallback getViewTranslationCallback() { 30880 return mViewTranslationCallback; 30881 } 30882 30883 /** 30884 * Sets a {@link ViewTranslationCallback} that is used to display/hide the translated 30885 * information. Developers can provide the customized implementation for show/hide translated 30886 * information. 30887 * 30888 * @param callback a {@link ViewTranslationCallback} that is used to control how to display the 30889 * translated information 30890 */ setViewTranslationCallback(@onNull ViewTranslationCallback callback)30891 public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { 30892 mViewTranslationCallback = callback; 30893 } 30894 30895 /** 30896 * Clear the {@link ViewTranslationCallback} from this view. 30897 */ clearViewTranslationCallback()30898 public void clearViewTranslationCallback() { 30899 mViewTranslationCallback = null; 30900 } 30901 30902 /** 30903 * Returns the {@link ViewTranslationResponse} associated with this view. The response will be 30904 * set when the translation is done then {@link #onViewTranslationResponse} is called. The 30905 * {@link ViewTranslationCallback} can use to get {@link ViewTranslationResponse} to display the 30906 * translated information. 30907 * 30908 * @return a {@link ViewTranslationResponse} that contains the translated information associated 30909 * with this view or {@code null} if this View doesn't have the translation. 30910 */ 30911 @Nullable getViewTranslationResponse()30912 public ViewTranslationResponse getViewTranslationResponse() { 30913 return mViewTranslationResponse; 30914 } 30915 30916 /** 30917 * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated 30918 * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that 30919 * the {@link ViewTranslationResponse} can be used to display the translation when the system 30920 * calls {@link ViewTranslationCallback#onShowTranslation}. 30921 * 30922 * <p> The default implementation will set the ViewTranslationResponse that can be get from 30923 * {@link View#getViewTranslationResponse}. </p> 30924 * 30925 * @param response a {@link ViewTranslationResponse} that contains the translated information 30926 * which can be shown in the view. 30927 */ onViewTranslationResponse(@onNull ViewTranslationResponse response)30928 public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { 30929 mViewTranslationResponse = response; 30930 } 30931 30932 /** 30933 * Clears the ViewTranslationResponse stored by the default implementation of {@link 30934 * #onViewTranslationResponse}. 30935 * 30936 * @hide 30937 */ clearViewTranslationResponse()30938 public void clearViewTranslationResponse() { 30939 mViewTranslationResponse = null; 30940 } 30941 30942 /** 30943 * Called when the content from {@link View#onCreateVirtualViewTranslationRequests} had been 30944 * translated by the TranslationService. 30945 * 30946 * <p> The default implementation does nothing.</p> 30947 * 30948 * @param response a {@link ViewTranslationResponse} SparseArray for the request that send by 30949 * {@link View#onCreateVirtualViewTranslationRequests} that contains the translated information 30950 * which can be shown in the view. The key of SparseArray is the virtual child ids. 30951 */ onVirtualViewTranslationResponses( @onNull LongSparseArray<ViewTranslationResponse> response)30952 public void onVirtualViewTranslationResponses( 30953 @NonNull LongSparseArray<ViewTranslationResponse> response) { 30954 // no-op 30955 } 30956 30957 /** 30958 * Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing 30959 * the hierarchy when the app requests ui translation. Typically, this method should only be 30960 * overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other 30961 * classes should override {@link View#onCreateViewTranslationRequest} for normal view or 30962 * override {@link View#onVirtualViewTranslationResponses} for view contains virtual children. 30963 * When requested to start the ui translation, the system will call this method to traverse the 30964 * view hierarchy to collect {@link ViewTranslationRequest}s and create a 30965 * {@link android.view.translation.Translator} to translate the requests. All the 30966 * {@link ViewTranslationRequest}s must be added when the traversal is done. 30967 * 30968 * <p> The default implementation calls {@link View#onCreateViewTranslationRequest} for normal 30969 * view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual 30970 * children to build {@link ViewTranslationRequest} if the view should be translated. 30971 * The view is marked as having {@link #setHasTransientState(boolean) transient state} so that 30972 * recycling of views doesn't prevent the system from attaching the response to it. Therefore, 30973 * if overriding this method, you should set or reset the transient state. </p> 30974 * 30975 * @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or 30976 * {@code null} if the view doesn't have virtual child that should be translated. The virtual 30977 * child ids are the same virtual ids provided by ContentCapture. 30978 * @param supportedFormats the supported translation formats. For now, the only possible value 30979 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 30980 * @param capability a {@link TranslationCapability} that holds translation capability. 30981 * information, e.g. source spec, target spec. 30982 * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose. 30983 */ dispatchCreateViewTranslationRequest(@onNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests)30984 public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, 30985 @NonNull @DataFormat int[] supportedFormats, 30986 @NonNull TranslationCapability capability, 30987 @NonNull List<ViewTranslationRequest> requests) { 30988 AutofillId autofillId = getAutofillId(); 30989 if (viewIds.containsKey(autofillId)) { 30990 if (viewIds.get(autofillId) == null) { 30991 // TODO: avoiding the allocation per view 30992 onCreateViewTranslationRequest(supportedFormats, 30993 new ViewTranslationRequestConsumer(requests)); 30994 } else { 30995 onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, 30996 request -> { 30997 requests.add(request); 30998 }); 30999 } 31000 } 31001 } 31002 31003 private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { 31004 private final List<ViewTranslationRequest> mRequests; 31005 private boolean mCalled; 31006 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests)31007 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { 31008 mRequests = requests; 31009 } 31010 31011 @Override accept(ViewTranslationRequest request)31012 public void accept(ViewTranslationRequest request) { 31013 if (mCalled) { 31014 throw new IllegalStateException("The translation Consumer is not reusable."); 31015 } 31016 mCalled = true; 31017 if (request != null && request.getKeys().size() > 0) { 31018 mRequests.add(request); 31019 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 31020 Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " 31021 + getAutofillId()); 31022 } 31023 setHasTransientState(true); 31024 setHasTranslationTransientState(true); 31025 } 31026 } 31027 } 31028 31029 /** 31030 * Called to generate a {@link DisplayHash} for this view. 31031 * 31032 * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of 31033 * the values returned from 31034 * {@link DisplayHashManager#getSupportedHashAlgorithms()} 31035 * @param bounds The bounds for the content within the View to generate the hash for. If 31036 * bounds are null, the entire View's bounds will be used. If empty, it will 31037 * invoke the callback 31038 * {@link DisplayHashResultCallback#onDisplayHashError} with error 31039 * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} 31040 * @param executor The executor that the callback should be invoked on. 31041 * @param callback The callback to handle the results of generating the display hash 31042 */ generateDisplayHash(@onNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback)31043 public void generateDisplayHash(@NonNull String hashAlgorithm, 31044 @Nullable Rect bounds, @NonNull Executor executor, 31045 @NonNull DisplayHashResultCallback callback) { 31046 IWindowSession session = getWindowSession(); 31047 if (session == null) { 31048 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 31049 return; 31050 } 31051 IWindow window = getWindow(); 31052 if (window == null) { 31053 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 31054 return; 31055 } 31056 31057 Rect visibleBounds = new Rect(); 31058 getGlobalVisibleRect(visibleBounds); 31059 31060 if (bounds != null && bounds.isEmpty()) { 31061 callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); 31062 return; 31063 } 31064 31065 if (bounds != null) { 31066 bounds.offset(visibleBounds.left, visibleBounds.top); 31067 visibleBounds.intersectUnchecked(bounds); 31068 } 31069 31070 if (visibleBounds.isEmpty()) { 31071 callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); 31072 return; 31073 } 31074 31075 RemoteCallback remoteCallback = new RemoteCallback(result -> 31076 executor.execute(() -> { 31077 DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH); 31078 int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, 31079 DISPLAY_HASH_ERROR_UNKNOWN); 31080 if (displayHash != null) { 31081 callback.onDisplayHashResult(displayHash); 31082 } else { 31083 callback.onDisplayHashError(errorCode); 31084 } 31085 })); 31086 31087 try { 31088 session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); 31089 } catch (RemoteException e) { 31090 Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); 31091 callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); 31092 } 31093 } 31094 31095 /** 31096 * The AttachedSurfaceControl itself is not a View, it is just the interface to the 31097 * windowing-system object that contains the entire view hierarchy. 31098 * For the root View of a given hierarchy see {@link #getRootView}. 31099 31100 * @return The {@link android.view.AttachedSurfaceControl} interface for this View. 31101 * This will only return a non-null value when called between {@link #onAttachedToWindow} 31102 * and {@link #onDetachedFromWindow}. 31103 */ getRootSurfaceControl()31104 public @Nullable AttachedSurfaceControl getRootSurfaceControl() { 31105 if (mAttachInfo != null) { 31106 return mAttachInfo.getRootSurfaceControl(); 31107 } 31108 return null; 31109 } 31110 } 31111