1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.view; 18 19 import static android.content.res.Resources.ID_NULL; 20 import static android.os.Trace.TRACE_TAG_APP; 21 import static android.os.Trace.TRACE_TAG_VIEW; 22 import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION; 23 import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; 24 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; 25 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; 26 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; 27 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; 28 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 29 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE; 30 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 31 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 32 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; 33 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 34 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; 35 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; 36 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; 37 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; 38 import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API; 39 import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; 40 import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; 41 import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; 42 import static android.view.flags.Flags.sensitiveContentAppProtection; 43 import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly; 44 import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly; 45 import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly; 46 import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly; 47 import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly; 48 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; 49 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; 50 import static android.view.flags.Flags.viewVelocityApi; 51 import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; 52 import static android.view.inputmethod.Flags.initiationWithoutInputConnection; 53 54 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 55 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 56 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 57 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 58 import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS; 59 60 import static java.lang.Math.max; 61 62 import android.animation.AnimatorInflater; 63 import android.animation.StateListAnimator; 64 import android.annotation.AttrRes; 65 import android.annotation.CallSuper; 66 import android.annotation.ColorInt; 67 import android.annotation.DrawableRes; 68 import android.annotation.FlaggedApi; 69 import android.annotation.FloatRange; 70 import android.annotation.IdRes; 71 import android.annotation.IntDef; 72 import android.annotation.IntRange; 73 import android.annotation.LayoutRes; 74 import android.annotation.NonNull; 75 import android.annotation.Nullable; 76 import android.annotation.RequiresPermission; 77 import android.annotation.Size; 78 import android.annotation.StyleRes; 79 import android.annotation.SuppressLint; 80 import android.annotation.SystemApi; 81 import android.annotation.TestApi; 82 import android.annotation.UiContext; 83 import android.annotation.UiThread; 84 import android.app.PendingIntent; 85 import android.compat.annotation.UnsupportedAppUsage; 86 import android.content.AutofillOptions; 87 import android.content.ClipData; 88 import android.content.ClipDescription; 89 import android.content.Context; 90 import android.content.ContextWrapper; 91 import android.content.Intent; 92 import android.content.IntentSender; 93 import android.content.res.ColorStateList; 94 import android.content.res.CompatibilityInfo; 95 import android.content.res.Configuration; 96 import android.content.res.Resources; 97 import android.content.res.TypedArray; 98 import android.credentials.CredentialManager; 99 import android.credentials.CredentialOption; 100 import android.credentials.GetCredentialException; 101 import android.credentials.GetCredentialRequest; 102 import android.credentials.GetCredentialResponse; 103 import android.graphics.Bitmap; 104 import android.graphics.BlendMode; 105 import android.graphics.Canvas; 106 import android.graphics.Color; 107 import android.graphics.Insets; 108 import android.graphics.Interpolator; 109 import android.graphics.LinearGradient; 110 import android.graphics.Matrix; 111 import android.graphics.Outline; 112 import android.graphics.Paint; 113 import android.graphics.PixelFormat; 114 import android.graphics.Point; 115 import android.graphics.PorterDuff; 116 import android.graphics.PorterDuffXfermode; 117 import android.graphics.RecordingCanvas; 118 import android.graphics.Rect; 119 import android.graphics.RectF; 120 import android.graphics.Region; 121 import android.graphics.RenderEffect; 122 import android.graphics.RenderNode; 123 import android.graphics.Shader; 124 import android.graphics.drawable.ColorDrawable; 125 import android.graphics.drawable.Drawable; 126 import android.graphics.drawable.GradientDrawable; 127 import android.hardware.display.DisplayManagerGlobal; 128 import android.hardware.input.InputManager; 129 import android.net.Uri; 130 import android.os.Build; 131 import android.os.Bundle; 132 import android.os.Handler; 133 import android.os.IBinder; 134 import android.os.Message; 135 import android.os.OutcomeReceiver; 136 import android.os.Parcel; 137 import android.os.Parcelable; 138 import android.os.RemoteCallback; 139 import android.os.RemoteException; 140 import android.os.SystemClock; 141 import android.os.Trace; 142 import android.os.Vibrator; 143 import android.os.vibrator.Flags; 144 import android.service.credentials.CredentialProviderService; 145 import android.sysprop.DisplayProperties; 146 import android.text.InputType; 147 import android.text.TextUtils; 148 import android.util.ArraySet; 149 import android.util.AttributeSet; 150 import android.util.DisplayMetrics; 151 import android.util.FloatProperty; 152 import android.util.LayoutDirection; 153 import android.util.Log; 154 import android.util.LongSparseArray; 155 import android.util.LongSparseLongArray; 156 import android.util.Pair; 157 import android.util.Pools.SynchronizedPool; 158 import android.util.Property; 159 import android.util.SparseArray; 160 import android.util.SparseIntArray; 161 import android.util.StateSet; 162 import android.util.SuperNotCalledException; 163 import android.util.TimeUtils; 164 import android.util.TypedValue; 165 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 166 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 167 import android.view.AccessibilityIterators.TextSegmentIterator; 168 import android.view.AccessibilityIterators.WordTextSegmentIterator; 169 import android.view.ContextMenu.ContextMenuInfo; 170 import android.view.InputDevice.InputSourceClass; 171 import android.view.Window.OnContentApplyWindowInsetsListener; 172 import android.view.WindowInsets.Type; 173 import android.view.WindowInsetsAnimation.Bounds; 174 import android.view.WindowManager.LayoutParams; 175 import android.view.accessibility.AccessibilityEvent; 176 import android.view.accessibility.AccessibilityEventSource; 177 import android.view.accessibility.AccessibilityManager; 178 import android.view.accessibility.AccessibilityNodeIdManager; 179 import android.view.accessibility.AccessibilityNodeInfo; 180 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 181 import android.view.accessibility.AccessibilityNodeProvider; 182 import android.view.accessibility.AccessibilityWindowInfo; 183 import android.view.animation.Animation; 184 import android.view.animation.AnimationUtils; 185 import android.view.animation.Transformation; 186 import android.view.autofill.AutofillId; 187 import android.view.autofill.AutofillManager; 188 import android.view.autofill.AutofillValue; 189 import android.view.contentcapture.ContentCaptureContext; 190 import android.view.contentcapture.ContentCaptureManager; 191 import android.view.contentcapture.ContentCaptureSession; 192 import android.view.displayhash.DisplayHash; 193 import android.view.displayhash.DisplayHashManager; 194 import android.view.displayhash.DisplayHashResultCallback; 195 import android.view.inputmethod.EditorInfo; 196 import android.view.inputmethod.InputConnection; 197 import android.view.inputmethod.InputMethodManager; 198 import android.view.inspector.InspectableProperty; 199 import android.view.inspector.InspectableProperty.EnumEntry; 200 import android.view.inspector.InspectableProperty.FlagEntry; 201 import android.view.translation.TranslationCapability; 202 import android.view.translation.TranslationSpec.DataFormat; 203 import android.view.translation.ViewTranslationCallback; 204 import android.view.translation.ViewTranslationRequest; 205 import android.view.translation.ViewTranslationResponse; 206 import android.widget.Checkable; 207 import android.widget.ScrollBarDrawable; 208 import android.window.OnBackInvokedDispatcher; 209 210 import com.android.internal.R; 211 import com.android.internal.util.ArrayUtils; 212 import com.android.internal.util.FrameworkStatsLog; 213 import com.android.internal.util.Preconditions; 214 import com.android.internal.view.ScrollCaptureInternal; 215 import com.android.internal.view.TooltipPopup; 216 import com.android.internal.view.menu.MenuBuilder; 217 import com.android.internal.widget.ScrollBarUtils; 218 219 import com.google.android.collect.Lists; 220 import com.google.android.collect.Maps; 221 222 import java.io.PrintWriter; 223 import java.lang.annotation.Retention; 224 import java.lang.annotation.RetentionPolicy; 225 import java.lang.ref.WeakReference; 226 import java.lang.reflect.Field; 227 import java.lang.reflect.InvocationTargetException; 228 import java.lang.reflect.Method; 229 import java.lang.reflect.Modifier; 230 import java.time.Duration; 231 import java.util.ArrayList; 232 import java.util.Arrays; 233 import java.util.Calendar; 234 import java.util.Collection; 235 import java.util.Collections; 236 import java.util.HashMap; 237 import java.util.List; 238 import java.util.Locale; 239 import java.util.Map; 240 import java.util.concurrent.CopyOnWriteArrayList; 241 import java.util.concurrent.Executor; 242 import java.util.concurrent.atomic.AtomicInteger; 243 import java.util.function.Consumer; 244 import java.util.function.Predicate; 245 246 /** 247 * <p> 248 * This class represents the basic building block for user interface components. A View 249 * occupies a rectangular area on the screen and is responsible for drawing and 250 * event handling. View is the base class for <em>widgets</em>, which are 251 * used to create interactive UI components (buttons, text fields, etc.). The 252 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 253 * are invisible containers that hold other Views (or other ViewGroups) and define 254 * their layout properties. 255 * </p> 256 * 257 * <div class="special reference"> 258 * <h3>Developer Guides</h3> 259 * <p>For information about using this class to develop your application's user interface, 260 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 261 * </div> 262 * 263 * <a name="Using"></a> 264 * <h3>Using Views</h3> 265 * <p> 266 * All of the views in a window are arranged in a single tree. You can add views 267 * either from code or by specifying a tree of views in one or more XML layout 268 * files. There are many specialized subclasses of views that act as controls or 269 * are capable of displaying text, images, or other content. 270 * </p> 271 * <p> 272 * Once you have created a tree of views, there are typically a few types of 273 * common operations you may wish to perform: 274 * <ul> 275 * <li><strong>Set properties:</strong> for example setting the text of a 276 * {@link android.widget.TextView}. The available properties and the methods 277 * that set them will vary among the different subclasses of views. Note that 278 * properties that are known at build time can be set in the XML layout 279 * files.</li> 280 * <li><strong>Set focus:</strong> The framework will handle moving focus in 281 * response to user input. To force focus to a specific view, call 282 * {@link #requestFocus}.</li> 283 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 284 * that will be notified when something interesting happens to the view. For 285 * example, all views will let you set a listener to be notified when the view 286 * gains or loses focus. You can register such a listener using 287 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 288 * Other view subclasses offer more specialized listeners. For example, a Button 289 * exposes a listener to notify clients when the button is clicked.</li> 290 * <li><strong>Set visibility:</strong> You can hide or show views using 291 * {@link #setVisibility(int)}.</li> 292 * </ul> 293 * </p> 294 * <p><em> 295 * Note: The Android framework is responsible for measuring, laying out and 296 * drawing views. You should not call methods that perform these actions on 297 * views yourself unless you are actually implementing a 298 * {@link android.view.ViewGroup}. 299 * </em></p> 300 * 301 * <a name="Lifecycle"></a> 302 * <h3>Implementing a Custom View</h3> 303 * 304 * <p> 305 * To implement a custom view, you will usually begin by providing overrides for 306 * some of the standard methods that the framework calls on all views. You do 307 * not need to override all of these methods. In fact, you can start by just 308 * overriding {@link #onDraw(android.graphics.Canvas)}. 309 * <table border="2" width="85%" align="center" cellpadding="5"> 310 * <thead> 311 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 312 * </thead> 313 * 314 * <tbody> 315 * <tr> 316 * <td rowspan="2">Creation</td> 317 * <td>Constructors</td> 318 * <td>There is a form of the constructor that are called when the view 319 * is created from code and a form that is called when the view is 320 * inflated from a layout file. The second form should parse and apply 321 * any attributes defined in the layout file. 322 * </td> 323 * </tr> 324 * <tr> 325 * <td><code>{@link #onFinishInflate()}</code></td> 326 * <td>Called after a view and all of its children has been inflated 327 * from XML.</td> 328 * </tr> 329 * 330 * <tr> 331 * <td rowspan="3">Layout</td> 332 * <td><code>{@link #onMeasure(int, int)}</code></td> 333 * <td>Called to determine the size requirements for this view and all 334 * of its children. 335 * </td> 336 * </tr> 337 * <tr> 338 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 339 * <td>Called when this view should assign a size and position to all 340 * of its children. 341 * </td> 342 * </tr> 343 * <tr> 344 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 345 * <td>Called when the size of this view has changed. 346 * </td> 347 * </tr> 348 * 349 * <tr> 350 * <td>Drawing</td> 351 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 352 * <td>Called when the view should render its content. 353 * </td> 354 * </tr> 355 * 356 * <tr> 357 * <td rowspan="6">Event processing</td> 358 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 359 * <td>Called when a new hardware key event occurs. 360 * </td> 361 * </tr> 362 * <tr> 363 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 364 * <td>Called when a hardware key up event occurs. 365 * </td> 366 * </tr> 367 * <tr> 368 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 369 * <td>Called when a trackball motion event occurs. 370 * </td> 371 * </tr> 372 * <tr> 373 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 374 * <td>Called when a touch screen motion event occurs. 375 * </td> 376 * </tr> 377 * <tr> 378 * <td><code>{@link #onGenericMotionEvent(MotionEvent)}</code></td> 379 * <td>Called when a generic motion event occurs. 380 * </td> 381 * </tr> 382 * <tr> 383 * <td><code>{@link #onHoverEvent(MotionEvent)}</code></td> 384 * <td>Called when a hover motion event occurs. 385 * </td> 386 * </tr> 387 * 388 * <tr> 389 * <td rowspan="2">Focus</td> 390 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 391 * <td>Called when the view gains or loses focus. 392 * </td> 393 * </tr> 394 * 395 * <tr> 396 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 397 * <td>Called when the window containing the view gains or loses focus. 398 * </td> 399 * </tr> 400 * 401 * <tr> 402 * <td rowspan="3">Attaching</td> 403 * <td><code>{@link #onAttachedToWindow()}</code></td> 404 * <td>Called when the view is attached to a window. 405 * </td> 406 * </tr> 407 * 408 * <tr> 409 * <td><code>{@link #onDetachedFromWindow}</code></td> 410 * <td>Called when the view is detached from its window. 411 * </td> 412 * </tr> 413 * 414 * <tr> 415 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 416 * <td>Called when the visibility of the window containing the view 417 * has changed. 418 * </td> 419 * </tr> 420 * </tbody> 421 * 422 * </table> 423 * </p> 424 * 425 * <a name="IDs"></a> 426 * <h3>IDs</h3> 427 * Views may have an integer id associated with them. These ids are typically 428 * assigned in the layout XML files, and are used to find specific views within 429 * the view tree. A common pattern is to: 430 * <ul> 431 * <li>Define a Button in the layout file and assign it a unique ID. 432 * <pre> 433 * <Button 434 * android:id="@+id/my_button" 435 * android:layout_width="wrap_content" 436 * android:layout_height="wrap_content" 437 * android:text="@string/my_button_text"/> 438 * </pre></li> 439 * <li>From the onCreate method of an Activity, find the Button 440 * <pre class="prettyprint"> 441 * Button myButton = findViewById(R.id.my_button); 442 * </pre></li> 443 * </ul> 444 * <p> 445 * View IDs need not be unique throughout the tree, but it is good practice to 446 * ensure that they are at least unique within the part of the tree you are 447 * searching. 448 * </p> 449 * 450 * <a name="Position"></a> 451 * <h3>Position</h3> 452 * <p> 453 * The geometry of a view is that of a rectangle. A view has a location, 454 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 455 * two dimensions, expressed as a width and a height. The unit for location 456 * and dimensions is the pixel. 457 * </p> 458 * 459 * <p> 460 * It is possible to retrieve the location of a view by invoking the methods 461 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 462 * coordinate of the rectangle representing the view. The latter returns the 463 * top, or Y, coordinate of the rectangle representing the view. These methods 464 * both return the location of the view relative to its parent. For instance, 465 * when getLeft() returns 20, that means the view is located 20 pixels to the 466 * right of the left edge of its direct parent. 467 * </p> 468 * 469 * <p> 470 * In addition, several convenience methods are offered to avoid unnecessary 471 * computations, namely {@link #getRight()} and {@link #getBottom()}. 472 * These methods return the coordinates of the right and bottom edges of the 473 * rectangle representing the view. For instance, calling {@link #getRight()} 474 * is similar to the following computation: <code>getLeft() + getWidth()</code> 475 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 476 * </p> 477 * 478 * <a name="SizePaddingMargins"></a> 479 * <h3>Size, padding and margins</h3> 480 * <p> 481 * The size of a view is expressed with a width and a height. A view actually 482 * possess two pairs of width and height values. 483 * </p> 484 * 485 * <p> 486 * The first pair is known as <em>measured width</em> and 487 * <em>measured height</em>. These dimensions define how big a view wants to be 488 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 489 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 490 * and {@link #getMeasuredHeight()}. 491 * </p> 492 * 493 * <p> 494 * The second pair is simply known as <em>width</em> and <em>height</em>, or 495 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 496 * dimensions define the actual size of the view on screen, at drawing time and 497 * after layout. These values may, but do not have to, be different from the 498 * measured width and height. The width and height can be obtained by calling 499 * {@link #getWidth()} and {@link #getHeight()}. 500 * </p> 501 * 502 * <p> 503 * To measure its dimensions, a view takes into account its padding. The padding 504 * is expressed in pixels for the left, top, right and bottom parts of the view. 505 * Padding can be used to offset the content of the view by a specific amount of 506 * pixels. For instance, a left padding of 2 will push the view's content by 507 * 2 pixels to the right of the left edge. Padding can be set using the 508 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 509 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 510 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 511 * {@link #getPaddingEnd()}. 512 * </p> 513 * 514 * <p> 515 * Even though a view can define a padding, it does not provide any support for 516 * margins. However, view groups provide such a support. Refer to 517 * {@link android.view.ViewGroup} and 518 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 519 * </p> 520 * 521 * <a name="Layout"></a> 522 * <h3>Layout</h3> 523 * <p> 524 * Layout is a two pass process: a measure pass and a layout pass. The measuring 525 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 526 * of the view tree. Each view pushes dimension specifications down the tree 527 * during the recursion. At the end of the measure pass, every view has stored 528 * its measurements. The second pass happens in 529 * {@link #layout(int,int,int,int)} and is also top-down. During 530 * this pass each parent is responsible for positioning all of its children 531 * using the sizes computed in the measure pass. 532 * </p> 533 * 534 * <p> 535 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 536 * {@link #getMeasuredHeight()} values must be set, along with those for all of 537 * that view's descendants. A view's measured width and measured height values 538 * must respect the constraints imposed by the view's parents. This guarantees 539 * that at the end of the measure pass, all parents accept all of their 540 * children's measurements. A parent view may call measure() more than once on 541 * its children. For example, the parent may measure each child once with 542 * unspecified dimensions to find out how big they want to be, then call 543 * measure() on them again with actual numbers if the sum of all the children's 544 * unconstrained sizes is too big or too small. 545 * </p> 546 * 547 * <p> 548 * The measure pass uses two classes to communicate dimensions. The 549 * {@link MeasureSpec} class is used by views to tell their parents how they 550 * want to be measured and positioned. The base LayoutParams class just 551 * describes how big the view wants to be for both width and height. For each 552 * dimension, it can specify one of: 553 * <ul> 554 * <li> an exact number 555 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 556 * (minus padding) 557 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 558 * enclose its content (plus padding). 559 * </ul> 560 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 561 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 562 * an X and Y value. 563 * </p> 564 * 565 * <p> 566 * MeasureSpecs are used to push requirements down the tree from parent to 567 * child. A MeasureSpec can be in one of three modes: 568 * <ul> 569 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 570 * of a child view. For example, a LinearLayout may call measure() on its child 571 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 572 * tall the child view wants to be given a width of 240 pixels. 573 * <li>EXACTLY: This is used by the parent to impose an exact size on the 574 * child. The child must use this size, and guarantee that all of its 575 * descendants will fit within this size. 576 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 577 * child. The child must guarantee that it and all of its descendants will fit 578 * within this size. 579 * </ul> 580 * </p> 581 * 582 * <p> 583 * To initiate a layout, call {@link #requestLayout}. This method is typically 584 * called by a view on itself when it believes that it can no longer fit within 585 * its current bounds. 586 * </p> 587 * 588 * <a name="Drawing"></a> 589 * <h3>Drawing</h3> 590 * <p> 591 * Drawing is handled by walking the tree and recording the drawing commands of 592 * any View that needs to update. After this, the drawing commands of the 593 * entire tree are issued to screen, clipped to the newly damaged area. 594 * </p> 595 * 596 * <p> 597 * The tree is largely recorded and drawn in order, with parents drawn before 598 * (i.e., behind) their children, with siblings drawn in the order they appear 599 * in the tree. If you set a background drawable for a View, then the View will 600 * draw it before calling back to its <code>onDraw()</code> method. The child 601 * drawing order can be overridden with 602 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 603 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 604 * </p> 605 * 606 * <p> 607 * To force a view to draw, call {@link #invalidate()}. 608 * </p> 609 * 610 * <a name="EventHandlingThreading"></a> 611 * <h3>Event Handling and Threading</h3> 612 * <p> 613 * The basic cycle of a view is as follows: 614 * <ol> 615 * <li>An event comes in and is dispatched to the appropriate view. The view 616 * handles the event and notifies any listeners.</li> 617 * <li>If in the course of processing the event, the view's bounds may need 618 * to be changed, the view will call {@link #requestLayout()}.</li> 619 * <li>Similarly, if in the course of processing the event the view's appearance 620 * may need to be changed, the view will call {@link #invalidate()}.</li> 621 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 622 * the framework will take care of measuring, laying out, and drawing the tree 623 * as appropriate.</li> 624 * </ol> 625 * </p> 626 * 627 * <p><em>Note: The entire view tree is single threaded. You must always be on 628 * the UI thread when calling any method on any view.</em> 629 * If you are doing work on other threads and want to update the state of a view 630 * from that thread, you should use a {@link Handler}. 631 * </p> 632 * 633 * <a name="FocusHandling"></a> 634 * <h3>Focus Handling</h3> 635 * <p> 636 * The framework will handle routine focus movement in response to user input. 637 * This includes changing the focus as views are removed or hidden, or as new 638 * views become available. Views indicate their willingness to take focus 639 * through the {@link #isFocusable} method. To change whether a view can take 640 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 641 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 642 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 643 * </p> 644 * <p> 645 * Focus movement is based on an algorithm which finds the nearest neighbor in a 646 * given direction. In rare cases, the default algorithm may not match the 647 * intended behavior of the developer. In these situations, you can provide 648 * explicit overrides by using these XML attributes in the layout file: 649 * <pre> 650 * nextFocusDown 651 * nextFocusLeft 652 * nextFocusRight 653 * nextFocusUp 654 * </pre> 655 * </p> 656 * 657 * 658 * <p> 659 * To get a particular view to take focus, call {@link #requestFocus()}. 660 * </p> 661 * 662 * <a name="TouchMode"></a> 663 * <h3>Touch Mode</h3> 664 * <p> 665 * When a user is navigating a user interface via directional keys such as a D-pad, it is 666 * necessary to give focus to actionable items such as buttons so the user can see 667 * what will take input. If the device has touch capabilities, however, and the user 668 * begins interacting with the interface by touching it, it is no longer necessary to 669 * always highlight, or give focus to, a particular view. This motivates a mode 670 * for interaction named 'touch mode'. 671 * </p> 672 * <p> 673 * For a touch capable device, once the user touches the screen, the device 674 * will enter touch mode. From this point onward, only views for which 675 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 676 * Other views that are touchable, like buttons, will not take focus when touched; they will 677 * only fire the on click listeners. 678 * </p> 679 * <p> 680 * Any time a user hits a directional key, such as a D-pad direction, the view device will 681 * exit touch mode, and find a view to take focus, so that the user may resume interacting 682 * with the user interface without touching the screen again. 683 * </p> 684 * <p> 685 * The touch mode state is maintained across {@link android.app.Activity}s. Call 686 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 687 * </p> 688 * 689 * <a name="Scrolling"></a> 690 * <h3>Scrolling</h3> 691 * <p> 692 * The framework provides basic support for views that wish to internally 693 * scroll their content. This includes keeping track of the X and Y scroll 694 * offset as well as mechanisms for drawing scrollbars. See 695 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 696 * {@link #awakenScrollBars()} for more details. 697 * </p> 698 * 699 * <a name="Tags"></a> 700 * <h3>Tags</h3> 701 * <p> 702 * Unlike IDs, tags are not used to identify views. Tags are essentially an 703 * extra piece of information that can be associated with a view. They are most 704 * often used as a convenience to store data related to views in the views 705 * themselves rather than by putting them in a separate structure. 706 * </p> 707 * <p> 708 * Tags may be specified with character sequence values in layout XML as either 709 * a single tag using the {@link android.R.styleable#View_tag android:tag} 710 * attribute or multiple tags using the {@code <tag>} child element: 711 * <pre> 712 * <View ... 713 * android:tag="@string/mytag_value" /> 714 * <View ...> 715 * <tag android:id="@+id/mytag" 716 * android:value="@string/mytag_value" /> 717 * </View> 718 * </pre> 719 * </p> 720 * <p> 721 * Tags may also be specified with arbitrary objects from code using 722 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 723 * </p> 724 * 725 * <a name="Themes"></a> 726 * <h3>Themes</h3> 727 * <p> 728 * By default, Views are created using the theme of the Context object supplied 729 * to their constructor; however, a different theme may be specified by using 730 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 731 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 732 * code. 733 * </p> 734 * <p> 735 * When the {@link android.R.styleable#View_theme android:theme} attribute is 736 * used in XML, the specified theme is applied on top of the inflation 737 * context's theme (see {@link LayoutInflater}) and used for the view itself as 738 * well as any child elements. 739 * </p> 740 * <p> 741 * In the following example, both views will be created using the Material dark 742 * color scheme; however, because an overlay theme is used which only defines a 743 * subset of attributes, the value of 744 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 745 * the inflation context's theme (e.g. the Activity theme) will be preserved. 746 * <pre> 747 * <LinearLayout 748 * ... 749 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 750 * <View ...> 751 * </LinearLayout> 752 * </pre> 753 * </p> 754 * 755 * <a name="Properties"></a> 756 * <h3>Properties</h3> 757 * <p> 758 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 759 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 760 * available both in the {@link Property} form as well as in similarly-named setter/getter 761 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 762 * be used to set persistent state associated with these rendering-related properties on the view. 763 * The properties and methods can also be used in conjunction with 764 * {@link android.animation.Animator Animator}-based animations, described more in the 765 * <a href="#Animation">Animation</a> section. 766 * </p> 767 * 768 * <a name="Animation"></a> 769 * <h3>Animation</h3> 770 * <p> 771 * Starting with Android 3.0, the preferred way of animating views is to use the 772 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 773 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 774 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 775 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 776 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 777 * makes animating these View properties particularly easy and efficient. 778 * </p> 779 * <p> 780 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 781 * You can attach an {@link Animation} object to a view using 782 * {@link #setAnimation(Animation)} or 783 * {@link #startAnimation(Animation)}. The animation can alter the scale, 784 * rotation, translation and alpha of a view over time. If the animation is 785 * attached to a view that has children, the animation will affect the entire 786 * subtree rooted by that node. When an animation is started, the framework will 787 * take care of redrawing the appropriate views until the animation completes. 788 * </p> 789 * 790 * <a name="Security"></a> 791 * <h3>Security</h3> 792 * <p> 793 * Sometimes it is essential that an application be able to verify that an action 794 * is being performed with the full knowledge and consent of the user, such as 795 * granting a permission request, making a purchase or clicking on an advertisement. 796 * Unfortunately, a malicious application could try to spoof the user into 797 * performing these actions, unaware, by concealing the intended purpose of the view. 798 * As a remedy, the framework offers a touch filtering mechanism that can be used to 799 * improve the security of views that provide access to sensitive functionality. 800 * </p><p> 801 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 802 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 803 * will discard touches that are received whenever the view's window is obscured by 804 * another visible window at the touched location. As a result, the view will not receive touches 805 * whenever the touch passed through a toast, dialog or other window that appears above the view's 806 * window. 807 * </p><p> 808 * For more fine-grained control over security, consider overriding the 809 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 810 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 811 * </p> 812 * 813 * @attr ref android.R.styleable#View_accessibilityHeading 814 * @attr ref android.R.styleable#View_allowClickWhenDisabled 815 * @attr ref android.R.styleable#View_alpha 816 * @attr ref android.R.styleable#View_background 817 * @attr ref android.R.styleable#View_clickable 818 * @attr ref android.R.styleable#View_clipToOutline 819 * @attr ref android.R.styleable#View_contentDescription 820 * @attr ref android.R.styleable#View_drawingCacheQuality 821 * @attr ref android.R.styleable#View_duplicateParentState 822 * @attr ref android.R.styleable#View_id 823 * @attr ref android.R.styleable#View_requiresFadingEdge 824 * @attr ref android.R.styleable#View_fadeScrollbars 825 * @attr ref android.R.styleable#View_fadingEdgeLength 826 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 827 * @attr ref android.R.styleable#View_fitsSystemWindows 828 * @attr ref android.R.styleable#View_isScrollContainer 829 * @attr ref android.R.styleable#View_focusable 830 * @attr ref android.R.styleable#View_focusableInTouchMode 831 * @attr ref android.R.styleable#View_focusedByDefault 832 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 833 * @attr ref android.R.styleable#View_keepScreenOn 834 * @attr ref android.R.styleable#View_keyboardNavigationCluster 835 * @attr ref android.R.styleable#View_layerType 836 * @attr ref android.R.styleable#View_layoutDirection 837 * @attr ref android.R.styleable#View_longClickable 838 * @attr ref android.R.styleable#View_minHeight 839 * @attr ref android.R.styleable#View_minWidth 840 * @attr ref android.R.styleable#View_nextClusterForward 841 * @attr ref android.R.styleable#View_nextFocusDown 842 * @attr ref android.R.styleable#View_nextFocusLeft 843 * @attr ref android.R.styleable#View_nextFocusRight 844 * @attr ref android.R.styleable#View_nextFocusUp 845 * @attr ref android.R.styleable#View_onClick 846 * @attr ref android.R.styleable#View_outlineSpotShadowColor 847 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 848 * @attr ref android.R.styleable#View_padding 849 * @attr ref android.R.styleable#View_paddingHorizontal 850 * @attr ref android.R.styleable#View_paddingVertical 851 * @attr ref android.R.styleable#View_paddingBottom 852 * @attr ref android.R.styleable#View_paddingLeft 853 * @attr ref android.R.styleable#View_paddingRight 854 * @attr ref android.R.styleable#View_paddingTop 855 * @attr ref android.R.styleable#View_paddingStart 856 * @attr ref android.R.styleable#View_paddingEnd 857 * @attr ref android.R.styleable#View_saveEnabled 858 * @attr ref android.R.styleable#View_rotation 859 * @attr ref android.R.styleable#View_rotationX 860 * @attr ref android.R.styleable#View_rotationY 861 * @attr ref android.R.styleable#View_scaleX 862 * @attr ref android.R.styleable#View_scaleY 863 * @attr ref android.R.styleable#View_scrollX 864 * @attr ref android.R.styleable#View_scrollY 865 * @attr ref android.R.styleable#View_scrollbarSize 866 * @attr ref android.R.styleable#View_scrollbarStyle 867 * @attr ref android.R.styleable#View_scrollbars 868 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 869 * @attr ref android.R.styleable#View_scrollbarFadeDuration 870 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 871 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 872 * @attr ref android.R.styleable#View_scrollbarThumbVertical 873 * @attr ref android.R.styleable#View_scrollbarTrackVertical 874 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 875 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 876 * @attr ref android.R.styleable#View_stateListAnimator 877 * @attr ref android.R.styleable#View_transitionName 878 * @attr ref android.R.styleable#View_soundEffectsEnabled 879 * @attr ref android.R.styleable#View_tag 880 * @attr ref android.R.styleable#View_textAlignment 881 * @attr ref android.R.styleable#View_textDirection 882 * @attr ref android.R.styleable#View_transformPivotX 883 * @attr ref android.R.styleable#View_transformPivotY 884 * @attr ref android.R.styleable#View_translationX 885 * @attr ref android.R.styleable#View_translationY 886 * @attr ref android.R.styleable#View_translationZ 887 * @attr ref android.R.styleable#View_visibility 888 * @attr ref android.R.styleable#View_theme 889 * 890 * @see android.view.ViewGroup 891 */ 892 @UiThread 893 public class View implements Drawable.Callback, KeyEvent.Callback, 894 AccessibilityEventSource { 895 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 896 private static final boolean DBG = false; 897 898 /** @hide */ 899 public static boolean DEBUG_DRAW = false; 900 901 /** 902 * The logging tag used by this class with android.util.Log. 903 */ 904 protected static final String VIEW_LOG_TAG = "View"; 905 906 /** 907 * The logging tag used by this class when logging verbose, autofill-related messages. 908 */ 909 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 910 // set if a session is not started. 911 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 912 913 /** 914 * The logging tag used by this class when logging content capture-related messages. 915 */ 916 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 917 918 private static final boolean DEBUG_CONTENT_CAPTURE = false; 919 920 /** 921 * When set to true, this view will save its attribute data. 922 * 923 * @hide 924 */ 925 public static boolean sDebugViewAttributes = false; 926 927 /** 928 * When set to this application package view will save its attribute data. 929 * 930 * @hide 931 */ 932 public static String sDebugViewAttributesApplicationPackage; 933 934 /** 935 * Used to mark a View that has no ID. 936 */ 937 public static final int NO_ID = -1; 938 939 /** 940 * Last ID that is given to Views that are no part of activities. 941 * 942 * {@hide} 943 */ 944 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 945 946 /** 947 * Attribute to find the autofilled highlight 948 * 949 * @see #getAutofilledDrawable() 950 */ 951 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 952 new int[]{android.R.attr.autofilledHighlight}; 953 954 /** 955 * Signals that compatibility booleans have been initialized according to 956 * target SDK versions. 957 */ 958 private static boolean sCompatibilityDone = false; 959 960 /** @hide */ 961 public HapticScrollFeedbackProvider mScrollFeedbackProvider = null; 962 963 /** 964 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 965 */ 966 private static boolean sAlwaysRemeasureExactly = false; 967 968 /** 969 * When true makes it possible to use onMeasure caches also when the force layout flag is 970 * enabled. This helps avoiding multiple measures in the same frame with the same dimensions. 971 */ 972 private static boolean sUseMeasureCacheDuringForceLayoutFlagValue; 973 974 /** 975 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 976 * without throwing 977 */ 978 static boolean sTextureViewIgnoresDrawableSetters = false; 979 980 /** 981 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 982 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 983 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 984 * check is implemented for backwards compatibility. 985 * 986 * {@hide} 987 */ 988 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 989 990 /** 991 * Prior to N, when drag enters into child of a view that has already received an 992 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 993 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 994 * false from its event handler for these events. 995 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 996 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 997 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 998 */ 999 static boolean sCascadedDragDrop; 1000 1001 /** 1002 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 1003 * to determine things like whether or not to permit item click events. We can't break 1004 * apps that do this just because more things (clickable things) are now auto-focusable 1005 * and they would get different results, so give old behavior to old apps. 1006 */ 1007 static boolean sHasFocusableExcludeAutoFocusable; 1008 1009 /** 1010 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 1011 * made focusable by default. As a result, apps could (incorrectly) change the clickable 1012 * setting of views off the UI thread. Now that clickable can effect the focusable state, 1013 * changing the clickable attribute off the UI thread will cause an exception (since changing 1014 * the focusable state checks). In order to prevent apps from crashing, we will handle this 1015 * specific case and just not notify parents on new focusables resulting from marking views 1016 * clickable from outside the UI thread. 1017 */ 1018 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 1019 1020 /** 1021 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 1022 * Float.NaN. If the app is targetting P or later then passing these values will result in an 1023 * exception being thrown. If the app is targetting an earlier SDK version, then we will 1024 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 1025 * these bogus values. 1026 */ 1027 private static boolean sThrowOnInvalidFloatProperties; 1028 1029 /** 1030 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 1031 * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead. 1032 */ 1033 private static boolean sAcceptZeroSizeDragShadow; 1034 1035 /** 1036 * When true, measure and layout passes of all the newly attached views will be logged with 1037 * {@link Trace}, so we can better debug jank due to complex view hierarchies. 1038 */ 1039 private static boolean sTraceLayoutSteps; 1040 1041 /** 1042 * When not null, emits a {@link Trace} instant event and the stacktrace every time a relayout 1043 * of a class having this name happens. 1044 */ 1045 private static String sTraceRequestLayoutClass; 1046 1047 @Nullable 1048 private ViewCredentialHandler mViewCredentialHandler; 1049 1050 /** Used to avoid computing the full strings each time when layout tracing is enabled. */ 1051 @Nullable 1052 private ViewTraversalTracingStrings mTracingStrings; 1053 1054 /** 1055 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 1056 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 1057 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 1058 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 1059 * thus, the hierarchical dispatching mechanism was hard to use for apps. 1060 * <p> 1061 * In order to make window inset dispatching work properly, we dispatch window insets 1062 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 1063 */ 1064 static boolean sBrokenInsetsDispatch; 1065 1066 /** 1067 * Prior to Q, calling 1068 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 1069 * did not call update the window format so the opacity of the background was not correctly 1070 * applied to the window. Some applications rely on this misbehavior to work properly. 1071 * <p> 1072 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 1073 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 1074 * which updates the window format. 1075 * @hide 1076 */ 1077 protected static boolean sBrokenWindowBackground; 1078 1079 /** 1080 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 1081 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 1082 * calling {@link #requestLayout} when they need to relayout based on an insets change. 1083 */ 1084 static boolean sForceLayoutWhenInsetsChanged; 1085 1086 /** @hide */ 1087 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 1088 @Retention(RetentionPolicy.SOURCE) 1089 public @interface Focusable {} 1090 1091 /** 1092 * This view does not want keystrokes. 1093 * <p> 1094 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1095 * android:focusable}. 1096 */ 1097 public static final int NOT_FOCUSABLE = 0x00000000; 1098 1099 /** 1100 * This view wants keystrokes. 1101 * <p> 1102 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1103 * android:focusable}. 1104 */ 1105 public static final int FOCUSABLE = 0x00000001; 1106 1107 /** 1108 * This view determines focusability automatically. This is the default. 1109 * <p> 1110 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1111 * android:focusable}. 1112 */ 1113 public static final int FOCUSABLE_AUTO = 0x00000010; 1114 1115 /** 1116 * Mask for use with setFlags indicating bits used for focus. 1117 */ 1118 private static final int FOCUSABLE_MASK = 0x00000011; 1119 1120 /** 1121 * This view will adjust its padding to fit system windows (e.g. status bar) 1122 */ 1123 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1124 1125 /** @hide */ 1126 @IntDef({VISIBLE, INVISIBLE, GONE}) 1127 @Retention(RetentionPolicy.SOURCE) 1128 public @interface Visibility {} 1129 1130 /** 1131 * This view is visible. 1132 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1133 * android:visibility}. 1134 */ 1135 public static final int VISIBLE = 0x00000000; 1136 1137 /** 1138 * This view is invisible, but it still takes up space for layout purposes. 1139 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1140 * android:visibility}. 1141 */ 1142 public static final int INVISIBLE = 0x00000004; 1143 1144 /** 1145 * This view is invisible, and it doesn't take any space for layout 1146 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1147 * android:visibility}. 1148 */ 1149 public static final int GONE = 0x00000008; 1150 1151 /** 1152 * Mask for use with setFlags indicating bits used for visibility. 1153 * {@hide} 1154 */ 1155 static final int VISIBILITY_MASK = 0x0000000C; 1156 1157 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1158 1159 /** 1160 * Hint indicating that this view can be autofilled with an email address. 1161 * 1162 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1163 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1164 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1165 * 1166 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1167 */ 1168 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1169 1170 /** 1171 * Hint indicating that this view can be autofilled with a user's real name. 1172 * 1173 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1174 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1175 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1176 * 1177 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1178 */ 1179 public static final String AUTOFILL_HINT_NAME = "name"; 1180 1181 /** 1182 * Hint indicating that this view can be autofilled with a username. 1183 * 1184 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1185 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1186 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1187 * 1188 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1189 */ 1190 public static final String AUTOFILL_HINT_USERNAME = "username"; 1191 1192 /** 1193 * Hint indicating that this view can be autofilled with a password. 1194 * 1195 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1196 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1197 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1198 * 1199 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1200 */ 1201 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1202 1203 /** 1204 * Hint indicating that this view can be autofilled with a phone number. 1205 * 1206 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1207 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1208 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1209 * 1210 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1211 */ 1212 public static final String AUTOFILL_HINT_PHONE = "phone"; 1213 1214 /** 1215 * Hint indicating that this view can be autofilled with a postal address. 1216 * 1217 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1218 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1219 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1220 * 1221 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1222 */ 1223 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1224 1225 /** 1226 * Hint indicating that this view can be autofilled with a postal code. 1227 * 1228 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1229 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1230 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1231 * 1232 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1233 */ 1234 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1235 1236 /** 1237 * Hint indicating that this view can be autofilled with a credit card number. 1238 * 1239 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1240 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1241 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1242 * 1243 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1244 */ 1245 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1246 1247 /** 1248 * Hint indicating that this view can be autofilled with a credit card security code. 1249 * 1250 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1251 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1252 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1253 * 1254 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1255 */ 1256 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1257 1258 /** 1259 * Hint indicating that this view can be autofilled with a credit card expiration date. 1260 * 1261 * <p>It should be used when the credit card expiration date is represented by just one view; 1262 * if it is represented by more than one (for example, one view for the month and another view 1263 * for the year), then each of these views should use the hint specific for the unit 1264 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1265 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1266 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1267 * 1268 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1269 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1270 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1271 * 1272 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1273 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1274 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1275 * the following options: 1276 * 1277 * <ul> 1278 * <li>{@code "04/2020"} 1279 * <li>{@code "4/2020"} 1280 * <li>{@code "2020/04"} 1281 * <li>{@code "2020/4"} 1282 * <li>{@code "April/2020"} 1283 * <li>{@code "Apr/2020"} 1284 * </ul> 1285 * 1286 * <p>You define a date autofill value for the view by overriding the following methods: 1287 * 1288 * <ol> 1289 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1290 * <li>{@link #getAutofillValue()} to return a 1291 * {@link AutofillValue#forDate(long) date autofillvalue}. 1292 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1293 * </ol> 1294 * 1295 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1296 */ 1297 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1298 "creditCardExpirationDate"; 1299 1300 /** 1301 * Hint indicating that this view can be autofilled with a credit card expiration month. 1302 * 1303 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1304 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1305 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1306 * 1307 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1308 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1309 * ambiguity when the autofill service provides a value for it. To understand why a 1310 * value can be ambiguous, consider "January", which could be represented as either of 1311 * 1312 * <ul> 1313 * <li>{@code "1"}: recommended way. 1314 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1315 * <li>{@code "January"}: full name, in English. 1316 * <li>{@code "jan"}: abbreviated name, in English. 1317 * <li>{@code "Janeiro"}: full name, in another language. 1318 * </ul> 1319 * 1320 * <p>Another recommended approach is to use a date autofill value - see 1321 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1322 * 1323 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1324 */ 1325 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1326 "creditCardExpirationMonth"; 1327 1328 /** 1329 * Hint indicating that this view can be autofilled with a credit card expiration year. 1330 * 1331 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1332 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1333 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1334 * 1335 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1336 */ 1337 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1338 "creditCardExpirationYear"; 1339 1340 /** 1341 * Hint indicating that this view can be autofilled with a credit card expiration day. 1342 * 1343 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1344 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1345 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1346 * 1347 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1348 */ 1349 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1350 1351 /** 1352 * A hint indicating that this view can be autofilled with a password. 1353 * 1354 * This is a heuristic-based hint that is meant to be used by UI Toolkit developers when a 1355 * view is a password field but doesn't specify a 1356 * <code>{@value View#AUTOFILL_HINT_PASSWORD}</code>. 1357 * @hide 1358 */ 1359 // TODO(229765029): unhide this for UI toolkit 1360 public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto"; 1361 1362 /** 1363 * Hint indicating that the developer intends to fill this view with output from 1364 * CredentialManager. 1365 * 1366 * @hide 1367 */ 1368 public static final String AUTOFILL_HINT_CREDENTIAL_MANAGER = "credential"; 1369 1370 /** 1371 * Hints for the autofill services that describes the content of the view. 1372 */ 1373 private @Nullable String[] mAutofillHints; 1374 1375 /** 1376 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1377 */ 1378 private AutofillId mAutofillId; 1379 1380 /** @hide */ 1381 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1382 AUTOFILL_TYPE_NONE, 1383 AUTOFILL_TYPE_TEXT, 1384 AUTOFILL_TYPE_TOGGLE, 1385 AUTOFILL_TYPE_LIST, 1386 AUTOFILL_TYPE_DATE, 1387 }) 1388 @Retention(RetentionPolicy.SOURCE) 1389 public @interface AutofillType {} 1390 1391 /** 1392 * Autofill type for views that cannot be autofilled. 1393 * 1394 * <p>Typically used when the view is read-only; for example, a text label. 1395 * 1396 * @see #getAutofillType() 1397 */ 1398 public static final int AUTOFILL_TYPE_NONE = 0; 1399 1400 /** 1401 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1402 * 1403 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1404 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1405 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1406 * 1407 * @see #getAutofillType() 1408 */ 1409 public static final int AUTOFILL_TYPE_TEXT = 1; 1410 1411 /** 1412 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1413 * 1414 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1415 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1416 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1417 * 1418 * @see #getAutofillType() 1419 */ 1420 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1421 1422 /** 1423 * Autofill type for a selection list field, which is filled by an {@code int} 1424 * representing the element index inside the list (starting at {@code 0}). 1425 * 1426 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1427 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1428 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1429 * 1430 * <p>The available options in the selection list are typically provided by 1431 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1432 * 1433 * @see #getAutofillType() 1434 */ 1435 public static final int AUTOFILL_TYPE_LIST = 3; 1436 1437 /** 1438 * Autofill type for a field that contains a date, which is represented by a long representing 1439 * the number of milliseconds since the standard base time known as "the epoch", namely 1440 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1441 * 1442 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1443 * {@link AutofillValue#forDate(long)}, and the values passed to 1444 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1445 * 1446 * @see #getAutofillType() 1447 */ 1448 public static final int AUTOFILL_TYPE_DATE = 4; 1449 1450 1451 /** @hide */ 1452 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1453 IMPORTANT_FOR_AUTOFILL_AUTO, 1454 IMPORTANT_FOR_AUTOFILL_YES, 1455 IMPORTANT_FOR_AUTOFILL_NO, 1456 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1457 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1458 }) 1459 @Retention(RetentionPolicy.SOURCE) 1460 public @interface AutofillImportance {} 1461 1462 /** 1463 * Automatically determine whether a view is important for autofill. 1464 * 1465 * @see #isImportantForAutofill() 1466 * @see #setImportantForAutofill(int) 1467 */ 1468 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1469 1470 /** 1471 * The view is important for autofill, and its children (if any) will be traversed. 1472 * 1473 * @see #isImportantForAutofill() 1474 * @see #setImportantForAutofill(int) 1475 */ 1476 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1477 1478 /** 1479 * The view is not important for autofill, but its children (if any) will be traversed. 1480 * 1481 * @see #isImportantForAutofill() 1482 * @see #setImportantForAutofill(int) 1483 */ 1484 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1485 1486 /** 1487 * The view is important for autofill, but its children (if any) will not be traversed. 1488 * 1489 * @see #isImportantForAutofill() 1490 * @see #setImportantForAutofill(int) 1491 */ 1492 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1493 1494 /** 1495 * The view is not important for autofill, and its children (if any) will not be traversed. 1496 * 1497 * @see #isImportantForAutofill() 1498 * @see #setImportantForAutofill(int) 1499 */ 1500 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1501 1502 /** @hide */ 1503 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1504 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1505 }) 1506 @Retention(RetentionPolicy.SOURCE) 1507 public @interface AutofillFlags {} 1508 1509 /** 1510 * Flag requesting you to add views that are marked as not important for autofill 1511 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1512 */ 1513 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1514 1515 /** @hide */ 1516 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1517 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1518 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1519 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1520 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1521 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1522 }) 1523 @Retention(RetentionPolicy.SOURCE) 1524 public @interface ContentCaptureImportance {} 1525 1526 /** 1527 * Automatically determine whether a view is important for content capture. 1528 * 1529 * @see #isImportantForContentCapture() 1530 * @see #setImportantForContentCapture(int) 1531 */ 1532 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1533 1534 /** 1535 * The view is important for content capture, and its children (if any) will be traversed. 1536 * 1537 * @see #isImportantForContentCapture() 1538 * @see #setImportantForContentCapture(int) 1539 */ 1540 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1541 1542 /** 1543 * The view is not important for content capture, but its children (if any) will be traversed. 1544 * 1545 * @see #isImportantForContentCapture() 1546 * @see #setImportantForContentCapture(int) 1547 */ 1548 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1549 1550 /** 1551 * The view is important for content capture, but its children (if any) will not be traversed. 1552 * 1553 * @see #isImportantForContentCapture() 1554 * @see #setImportantForContentCapture(int) 1555 */ 1556 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1557 1558 /** 1559 * The view is not important for content capture, and its children (if any) will not be 1560 * traversed. 1561 * 1562 * @see #isImportantForContentCapture() 1563 * @see #setImportantForContentCapture(int) 1564 */ 1565 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1566 1567 /** {@hide} */ 1568 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1569 value = { 1570 SCROLL_CAPTURE_HINT_AUTO, 1571 SCROLL_CAPTURE_HINT_EXCLUDE, 1572 SCROLL_CAPTURE_HINT_INCLUDE, 1573 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1574 }) 1575 @Retention(RetentionPolicy.SOURCE) 1576 public @interface ScrollCaptureHint {} 1577 1578 /** 1579 * The content of this view will be considered for scroll capture if scrolling is possible. 1580 * 1581 * @see #getScrollCaptureHint() 1582 * @see #setScrollCaptureHint(int) 1583 */ 1584 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1585 1586 /** 1587 * Explicitly exclude this view as a potential scroll capture target. The system will not 1588 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1589 * takes precedence over. 1590 * 1591 * @see #getScrollCaptureHint() 1592 * @see #setScrollCaptureHint(int) 1593 */ 1594 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1595 1596 /** 1597 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1598 * capture target, this view will be prioritized before others without this flag. Mutually 1599 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1600 * 1601 * @see #getScrollCaptureHint() 1602 * @see #setScrollCaptureHint(int) 1603 */ 1604 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1605 1606 /** 1607 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1608 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1609 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1610 * 1611 * @see #getScrollCaptureHint() 1612 * @see #setScrollCaptureHint(int) 1613 */ 1614 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1615 1616 /** 1617 * This view is enabled. Interpretation varies by subclass. 1618 * Use with ENABLED_MASK when calling setFlags. 1619 * {@hide} 1620 */ 1621 static final int ENABLED = 0x00000000; 1622 1623 /** 1624 * This view is disabled. Interpretation varies by subclass. 1625 * Use with ENABLED_MASK when calling setFlags. 1626 * {@hide} 1627 */ 1628 static final int DISABLED = 0x00000020; 1629 1630 /** 1631 * Mask for use with setFlags indicating bits used for indicating whether 1632 * this view is enabled 1633 * {@hide} 1634 */ 1635 static final int ENABLED_MASK = 0x00000020; 1636 1637 /** 1638 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1639 * called and further optimizations will be performed. It is okay to have 1640 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1641 * {@hide} 1642 */ 1643 static final int WILL_NOT_DRAW = 0x00000080; 1644 1645 /** 1646 * Mask for use with setFlags indicating bits used for indicating whether 1647 * this view is will draw 1648 * {@hide} 1649 */ 1650 static final int DRAW_MASK = 0x00000080; 1651 1652 /** 1653 * <p>This view doesn't show scrollbars.</p> 1654 * {@hide} 1655 */ 1656 static final int SCROLLBARS_NONE = 0x00000000; 1657 1658 /** 1659 * <p>This view shows horizontal scrollbars.</p> 1660 * {@hide} 1661 */ 1662 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1663 1664 /** 1665 * <p>This view shows vertical scrollbars.</p> 1666 * {@hide} 1667 */ 1668 static final int SCROLLBARS_VERTICAL = 0x00000200; 1669 1670 /** 1671 * <p>Mask for use with setFlags indicating bits used for indicating which 1672 * scrollbars are enabled.</p> 1673 * {@hide} 1674 */ 1675 static final int SCROLLBARS_MASK = 0x00000300; 1676 1677 /** 1678 * Indicates that the view should filter touches when its window is obscured. 1679 * Refer to the class comments for more information about this security feature. 1680 * {@hide} 1681 */ 1682 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1683 1684 /** 1685 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1686 * that they are optional and should be skipped if the window has 1687 * requested system UI flags that ignore those insets for layout. 1688 * <p> 1689 * This is only used for support library as of Android R. The framework now uses 1690 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1691 * insets path that loses insets information. 1692 */ 1693 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1694 1695 /** 1696 * <p>This view doesn't show fading edges.</p> 1697 * {@hide} 1698 */ 1699 static final int FADING_EDGE_NONE = 0x00000000; 1700 1701 /** 1702 * <p>This view shows horizontal fading edges.</p> 1703 * {@hide} 1704 */ 1705 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1706 1707 /** 1708 * <p>This view shows vertical fading edges.</p> 1709 * {@hide} 1710 */ 1711 static final int FADING_EDGE_VERTICAL = 0x00002000; 1712 1713 /** 1714 * <p>Mask for use with setFlags indicating bits used for indicating which 1715 * fading edges are enabled.</p> 1716 * {@hide} 1717 */ 1718 static final int FADING_EDGE_MASK = 0x00003000; 1719 1720 /** 1721 * <p>Indicates this view can be clicked. When clickable, a View reacts 1722 * to clicks by notifying the OnClickListener.<p> 1723 * {@hide} 1724 */ 1725 static final int CLICKABLE = 0x00004000; 1726 1727 /** 1728 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1729 * {@hide} 1730 */ 1731 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1732 1733 /** 1734 * <p>Indicates that no icicle should be saved for this view.<p> 1735 * {@hide} 1736 */ 1737 static final int SAVE_DISABLED = 0x000010000; 1738 1739 /** 1740 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1741 * property.</p> 1742 * {@hide} 1743 */ 1744 static final int SAVE_DISABLED_MASK = 0x000010000; 1745 1746 /** 1747 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1748 * {@hide} 1749 */ 1750 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1751 1752 /** 1753 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1754 * {@hide} 1755 */ 1756 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1757 1758 /** @hide */ 1759 @Retention(RetentionPolicy.SOURCE) 1760 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1761 DRAWING_CACHE_QUALITY_LOW, 1762 DRAWING_CACHE_QUALITY_HIGH, 1763 DRAWING_CACHE_QUALITY_AUTO 1764 }) 1765 public @interface DrawingCacheQuality {} 1766 1767 /** 1768 * <p>Enables low quality mode for the drawing cache.</p> 1769 * 1770 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1771 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1772 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1773 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1774 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1775 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1776 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1777 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1778 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1779 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1780 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1781 * reports or unit testing the {@link PixelCopy} API is recommended. 1782 */ 1783 @Deprecated 1784 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1785 1786 /** 1787 * <p>Enables high quality mode for the drawing cache.</p> 1788 * 1789 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1790 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1791 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1792 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1793 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1794 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1795 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1796 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1797 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1798 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1799 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1800 * reports or unit testing the {@link PixelCopy} API is recommended. 1801 */ 1802 @Deprecated 1803 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1804 1805 /** 1806 * <p>Enables automatic quality mode for the drawing cache.</p> 1807 * 1808 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1809 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1810 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1811 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1812 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1813 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1814 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1815 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1816 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1817 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1818 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1819 * reports or unit testing the {@link PixelCopy} API is recommended. 1820 */ 1821 @Deprecated 1822 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1823 1824 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1825 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1826 }; 1827 1828 /** 1829 * <p>Mask for use with setFlags indicating bits used for the cache 1830 * quality property.</p> 1831 * {@hide} 1832 */ 1833 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1834 1835 /** 1836 * <p> 1837 * Indicates this view can be long clicked. When long clickable, a View 1838 * reacts to long clicks by notifying the OnLongClickListener or showing a 1839 * context menu. 1840 * </p> 1841 * {@hide} 1842 */ 1843 static final int LONG_CLICKABLE = 0x00200000; 1844 1845 /** 1846 * <p>Indicates that this view gets its drawable states from its direct parent 1847 * and ignores its original internal states.</p> 1848 * 1849 * @hide 1850 */ 1851 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1852 1853 /** 1854 * <p> 1855 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1856 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1857 * OnContextClickListener. 1858 * </p> 1859 * {@hide} 1860 */ 1861 static final int CONTEXT_CLICKABLE = 0x00800000; 1862 1863 /** @hide */ 1864 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1865 SCROLLBARS_INSIDE_OVERLAY, 1866 SCROLLBARS_INSIDE_INSET, 1867 SCROLLBARS_OUTSIDE_OVERLAY, 1868 SCROLLBARS_OUTSIDE_INSET 1869 }) 1870 @Retention(RetentionPolicy.SOURCE) 1871 public @interface ScrollBarStyle {} 1872 1873 /** 1874 * The scrollbar style to display the scrollbars inside the content area, 1875 * without increasing the padding. The scrollbars will be overlaid with 1876 * translucency on the view's content. 1877 */ 1878 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1879 1880 /** 1881 * The scrollbar style to display the scrollbars inside the padded area, 1882 * increasing the padding of the view. The scrollbars will not overlap the 1883 * content area of the view. 1884 */ 1885 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1886 1887 /** 1888 * The scrollbar style to display the scrollbars at the edge of the view, 1889 * without increasing the padding. The scrollbars will be overlaid with 1890 * translucency. 1891 */ 1892 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1893 1894 /** 1895 * The scrollbar style to display the scrollbars at the edge of the view, 1896 * increasing the padding of the view. The scrollbars will only overlap the 1897 * background, if any. 1898 */ 1899 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1900 1901 /** 1902 * Mask to check if the scrollbar style is overlay or inset. 1903 * {@hide} 1904 */ 1905 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1906 1907 /** 1908 * Mask to check if the scrollbar style is inside or outside. 1909 * {@hide} 1910 */ 1911 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1912 1913 /** 1914 * Mask for scrollbar style. 1915 * {@hide} 1916 */ 1917 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1918 1919 /** 1920 * View flag indicating that the screen should remain on while the 1921 * window containing this view is visible to the user. This effectively 1922 * takes care of automatically setting the WindowManager's 1923 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1924 */ 1925 public static final int KEEP_SCREEN_ON = 0x04000000; 1926 1927 /** 1928 * View flag indicating whether this view should have sound effects enabled 1929 * for events such as clicking and touching. 1930 */ 1931 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1932 1933 /** 1934 * View flag indicating whether this view should have haptic feedback 1935 * enabled for events such as long presses. 1936 */ 1937 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1938 1939 /** 1940 * <p>Indicates that the view hierarchy should stop saving state when 1941 * it reaches this view. If state saving is initiated immediately at 1942 * the view, it will be allowed. 1943 * {@hide} 1944 */ 1945 static final int PARENT_SAVE_DISABLED = 0x20000000; 1946 1947 /** 1948 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1949 * {@hide} 1950 */ 1951 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1952 1953 private static Paint sDebugPaint; 1954 1955 /** 1956 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1957 * {@hide} 1958 */ 1959 static final int TOOLTIP = 0x40000000; 1960 1961 /** @hide */ 1962 @IntDef(prefix = { "CONTENT_SENSITIVITY_" }, value = { 1963 CONTENT_SENSITIVITY_AUTO, 1964 CONTENT_SENSITIVITY_SENSITIVE, 1965 CONTENT_SENSITIVITY_NOT_SENSITIVE 1966 }) 1967 @Retention(RetentionPolicy.SOURCE) 1968 public @interface ContentSensitivity {} 1969 1970 /** 1971 * Content sensitivity is determined by the framework. The framework uses a heuristic to 1972 * determine if this view displays sensitive content. 1973 * Autofill hints i.e. {@link #getAutofillHints()} are used in the heuristic 1974 * to determine if this view should be considered as a sensitive view. 1975 * <p> 1976 * {@link #AUTOFILL_HINT_USERNAME}, 1977 * {@link #AUTOFILL_HINT_PASSWORD}, 1978 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, 1979 * {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 1980 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 1981 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1982 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1983 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR} 1984 * are considered sensitive hints by the framework, and the list may include more hints 1985 * in the future. 1986 * 1987 * <p> The window hosting a sensitive view will be marked as secure during an active media 1988 * projection session. This would be equivalent to applying 1989 * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. 1990 * 1991 * @see #getContentSensitivity() 1992 */ 1993 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 1994 public static final int CONTENT_SENSITIVITY_AUTO = 0x0; 1995 1996 /** 1997 * The view displays sensitive content. 1998 * 1999 * <p> The window hosting a sensitive view will be marked as secure during an active media 2000 * projection session. This would be equivalent to applying 2001 * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. 2002 * 2003 * @see #getContentSensitivity() 2004 */ 2005 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 2006 public static final int CONTENT_SENSITIVITY_SENSITIVE = 0x1; 2007 2008 /** 2009 * The view doesn't display sensitive content. 2010 * 2011 * @see #getContentSensitivity() 2012 */ 2013 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 2014 public static final int CONTENT_SENSITIVITY_NOT_SENSITIVE = 0x2; 2015 2016 /** @hide */ 2017 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 2018 FOCUSABLES_ALL, 2019 FOCUSABLES_TOUCH_MODE 2020 }) 2021 @Retention(RetentionPolicy.SOURCE) 2022 public @interface FocusableMode {} 2023 2024 /** 2025 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 2026 * should add all focusable Views regardless if they are focusable in touch mode. 2027 */ 2028 public static final int FOCUSABLES_ALL = 0x00000000; 2029 2030 /** 2031 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 2032 * should add only Views focusable in touch mode. 2033 */ 2034 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 2035 2036 /** @hide */ 2037 @IntDef(prefix = { "FOCUS_" }, value = { 2038 FOCUS_BACKWARD, 2039 FOCUS_FORWARD, 2040 FOCUS_LEFT, 2041 FOCUS_UP, 2042 FOCUS_RIGHT, 2043 FOCUS_DOWN 2044 }) 2045 @Retention(RetentionPolicy.SOURCE) 2046 public @interface FocusDirection {} 2047 2048 /** @hide */ 2049 @IntDef(prefix = { "FOCUS_" }, value = { 2050 FOCUS_LEFT, 2051 FOCUS_UP, 2052 FOCUS_RIGHT, 2053 FOCUS_DOWN 2054 }) 2055 @Retention(RetentionPolicy.SOURCE) 2056 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 2057 2058 /** 2059 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 2060 * item. 2061 */ 2062 public static final int FOCUS_BACKWARD = 0x00000001; 2063 2064 /** 2065 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 2066 * item. 2067 */ 2068 public static final int FOCUS_FORWARD = 0x00000002; 2069 2070 /** 2071 * Use with {@link #focusSearch(int)}. Move focus to the left. 2072 */ 2073 public static final int FOCUS_LEFT = 0x00000011; 2074 2075 /** 2076 * Use with {@link #focusSearch(int)}. Move focus up. 2077 */ 2078 public static final int FOCUS_UP = 0x00000021; 2079 2080 /** 2081 * Use with {@link #focusSearch(int)}. Move focus to the right. 2082 */ 2083 public static final int FOCUS_RIGHT = 0x00000042; 2084 2085 /** 2086 * Use with {@link #focusSearch(int)}. Move focus down. 2087 */ 2088 public static final int FOCUS_DOWN = 0x00000082; 2089 2090 /** 2091 * Bits of {@link #getMeasuredWidthAndState()} and 2092 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 2093 */ 2094 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 2095 2096 /** 2097 * Bits of {@link #getMeasuredWidthAndState()} and 2098 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 2099 */ 2100 public static final int MEASURED_STATE_MASK = 0xff000000; 2101 2102 /** 2103 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 2104 * for functions that combine both width and height into a single int, 2105 * such as {@link #getMeasuredState()} and the childState argument of 2106 * {@link #resolveSizeAndState(int, int, int)}. 2107 */ 2108 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 2109 2110 /** 2111 * Bit of {@link #getMeasuredWidthAndState()} and 2112 * {@link #getMeasuredWidthAndState()} that indicates the measured size 2113 * is smaller that the space the view would like to have. 2114 */ 2115 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 2116 2117 /** 2118 * Base View state sets 2119 */ 2120 // Singles 2121 /** 2122 * Indicates the view has no states set. States are used with 2123 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2124 * view depending on its state. 2125 * 2126 * @see android.graphics.drawable.Drawable 2127 * @see #getDrawableState() 2128 */ 2129 protected static final int[] EMPTY_STATE_SET; 2130 /** 2131 * Indicates the view is enabled. States are used with 2132 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2133 * view depending on its state. 2134 * 2135 * @see android.graphics.drawable.Drawable 2136 * @see #getDrawableState() 2137 */ 2138 protected static final int[] ENABLED_STATE_SET; 2139 /** 2140 * Indicates the view is focused. States are used with 2141 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2142 * view depending on its state. 2143 * 2144 * @see android.graphics.drawable.Drawable 2145 * @see #getDrawableState() 2146 */ 2147 protected static final int[] FOCUSED_STATE_SET; 2148 /** 2149 * Indicates the view is selected. States are used with 2150 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2151 * view depending on its state. 2152 * 2153 * @see android.graphics.drawable.Drawable 2154 * @see #getDrawableState() 2155 */ 2156 protected static final int[] SELECTED_STATE_SET; 2157 /** 2158 * Indicates the view is pressed. States are used with 2159 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2160 * view depending on its state. 2161 * 2162 * @see android.graphics.drawable.Drawable 2163 * @see #getDrawableState() 2164 */ 2165 protected static final int[] PRESSED_STATE_SET; 2166 /** 2167 * Indicates the view's window has focus. States are used with 2168 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2169 * view depending on its state. 2170 * 2171 * @see android.graphics.drawable.Drawable 2172 * @see #getDrawableState() 2173 */ 2174 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2175 // Doubles 2176 /** 2177 * Indicates the view is enabled and has the focus. 2178 * 2179 * @see #ENABLED_STATE_SET 2180 * @see #FOCUSED_STATE_SET 2181 */ 2182 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2183 /** 2184 * Indicates the view is enabled and selected. 2185 * 2186 * @see #ENABLED_STATE_SET 2187 * @see #SELECTED_STATE_SET 2188 */ 2189 protected static final int[] ENABLED_SELECTED_STATE_SET; 2190 /** 2191 * Indicates the view is enabled and that its window has focus. 2192 * 2193 * @see #ENABLED_STATE_SET 2194 * @see #WINDOW_FOCUSED_STATE_SET 2195 */ 2196 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2197 /** 2198 * Indicates the view is focused and selected. 2199 * 2200 * @see #FOCUSED_STATE_SET 2201 * @see #SELECTED_STATE_SET 2202 */ 2203 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2204 /** 2205 * Indicates the view has the focus and that its window has the focus. 2206 * 2207 * @see #FOCUSED_STATE_SET 2208 * @see #WINDOW_FOCUSED_STATE_SET 2209 */ 2210 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2211 /** 2212 * Indicates the view is selected and that its window has the focus. 2213 * 2214 * @see #SELECTED_STATE_SET 2215 * @see #WINDOW_FOCUSED_STATE_SET 2216 */ 2217 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2218 // Triples 2219 /** 2220 * Indicates the view is enabled, focused and selected. 2221 * 2222 * @see #ENABLED_STATE_SET 2223 * @see #FOCUSED_STATE_SET 2224 * @see #SELECTED_STATE_SET 2225 */ 2226 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2227 /** 2228 * Indicates the view is enabled, focused and its window has the focus. 2229 * 2230 * @see #ENABLED_STATE_SET 2231 * @see #FOCUSED_STATE_SET 2232 * @see #WINDOW_FOCUSED_STATE_SET 2233 */ 2234 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2235 /** 2236 * Indicates the view is enabled, selected and its window has the focus. 2237 * 2238 * @see #ENABLED_STATE_SET 2239 * @see #SELECTED_STATE_SET 2240 * @see #WINDOW_FOCUSED_STATE_SET 2241 */ 2242 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2243 /** 2244 * Indicates the view is focused, selected and its window has the focus. 2245 * 2246 * @see #FOCUSED_STATE_SET 2247 * @see #SELECTED_STATE_SET 2248 * @see #WINDOW_FOCUSED_STATE_SET 2249 */ 2250 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2251 /** 2252 * Indicates the view is enabled, focused, selected and its window 2253 * has the focus. 2254 * 2255 * @see #ENABLED_STATE_SET 2256 * @see #FOCUSED_STATE_SET 2257 * @see #SELECTED_STATE_SET 2258 * @see #WINDOW_FOCUSED_STATE_SET 2259 */ 2260 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2261 /** 2262 * Indicates the view is pressed and its window has the focus. 2263 * 2264 * @see #PRESSED_STATE_SET 2265 * @see #WINDOW_FOCUSED_STATE_SET 2266 */ 2267 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2268 /** 2269 * Indicates the view is pressed and selected. 2270 * 2271 * @see #PRESSED_STATE_SET 2272 * @see #SELECTED_STATE_SET 2273 */ 2274 protected static final int[] PRESSED_SELECTED_STATE_SET; 2275 /** 2276 * Indicates the view is pressed, selected and its window has the focus. 2277 * 2278 * @see #PRESSED_STATE_SET 2279 * @see #SELECTED_STATE_SET 2280 * @see #WINDOW_FOCUSED_STATE_SET 2281 */ 2282 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2283 /** 2284 * Indicates the view is pressed and focused. 2285 * 2286 * @see #PRESSED_STATE_SET 2287 * @see #FOCUSED_STATE_SET 2288 */ 2289 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2290 /** 2291 * Indicates the view is pressed, focused and its window has the focus. 2292 * 2293 * @see #PRESSED_STATE_SET 2294 * @see #FOCUSED_STATE_SET 2295 * @see #WINDOW_FOCUSED_STATE_SET 2296 */ 2297 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2298 /** 2299 * Indicates the view is pressed, focused and selected. 2300 * 2301 * @see #PRESSED_STATE_SET 2302 * @see #SELECTED_STATE_SET 2303 * @see #FOCUSED_STATE_SET 2304 */ 2305 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2306 /** 2307 * Indicates the view is pressed, focused, selected and its window has the focus. 2308 * 2309 * @see #PRESSED_STATE_SET 2310 * @see #FOCUSED_STATE_SET 2311 * @see #SELECTED_STATE_SET 2312 * @see #WINDOW_FOCUSED_STATE_SET 2313 */ 2314 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2315 /** 2316 * Indicates the view is pressed and enabled. 2317 * 2318 * @see #PRESSED_STATE_SET 2319 * @see #ENABLED_STATE_SET 2320 */ 2321 protected static final int[] PRESSED_ENABLED_STATE_SET; 2322 /** 2323 * Indicates the view is pressed, enabled and its window has the focus. 2324 * 2325 * @see #PRESSED_STATE_SET 2326 * @see #ENABLED_STATE_SET 2327 * @see #WINDOW_FOCUSED_STATE_SET 2328 */ 2329 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2330 /** 2331 * Indicates the view is pressed, enabled and selected. 2332 * 2333 * @see #PRESSED_STATE_SET 2334 * @see #ENABLED_STATE_SET 2335 * @see #SELECTED_STATE_SET 2336 */ 2337 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2338 /** 2339 * Indicates the view is pressed, enabled, selected and its window has the 2340 * focus. 2341 * 2342 * @see #PRESSED_STATE_SET 2343 * @see #ENABLED_STATE_SET 2344 * @see #SELECTED_STATE_SET 2345 * @see #WINDOW_FOCUSED_STATE_SET 2346 */ 2347 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2348 /** 2349 * Indicates the view is pressed, enabled and focused. 2350 * 2351 * @see #PRESSED_STATE_SET 2352 * @see #ENABLED_STATE_SET 2353 * @see #FOCUSED_STATE_SET 2354 */ 2355 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2356 /** 2357 * Indicates the view is pressed, enabled, focused and its window has the 2358 * focus. 2359 * 2360 * @see #PRESSED_STATE_SET 2361 * @see #ENABLED_STATE_SET 2362 * @see #FOCUSED_STATE_SET 2363 * @see #WINDOW_FOCUSED_STATE_SET 2364 */ 2365 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2366 /** 2367 * Indicates the view is pressed, enabled, focused and selected. 2368 * 2369 * @see #PRESSED_STATE_SET 2370 * @see #ENABLED_STATE_SET 2371 * @see #SELECTED_STATE_SET 2372 * @see #FOCUSED_STATE_SET 2373 */ 2374 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2375 /** 2376 * Indicates the view is pressed, enabled, focused, selected and its window 2377 * has the focus. 2378 * 2379 * @see #PRESSED_STATE_SET 2380 * @see #ENABLED_STATE_SET 2381 * @see #SELECTED_STATE_SET 2382 * @see #FOCUSED_STATE_SET 2383 * @see #WINDOW_FOCUSED_STATE_SET 2384 */ 2385 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2386 2387 /** 2388 * This indicates that the frame rate category was chosen for an unknown reason. 2389 * @hide 2390 */ 2391 public static final int FRAME_RATE_CATEGORY_REASON_UNKNOWN = 0x0000_0000; 2392 2393 /** 2394 * This indicates that the frame rate category was chosen because it was a small area update. 2395 * @hide 2396 */ 2397 public static final int FRAME_RATE_CATEGORY_REASON_SMALL = 0x0100_0000; 2398 2399 /** 2400 * This indicates that the frame rate category was chosen because it was an intermittent update. 2401 * @hide 2402 */ 2403 public static final int FRAME_RATE_CATEGORY_REASON_INTERMITTENT = 0x0200_0000; 2404 2405 /** 2406 * This indicates that the frame rate category was chosen because it was a large View. 2407 * @hide 2408 */ 2409 public static final int FRAME_RATE_CATEGORY_REASON_LARGE = 0x03000000; 2410 2411 /** 2412 * This indicates that the frame rate category was chosen because it was requested. 2413 * @hide 2414 */ 2415 public static final int FRAME_RATE_CATEGORY_REASON_REQUESTED = 0x0400_0000; 2416 2417 /** 2418 * This indicates that the frame rate category was chosen because an invalid frame rate was 2419 * requested. 2420 * @hide 2421 */ 2422 public static final int FRAME_RATE_CATEGORY_REASON_INVALID = 0x0500_0000; 2423 2424 /** 2425 * This indicates that the frame rate category was chosen because the view has a velocity 2426 * @hide 2427 */ 2428 public static final int FRAME_RATE_CATEGORY_REASON_VELOCITY = 0x0600_0000; 2429 2430 /** 2431 * This indicates that the frame rate category was chosen because it is currently boosting. 2432 * @hide 2433 */ 2434 public static final int FRAME_RATE_CATEGORY_REASON_BOOST = 0x0800_0000; 2435 2436 /** 2437 * This indicates that the frame rate category was chosen because it is currently having 2438 * touch boost. 2439 * @hide 2440 */ 2441 public static final int FRAME_RATE_CATEGORY_REASON_TOUCH = 0x0900_0000; 2442 2443 /** 2444 * This indicates that the frame rate category was chosen because it is currently having 2445 * touch boost. 2446 * @hide 2447 */ 2448 public static final int FRAME_RATE_CATEGORY_REASON_CONFLICTED = 0x0A00_0000; 2449 2450 private static final int FRAME_RATE_CATEGORY_REASON_MASK = 0xFFFF_0000; 2451 2452 /** 2453 * @hide 2454 */ 2455 protected static boolean sToolkitSetFrameRateReadOnlyFlagValue; 2456 private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; 2457 private static final boolean sToolkitFrameRateDefaultNormalReadOnlyFlagValue = 2458 toolkitFrameRateDefaultNormalReadOnly(); 2459 private static final boolean sToolkitFrameRateBySizeReadOnlyFlagValue = 2460 toolkitFrameRateBySizeReadOnly(); 2461 2462 private static final boolean sToolkitFrameRateSmallUsesPercentReadOnlyFlagValue = 2463 toolkitFrameRateSmallUsesPercentReadOnly(); 2464 private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue = 2465 toolkitFrameRateViewEnablingReadOnly(); 2466 private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue = 2467 toolkitFrameRateVelocityMappingReadOnly(); 2468 2469 // Used to set frame rate compatibility. 2470 @Surface.FrameRateCompatibility int mFrameRateCompatibility = 2471 FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 2472 2473 static { 2474 EMPTY_STATE_SET = StateSet.get(0); 2475 2476 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2477 2478 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2479 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2480 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2481 2482 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2483 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2484 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2485 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2486 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2487 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2488 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2489 | StateSet.VIEW_STATE_FOCUSED); 2490 2491 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2492 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2493 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2494 ENABLED_SELECTED_STATE_SET = StateSet.get( 2495 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2496 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2497 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2498 | StateSet.VIEW_STATE_ENABLED); 2499 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2500 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2501 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2502 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2503 | StateSet.VIEW_STATE_ENABLED); 2504 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2505 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2506 | StateSet.VIEW_STATE_ENABLED); 2507 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2508 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2509 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2510 2511 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2512 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2513 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2514 PRESSED_SELECTED_STATE_SET = StateSet.get( 2515 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2516 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2517 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2518 | StateSet.VIEW_STATE_PRESSED); 2519 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2520 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2521 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2522 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2523 | StateSet.VIEW_STATE_PRESSED); 2524 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2525 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2526 | StateSet.VIEW_STATE_PRESSED); 2527 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2528 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2529 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2530 PRESSED_ENABLED_STATE_SET = StateSet.get( 2531 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2532 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2533 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2534 | StateSet.VIEW_STATE_PRESSED); 2535 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2536 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2537 | StateSet.VIEW_STATE_PRESSED); 2538 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2539 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2540 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2541 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2542 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2543 | StateSet.VIEW_STATE_PRESSED); 2544 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2545 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2546 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2547 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2548 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2549 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2550 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2551 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2552 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2553 | StateSet.VIEW_STATE_PRESSED); 2554 2555 sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); 2556 sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); 2557 sUseMeasureCacheDuringForceLayoutFlagValue = enableUseMeasureCacheDuringForceLayout(); 2558 } 2559 2560 /** 2561 * Accessibility event types that are dispatched for text population. 2562 */ 2563 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2564 AccessibilityEvent.TYPE_VIEW_CLICKED 2565 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2566 | AccessibilityEvent.TYPE_VIEW_SELECTED 2567 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2568 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2569 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2570 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2571 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2572 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2573 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2574 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2575 2576 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2577 2578 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2579 2580 /** 2581 * Temporary Rect currently for use in setBackground(). This will probably 2582 * be extended in the future to hold our own class with more than just 2583 * a Rect. :) 2584 */ 2585 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2586 2587 /** 2588 * Map used to store views' tags. 2589 */ 2590 @UnsupportedAppUsage 2591 private SparseArray<Object> mKeyedTags; 2592 2593 /** 2594 * The next available accessibility id. 2595 */ 2596 private static int sNextAccessibilityViewId; 2597 2598 /** 2599 * The animation currently associated with this view. 2600 * @hide 2601 */ 2602 protected Animation mCurrentAnimation = null; 2603 2604 /** 2605 * Width as measured during measure pass. 2606 * {@hide} 2607 */ 2608 @ViewDebug.ExportedProperty(category = "measurement") 2609 @UnsupportedAppUsage 2610 int mMeasuredWidth; 2611 2612 /** 2613 * Height as measured during measure pass. 2614 * {@hide} 2615 */ 2616 @ViewDebug.ExportedProperty(category = "measurement") 2617 @UnsupportedAppUsage 2618 int mMeasuredHeight; 2619 2620 /** 2621 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2622 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2623 * its display list. This flag, used only when hw accelerated, allows us to clear the 2624 * flag while retaining this information until it's needed (at getDisplayList() time and 2625 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2626 * 2627 * {@hide} 2628 */ 2629 @UnsupportedAppUsage 2630 boolean mRecreateDisplayList = false; 2631 2632 /** 2633 * The view's identifier. 2634 * {@hide} 2635 * 2636 * @see #setId(int) 2637 * @see #getId() 2638 */ 2639 @IdRes 2640 @ViewDebug.ExportedProperty(resolveId = true) 2641 int mID = NO_ID; 2642 2643 /** The ID of this view for autofill purposes. 2644 * <ul> 2645 * <li>== {@link #NO_ID}: ID has not been assigned yet 2646 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2647 * unique in the process. This might change 2648 * over activity lifecycle events. 2649 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2650 * unique in the activity. This stays the same 2651 * over activity lifecycle events. 2652 */ 2653 private int mAutofillViewId = NO_ID; 2654 2655 // ID for accessibility purposes. This ID must be unique for every window 2656 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2657 private int mAccessibilityViewId = NO_ID; 2658 2659 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2660 2661 /** 2662 * The view's tag. 2663 * {@hide} 2664 * 2665 * @see #setTag(Object) 2666 * @see #getTag() 2667 */ 2668 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2669 protected Object mTag = null; 2670 2671 /* 2672 * Masks for mPrivateFlags, as generated by dumpFlags(): 2673 * 2674 * |-------|-------|-------|-------| 2675 * 1 PFLAG_WANTS_FOCUS 2676 * 1 PFLAG_FOCUSED 2677 * 1 PFLAG_SELECTED 2678 * 1 PFLAG_IS_ROOT_NAMESPACE 2679 * 1 PFLAG_HAS_BOUNDS 2680 * 1 PFLAG_DRAWN 2681 * 1 PFLAG_DRAW_ANIMATION 2682 * 1 PFLAG_SKIP_DRAW 2683 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2684 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2685 * 1 PFLAG_MEASURED_DIMENSION_SET 2686 * 1 PFLAG_FORCE_LAYOUT 2687 * 1 PFLAG_LAYOUT_REQUIRED 2688 * 1 PFLAG_PRESSED 2689 * 1 PFLAG_DRAWING_CACHE_VALID 2690 * 1 PFLAG_ANIMATION_STARTED 2691 * 1 PFLAG_SAVE_STATE_CALLED 2692 * 1 PFLAG_ALPHA_SET 2693 * 1 PFLAG_SCROLL_CONTAINER 2694 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2695 * 1 PFLAG_DIRTY 2696 * 1 PFLAG_DIRTY_MASK 2697 * 1 PFLAG_OPAQUE_BACKGROUND 2698 * 1 PFLAG_OPAQUE_SCROLLBARS 2699 * 11 PFLAG_OPAQUE_MASK 2700 * 1 PFLAG_PREPRESSED 2701 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2702 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2703 * 1 PFLAG_HOVERED 2704 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2705 * 1 PFLAG_ACTIVATED 2706 * 1 PFLAG_INVALIDATED 2707 * |-------|-------|-------|-------| 2708 */ 2709 /** {@hide} */ 2710 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2711 /** {@hide} */ 2712 static final int PFLAG_FOCUSED = 0x00000002; 2713 /** {@hide} */ 2714 static final int PFLAG_SELECTED = 0x00000004; 2715 /** {@hide} */ 2716 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2717 /** {@hide} */ 2718 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2719 /** {@hide} */ 2720 static final int PFLAG_DRAWN = 0x00000020; 2721 /** 2722 * When this flag is set, this view is running an animation on behalf of its 2723 * children and should therefore not cancel invalidate requests, even if they 2724 * lie outside of this view's bounds. 2725 * 2726 * {@hide} 2727 */ 2728 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2729 /** {@hide} */ 2730 static final int PFLAG_SKIP_DRAW = 0x00000080; 2731 /** {@hide} */ 2732 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2733 /** {@hide} */ 2734 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2735 /** {@hide} */ 2736 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2737 /** {@hide} */ 2738 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2739 /** {@hide} */ 2740 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2741 2742 private static final int PFLAG_PRESSED = 0x00004000; 2743 2744 /** {@hide} */ 2745 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2746 /** 2747 * Flag used to indicate that this view should be drawn once more (and only once 2748 * more) after its animation has completed. 2749 * {@hide} 2750 */ 2751 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2752 2753 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2754 2755 /** 2756 * Indicates that the View returned true when onSetAlpha() was called and that 2757 * the alpha must be restored. 2758 * {@hide} 2759 */ 2760 static final int PFLAG_ALPHA_SET = 0x00040000; 2761 2762 /** 2763 * Set by {@link #setScrollContainer(boolean)}. 2764 */ 2765 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2766 2767 /** 2768 * Set by {@link #setScrollContainer(boolean)}. 2769 */ 2770 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2771 2772 /** 2773 * View flag indicating whether this view was invalidated (fully or partially.) 2774 * 2775 * @hide 2776 */ 2777 static final int PFLAG_DIRTY = 0x00200000; 2778 2779 /** 2780 * Mask for {@link #PFLAG_DIRTY}. 2781 * 2782 * @hide 2783 */ 2784 static final int PFLAG_DIRTY_MASK = 0x00200000; 2785 2786 /** 2787 * Indicates whether the background is opaque. 2788 * 2789 * @hide 2790 */ 2791 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2792 2793 /** 2794 * Indicates whether the scrollbars are opaque. 2795 * 2796 * @hide 2797 */ 2798 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2799 2800 /** 2801 * Indicates whether the view is opaque. 2802 * 2803 * @hide 2804 */ 2805 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2806 2807 /** 2808 * Indicates a prepressed state; 2809 * the short time between ACTION_DOWN and recognizing 2810 * a 'real' press. Prepressed is used to recognize quick taps 2811 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2812 * 2813 * @hide 2814 */ 2815 private static final int PFLAG_PREPRESSED = 0x02000000; 2816 2817 /** 2818 * Indicates whether the view is temporarily detached. 2819 * 2820 * @hide 2821 */ 2822 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2823 2824 /** 2825 * Indicates that we should awaken scroll bars once attached 2826 * 2827 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2828 * during window attachment and it is no longer needed. Feel free to repurpose it. 2829 * 2830 * @hide 2831 */ 2832 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2833 2834 /** 2835 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2836 * @hide 2837 */ 2838 private static final int PFLAG_HOVERED = 0x10000000; 2839 2840 /** 2841 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2842 */ 2843 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2844 2845 /** {@hide} */ 2846 static final int PFLAG_ACTIVATED = 0x40000000; 2847 2848 /** 2849 * Indicates that this view was specifically invalidated, not just dirtied because some 2850 * child view was invalidated. The flag is used to determine when we need to recreate 2851 * a view's display list (as opposed to just returning a reference to its existing 2852 * display list). 2853 * 2854 * @hide 2855 */ 2856 static final int PFLAG_INVALIDATED = 0x80000000; 2857 2858 /* End of masks for mPrivateFlags */ 2859 2860 /* 2861 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2862 * 2863 * |-------|-------|-------|-------| 2864 * 1 PFLAG2_DRAG_CAN_ACCEPT 2865 * 1 PFLAG2_DRAG_HOVERED 2866 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2867 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2868 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2869 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2870 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2871 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2872 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2873 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2874 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2875 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2876 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2877 * 111 PFLAG2_TEXT_DIRECTION_MASK 2878 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2879 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2880 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2881 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2882 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2883 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2884 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2885 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2886 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2887 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2888 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2889 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2890 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2891 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2892 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2893 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2894 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2895 * 1 PFLAG2_VIEW_QUICK_REJECTED 2896 * 1 PFLAG2_PADDING_RESOLVED 2897 * 1 PFLAG2_DRAWABLE_RESOLVED 2898 * 1 PFLAG2_HAS_TRANSIENT_STATE 2899 * |-------|-------|-------|-------| 2900 */ 2901 2902 /** 2903 * Indicates that this view has reported that it can accept the current drag's content. 2904 * Cleared when the drag operation concludes. 2905 * @hide 2906 */ 2907 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2908 2909 /** 2910 * Indicates that this view is currently directly under the drag location in a 2911 * drag-and-drop operation involving content that it can accept. Cleared when 2912 * the drag exits the view, or when the drag operation concludes. 2913 * @hide 2914 */ 2915 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2916 2917 /** @hide */ 2918 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2919 LAYOUT_DIRECTION_LTR, 2920 LAYOUT_DIRECTION_RTL, 2921 LAYOUT_DIRECTION_INHERIT, 2922 LAYOUT_DIRECTION_LOCALE 2923 }) 2924 @Retention(RetentionPolicy.SOURCE) 2925 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2926 public @interface LayoutDir {} 2927 2928 /** @hide */ 2929 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2930 LAYOUT_DIRECTION_LTR, 2931 LAYOUT_DIRECTION_RTL 2932 }) 2933 @Retention(RetentionPolicy.SOURCE) 2934 public @interface ResolvedLayoutDir {} 2935 2936 /** 2937 * A flag to indicate that the layout direction of this view has not been defined yet. 2938 * @hide 2939 */ 2940 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2941 2942 /** 2943 * Horizontal layout direction of this view is from Left to Right. 2944 * Use with {@link #setLayoutDirection}. 2945 */ 2946 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2947 2948 /** 2949 * Horizontal layout direction of this view is from Right to Left. 2950 * Use with {@link #setLayoutDirection}. 2951 */ 2952 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2953 2954 /** 2955 * Horizontal layout direction of this view is inherited from its parent. 2956 * Use with {@link #setLayoutDirection}. 2957 */ 2958 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2959 2960 /** 2961 * Horizontal layout direction of this view is from deduced from the default language 2962 * script for the locale. Use with {@link #setLayoutDirection}. 2963 */ 2964 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2965 2966 /** 2967 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2968 * @hide 2969 */ 2970 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2971 2972 /** 2973 * Mask for use with private flags indicating bits used for horizontal layout direction. 2974 * @hide 2975 */ 2976 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2977 2978 /** 2979 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2980 * right-to-left direction. 2981 * @hide 2982 */ 2983 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2984 2985 /** 2986 * Indicates whether the view horizontal layout direction has been resolved. 2987 * @hide 2988 */ 2989 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2990 2991 /** 2992 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2993 * @hide 2994 */ 2995 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2996 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2997 2998 /* 2999 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 3000 * flag value. 3001 * @hide 3002 */ 3003 private static final int[] LAYOUT_DIRECTION_FLAGS = { 3004 LAYOUT_DIRECTION_LTR, 3005 LAYOUT_DIRECTION_RTL, 3006 LAYOUT_DIRECTION_INHERIT, 3007 LAYOUT_DIRECTION_LOCALE 3008 }; 3009 3010 /** 3011 * Default horizontal layout direction. 3012 */ 3013 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 3014 3015 /** 3016 * Default horizontal layout direction. 3017 * @hide 3018 */ 3019 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 3020 3021 /** 3022 * Text direction is inherited through {@link ViewGroup} 3023 */ 3024 public static final int TEXT_DIRECTION_INHERIT = 0; 3025 3026 /** 3027 * Text direction is using "first strong algorithm". The first strong directional character 3028 * determines the paragraph direction. If there is no strong directional character, the 3029 * paragraph direction is the view's resolved layout direction. 3030 */ 3031 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 3032 3033 /** 3034 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 3035 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 3036 * If there are neither, the paragraph direction is the view's resolved layout direction. 3037 */ 3038 public static final int TEXT_DIRECTION_ANY_RTL = 2; 3039 3040 /** 3041 * Text direction is forced to LTR. 3042 */ 3043 public static final int TEXT_DIRECTION_LTR = 3; 3044 3045 /** 3046 * Text direction is forced to RTL. 3047 */ 3048 public static final int TEXT_DIRECTION_RTL = 4; 3049 3050 /** 3051 * Text direction is coming from the system Locale. 3052 */ 3053 public static final int TEXT_DIRECTION_LOCALE = 5; 3054 3055 /** 3056 * Text direction is using "first strong algorithm". The first strong directional character 3057 * determines the paragraph direction. If there is no strong directional character, the 3058 * paragraph direction is LTR. 3059 */ 3060 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 3061 3062 /** 3063 * Text direction is using "first strong algorithm". The first strong directional character 3064 * determines the paragraph direction. If there is no strong directional character, the 3065 * paragraph direction is RTL. 3066 */ 3067 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 3068 3069 /** 3070 * Default text direction is inherited 3071 */ 3072 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 3073 3074 /** 3075 * Default resolved text direction 3076 * @hide 3077 */ 3078 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 3079 3080 /** 3081 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 3082 * @hide 3083 */ 3084 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 3085 3086 /** 3087 * Mask for use with private flags indicating bits used for text direction. 3088 * @hide 3089 */ 3090 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 3091 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 3092 3093 /** 3094 * Array of text direction flags for mapping attribute "textDirection" to correct 3095 * flag value. 3096 * @hide 3097 */ 3098 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 3099 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3100 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3101 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3102 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3103 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3104 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3105 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3106 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 3107 }; 3108 3109 /** 3110 * Indicates whether the view text direction has been resolved. 3111 * @hide 3112 */ 3113 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 3114 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 3115 3116 /** 3117 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 3118 * @hide 3119 */ 3120 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 3121 3122 /** 3123 * Mask for use with private flags indicating bits used for resolved text direction. 3124 * @hide 3125 */ 3126 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 3127 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 3128 3129 /** 3130 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 3131 * @hide 3132 */ 3133 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 3134 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 3135 3136 /** @hide */ 3137 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 3138 TEXT_ALIGNMENT_INHERIT, 3139 TEXT_ALIGNMENT_GRAVITY, 3140 TEXT_ALIGNMENT_CENTER, 3141 TEXT_ALIGNMENT_TEXT_START, 3142 TEXT_ALIGNMENT_TEXT_END, 3143 TEXT_ALIGNMENT_VIEW_START, 3144 TEXT_ALIGNMENT_VIEW_END 3145 }) 3146 @Retention(RetentionPolicy.SOURCE) 3147 public @interface TextAlignment {} 3148 3149 /** 3150 * Default text alignment. The text alignment of this View is inherited from its parent. 3151 * Use with {@link #setTextAlignment(int)} 3152 */ 3153 public static final int TEXT_ALIGNMENT_INHERIT = 0; 3154 3155 /** 3156 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 3157 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 3158 * 3159 * Use with {@link #setTextAlignment(int)} 3160 */ 3161 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 3162 3163 /** 3164 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 3165 * 3166 * Use with {@link #setTextAlignment(int)} 3167 */ 3168 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 3169 3170 /** 3171 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 3172 * 3173 * Use with {@link #setTextAlignment(int)} 3174 */ 3175 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 3176 3177 /** 3178 * Center the paragraph, e.g. ALIGN_CENTER. 3179 * 3180 * Use with {@link #setTextAlignment(int)} 3181 */ 3182 public static final int TEXT_ALIGNMENT_CENTER = 4; 3183 3184 /** 3185 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 3186 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 3187 * 3188 * Use with {@link #setTextAlignment(int)} 3189 */ 3190 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 3191 3192 /** 3193 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 3194 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 3195 * 3196 * Use with {@link #setTextAlignment(int)} 3197 */ 3198 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 3199 3200 /** 3201 * Default text alignment is inherited 3202 */ 3203 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3204 3205 /** 3206 * Default resolved text alignment 3207 * @hide 3208 */ 3209 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3210 3211 /** 3212 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 3213 * @hide 3214 */ 3215 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 3216 3217 /** 3218 * Mask for use with private flags indicating bits used for text alignment. 3219 * @hide 3220 */ 3221 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3222 3223 /** 3224 * Array of text direction flags for mapping attribute "textAlignment" to correct 3225 * flag value. 3226 * @hide 3227 */ 3228 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 3229 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3230 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3231 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3232 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3233 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3234 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3235 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 3236 }; 3237 3238 /** 3239 * Indicates whether the view text alignment has been resolved. 3240 * @hide 3241 */ 3242 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3243 3244 /** 3245 * Bit shift to get the resolved text alignment. 3246 * @hide 3247 */ 3248 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 3249 3250 /** 3251 * Mask for use with private flags indicating bits used for text alignment. 3252 * @hide 3253 */ 3254 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 3255 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3256 3257 /** 3258 * Indicates whether if the view text alignment has been resolved to gravity 3259 */ 3260 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3261 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3262 3263 // Accessiblity constants for mPrivateFlags2 3264 3265 /** 3266 * Shift for the bits in {@link #mPrivateFlags2} related to the 3267 * "importantForAccessibility" attribute. 3268 */ 3269 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3270 3271 /** 3272 * Automatically determine whether a view is important for accessibility. 3273 */ 3274 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3275 3276 /** 3277 * The view is important for accessibility. 3278 */ 3279 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3280 3281 /** 3282 * The view is not important for accessibility. 3283 */ 3284 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3285 3286 /** 3287 * The view is not important for accessibility, nor are any of its 3288 * descendant views. 3289 */ 3290 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3291 3292 /** 3293 * The default whether the view is important for accessibility. 3294 */ 3295 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3296 3297 /** 3298 * Automatically determine whether the view should only allow interactions from 3299 * {@link android.accessibilityservice.AccessibilityService}s with the 3300 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 3301 * set to true. 3302 * 3303 * <p> 3304 * Accessibility interactions from services without {@code isAccessibilityTool} set to true are 3305 * disallowed for any of the following conditions: 3306 * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li> 3307 * <li>any parent of this view returns true from {@link #isAccessibilityDataSensitive()}.</li> 3308 * </p> 3309 */ 3310 public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000; 3311 3312 /** 3313 * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s 3314 * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} 3315 * property set to true. 3316 */ 3317 public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001; 3318 3319 /** 3320 * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s, 3321 * regardless of their 3322 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property. 3323 */ 3324 public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002; 3325 3326 /** @hide */ 3327 @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = { 3328 ACCESSIBILITY_DATA_SENSITIVE_AUTO, 3329 ACCESSIBILITY_DATA_SENSITIVE_YES, 3330 ACCESSIBILITY_DATA_SENSITIVE_NO, 3331 }) 3332 @Retention(RetentionPolicy.SOURCE) 3333 public @interface AccessibilityDataSensitive {} 3334 3335 /** 3336 * Mask for obtaining the bits which specify how to determine 3337 * whether a view is important for accessibility. 3338 */ 3339 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3340 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3341 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3342 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3343 3344 /** 3345 * Shift for the bits in {@link #mPrivateFlags2} related to the 3346 * "accessibilityLiveRegion" attribute. 3347 */ 3348 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3349 3350 /** 3351 * Live region mode specifying that accessibility services should not 3352 * automatically announce changes to this view. This is the default live 3353 * region mode for most views. 3354 * <p> 3355 * Use with {@link #setAccessibilityLiveRegion(int)}. 3356 */ 3357 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3358 3359 /** 3360 * Live region mode specifying that accessibility services should notify users of changes to 3361 * this view. 3362 * <p> 3363 * Use with {@link #setAccessibilityLiveRegion(int)}. 3364 */ 3365 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3366 3367 /** 3368 * Live region mode specifying that accessibility services should immediately notify users of 3369 * changes to this view. For example, a screen reader may interrupt ongoing speech to 3370 * immediately announce these changes. 3371 * <p> 3372 * Use with {@link #setAccessibilityLiveRegion(int)}. 3373 */ 3374 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3375 3376 /** 3377 * The default whether the view is important for accessibility. 3378 */ 3379 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3380 3381 /** 3382 * Mask for obtaining the bits which specify a view's accessibility live 3383 * region mode. 3384 */ 3385 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3386 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3387 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3388 3389 /** 3390 * Flag indicating whether a view has accessibility focus. 3391 */ 3392 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3393 3394 /** 3395 * Flag whether the accessibility state of the subtree rooted at this view changed. 3396 */ 3397 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3398 3399 /** 3400 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3401 * is used to check whether later changes to the view's transform should invalidate the 3402 * view to force the quickReject test to run again. 3403 */ 3404 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3405 3406 /** 3407 * Flag indicating that start/end padding has been resolved into left/right padding 3408 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3409 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3410 * during measurement. In some special cases this is required such as when an adapter-based 3411 * view measures prospective children without attaching them to a window. 3412 */ 3413 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3414 3415 /** 3416 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3417 */ 3418 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3419 3420 /** 3421 * Indicates that the view is tracking some sort of transient state 3422 * that the app should not need to be aware of, but that the framework 3423 * should take special care to preserve. 3424 */ 3425 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3426 3427 /** 3428 * Group of bits indicating that RTL properties resolution is done. 3429 */ 3430 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3431 PFLAG2_TEXT_DIRECTION_RESOLVED | 3432 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3433 PFLAG2_PADDING_RESOLVED | 3434 PFLAG2_DRAWABLE_RESOLVED; 3435 3436 // There are a couple of flags left in mPrivateFlags2 3437 3438 /* End of masks for mPrivateFlags2 */ 3439 3440 /* 3441 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3442 * 3443 * |-------|-------|-------|-------| 3444 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3445 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3446 * 1 PFLAG3_IS_LAID_OUT 3447 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3448 * 1 PFLAG3_CALLED_SUPER 3449 * 1 PFLAG3_APPLYING_INSETS 3450 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3451 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3452 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3453 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3454 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3455 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3456 * 1 PFLAG3_SCROLL_INDICATOR_START 3457 * 1 PFLAG3_SCROLL_INDICATOR_END 3458 * 1 PFLAG3_ASSIST_BLOCKED 3459 * 1 PFLAG3_CLUSTER 3460 * 1 PFLAG3_IS_AUTOFILLED 3461 * 1 PFLAG3_FINGER_DOWN 3462 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3463 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3464 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3465 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3466 * 1 PFLAG3_TEMPORARY_DETACH 3467 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3468 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3469 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3470 * 1 PFLAG3_AGGREGATED_VISIBLE 3471 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3472 * 1 PFLAG3_ACCESSIBILITY_HEADING 3473 * |-------|-------|-------|-------| 3474 */ 3475 3476 /** 3477 * Flag indicating that view has a transform animation set on it. This is used to track whether 3478 * an animation is cleared between successive frames, in order to tell the associated 3479 * DisplayList to clear its animation matrix. 3480 */ 3481 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3482 3483 /** 3484 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3485 * animation is cleared between successive frames, in order to tell the associated 3486 * DisplayList to restore its alpha value. 3487 */ 3488 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3489 3490 /** 3491 * Flag indicating that the view has been through at least one layout since it 3492 * was last attached to a window. 3493 */ 3494 static final int PFLAG3_IS_LAID_OUT = 0x4; 3495 3496 /** 3497 * Flag indicating that a call to measure() was skipped and should be done 3498 * instead when layout() is invoked. 3499 */ 3500 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3501 3502 /** 3503 * Flag indicating that an overridden method correctly called down to 3504 * the superclass implementation as required by the API spec. 3505 */ 3506 static final int PFLAG3_CALLED_SUPER = 0x10; 3507 3508 /** 3509 * Flag indicating that we're in the process of applying window insets. 3510 */ 3511 static final int PFLAG3_APPLYING_INSETS = 0x20; 3512 3513 /** 3514 * Flag indicating that we're in the process of fitting system windows using the old method. 3515 */ 3516 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3517 3518 /** 3519 * Flag indicating that nested scrolling is enabled for this view. 3520 * The view will optionally cooperate with views up its parent chain to allow for 3521 * integrated nested scrolling along the same axis. 3522 */ 3523 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3524 3525 /** 3526 * Flag indicating that the bottom scroll indicator should be displayed 3527 * when this view can scroll up. 3528 */ 3529 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3530 3531 /** 3532 * Flag indicating that the bottom scroll indicator should be displayed 3533 * when this view can scroll down. 3534 */ 3535 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3536 3537 /** 3538 * Flag indicating that the left scroll indicator should be displayed 3539 * when this view can scroll left. 3540 */ 3541 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3542 3543 /** 3544 * Flag indicating that the right scroll indicator should be displayed 3545 * when this view can scroll right. 3546 */ 3547 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3548 3549 /** 3550 * Flag indicating that the start scroll indicator should be displayed 3551 * when this view can scroll in the start direction. 3552 */ 3553 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3554 3555 /** 3556 * Flag indicating that the end scroll indicator should be displayed 3557 * when this view can scroll in the end direction. 3558 */ 3559 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3560 3561 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3562 3563 static final int SCROLL_INDICATORS_NONE = 0x0000; 3564 3565 /** 3566 * Mask for use with setFlags indicating bits used for indicating which 3567 * scroll indicators are enabled. 3568 */ 3569 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3570 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3571 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3572 | PFLAG3_SCROLL_INDICATOR_END; 3573 3574 /** 3575 * Left-shift required to translate between public scroll indicator flags 3576 * and internal PFLAGS3 flags. When used as a right-shift, translates 3577 * PFLAGS3 flags to public flags. 3578 */ 3579 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3580 3581 /** @hide */ 3582 @Retention(RetentionPolicy.SOURCE) 3583 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3584 SCROLL_INDICATOR_TOP, 3585 SCROLL_INDICATOR_BOTTOM, 3586 SCROLL_INDICATOR_LEFT, 3587 SCROLL_INDICATOR_RIGHT, 3588 SCROLL_INDICATOR_START, 3589 SCROLL_INDICATOR_END, 3590 }) 3591 public @interface ScrollIndicators {} 3592 3593 /** 3594 * Scroll indicator direction for the top edge of the view. 3595 * 3596 * @see #setScrollIndicators(int) 3597 * @see #setScrollIndicators(int, int) 3598 * @see #getScrollIndicators() 3599 */ 3600 public static final int SCROLL_INDICATOR_TOP = 3601 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3602 3603 /** 3604 * Scroll indicator direction for the bottom edge of the view. 3605 * 3606 * @see #setScrollIndicators(int) 3607 * @see #setScrollIndicators(int, int) 3608 * @see #getScrollIndicators() 3609 */ 3610 public static final int SCROLL_INDICATOR_BOTTOM = 3611 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3612 3613 /** 3614 * Scroll indicator direction for the left edge of the view. 3615 * 3616 * @see #setScrollIndicators(int) 3617 * @see #setScrollIndicators(int, int) 3618 * @see #getScrollIndicators() 3619 */ 3620 public static final int SCROLL_INDICATOR_LEFT = 3621 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3622 3623 /** 3624 * Scroll indicator direction for the right edge of the view. 3625 * 3626 * @see #setScrollIndicators(int) 3627 * @see #setScrollIndicators(int, int) 3628 * @see #getScrollIndicators() 3629 */ 3630 public static final int SCROLL_INDICATOR_RIGHT = 3631 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3632 3633 /** 3634 * Scroll indicator direction for the starting edge of the view. 3635 * <p> 3636 * Resolved according to the view's layout direction, see 3637 * {@link #getLayoutDirection()} for more information. 3638 * 3639 * @see #setScrollIndicators(int) 3640 * @see #setScrollIndicators(int, int) 3641 * @see #getScrollIndicators() 3642 */ 3643 public static final int SCROLL_INDICATOR_START = 3644 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3645 3646 /** 3647 * Scroll indicator direction for the ending edge of the view. 3648 * <p> 3649 * Resolved according to the view's layout direction, see 3650 * {@link #getLayoutDirection()} for more information. 3651 * 3652 * @see #setScrollIndicators(int) 3653 * @see #setScrollIndicators(int, int) 3654 * @see #getScrollIndicators() 3655 */ 3656 public static final int SCROLL_INDICATOR_END = 3657 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3658 3659 /** 3660 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3661 * into this view.<p> 3662 */ 3663 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3664 3665 /** 3666 * Flag indicating that the view is a root of a keyboard navigation cluster. 3667 * 3668 * @see #isKeyboardNavigationCluster() 3669 * @see #setKeyboardNavigationCluster(boolean) 3670 */ 3671 private static final int PFLAG3_CLUSTER = 0x8000; 3672 3673 /** 3674 * Flag indicating that the view is autofilled 3675 * 3676 * @see #isAutofilled() 3677 * @see #setAutofilled(boolean, boolean) 3678 */ 3679 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3680 3681 /** 3682 * Indicates that the user is currently touching the screen. 3683 * Currently used for the tooltip positioning only. 3684 */ 3685 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3686 3687 /** 3688 * Flag indicating that this view is the default-focus view. 3689 * 3690 * @see #isFocusedByDefault() 3691 * @see #setFocusedByDefault(boolean) 3692 */ 3693 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3694 3695 /** 3696 * Shift for the bits in {@link #mPrivateFlags3} related to the 3697 * "importantForAutofill" attribute. 3698 */ 3699 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3700 3701 /** 3702 * Mask for obtaining the bits which specify how to determine 3703 * whether a view is important for autofill. 3704 */ 3705 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3706 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3707 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3708 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3709 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3710 3711 /** 3712 * Whether this view has rendered elements that overlap (see {@link 3713 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3714 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3715 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3716 * determined by whatever {@link #hasOverlappingRendering()} returns. 3717 */ 3718 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3719 3720 /** 3721 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3722 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3723 */ 3724 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3725 3726 /** 3727 * Flag indicating that the view is temporarily detached from the parent view. 3728 * 3729 * @see #onStartTemporaryDetach() 3730 * @see #onFinishTemporaryDetach() 3731 */ 3732 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3733 3734 /** 3735 * Flag indicating that the view does not wish to be revealed within its parent 3736 * hierarchy when it gains focus. Expressed in the negative since the historical 3737 * default behavior is to reveal on focus; this flag suppresses that behavior. 3738 * 3739 * @see #setRevealOnFocusHint(boolean) 3740 * @see #getRevealOnFocusHint() 3741 */ 3742 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3743 3744 /** 3745 * Flag indicating that when layout is completed we should notify 3746 * that the view was entered for autofill purposes. To minimize 3747 * showing autofill for views not visible to the user we evaluate 3748 * user visibility which cannot be done until the view is laid out. 3749 */ 3750 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3751 3752 /** 3753 * Works like focusable for screen readers, but without the side effects on input focus. 3754 * @see #setScreenReaderFocusable(boolean) 3755 */ 3756 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3757 3758 /** 3759 * The last aggregated visibility. Used to detect when it truly changes. 3760 */ 3761 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3762 3763 /** 3764 * Used to indicate that {@link #mAutofillId} was explicitly set through 3765 * {@link #setAutofillId(AutofillId)}. 3766 */ 3767 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3768 3769 /** 3770 * Indicates if the View is a heading for accessibility purposes 3771 */ 3772 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3773 3774 /* End of masks for mPrivateFlags3 */ 3775 3776 /* 3777 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3778 * 3779 * |-------|-------|-------|-------| 3780 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3781 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3782 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3783 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3784 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3785 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3786 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3787 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3788 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3789 * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED 3790 * 1 PFLAG4_DETACHED 3791 * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE 3792 * 1 PFLAG4_DRAG_A11Y_STARTED 3793 * 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED 3794 * 1 PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER 3795 * 1 PFLAG4_TRAVERSAL_TRACING_ENABLED 3796 * 1 PFLAG4_RELAYOUT_TRACING_ENABLED 3797 * 1 PFLAG4_ROTARY_HAPTICS_DETERMINED 3798 * 1 PFLAG4_ROTARY_HAPTICS_ENABLED 3799 * 1 PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT 3800 * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT 3801 * 11 PFLAG4_CONTENT_SENSITIVITY_MASK 3802 * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE 3803 * 1 PFLAG4_HAS_DRAWN 3804 * 1 PFLAG4_HAS_MOVED 3805 * 1 PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION 3806 * |-------|-------|-------|-------| 3807 */ 3808 3809 /** 3810 * Mask for obtaining the bits which specify how to determine 3811 * whether a view is important for autofill. 3812 * 3813 * <p>NOTE: the important for content capture values were the first flags added and are set in 3814 * the rightmost position, so we don't need to shift them 3815 */ 3816 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3817 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3818 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3819 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3820 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3821 3822 /* 3823 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3824 * should be called. 3825 * 3826 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3827 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3828 */ 3829 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3830 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3831 3832 /* 3833 * Flags used to cache the value returned by isImportantForContentCapture while the view 3834 * hierarchy is being traversed. 3835 */ 3836 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3837 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3838 3839 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3840 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3841 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3842 3843 /** 3844 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3845 */ 3846 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3847 3848 /** 3849 * Flag indicating the field should not have yellow highlight when autofilled. 3850 */ 3851 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3852 3853 /** 3854 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3855 */ 3856 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3857 3858 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3859 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3860 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3861 3862 /** 3863 * Indicates if the view can receive click events when disabled. 3864 */ 3865 private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; 3866 3867 /** 3868 * Indicates if the view is just detached. 3869 */ 3870 private static final int PFLAG4_DETACHED = 0x000002000; 3871 3872 /** 3873 * Indicates that the view has transient state because the system is translating it. 3874 */ 3875 private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; 3876 3877 /** 3878 * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START} 3879 */ 3880 private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; 3881 3882 /** 3883 * Indicates that the view enables auto handwriting initiation. 3884 */ 3885 private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; 3886 3887 /** 3888 * Indicates that the view is important for Credential Manager. 3889 */ 3890 private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000; 3891 3892 /** 3893 * When set, measure and layout passes of this view will be logged with {@link Trace}, so we 3894 * can better debug jank due to complex view hierarchies. 3895 */ 3896 private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000; 3897 3898 /** 3899 * When set, emits a {@link Trace} instant event and stacktrace every time a requestLayout of 3900 * this class happens. 3901 */ 3902 private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000; 3903 3904 /** Indicates if rotary scroll haptics support for the view has been determined. */ 3905 private static final int PFLAG4_ROTARY_HAPTICS_DETERMINED = 0x100000; 3906 3907 /** 3908 * Indicates if rotary scroll haptics is enabled for this view. 3909 * The source of truth for this info is a ViewConfiguration API; this bit only caches the value. 3910 */ 3911 private static final int PFLAG4_ROTARY_HAPTICS_ENABLED = 0x200000; 3912 3913 /** Indicates if there has been a scroll event since the last rotary input. */ 3914 private static final int PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT = 0x400000; 3915 3916 /** 3917 * Indicates if there has been a rotary input that may generate a scroll event. 3918 * This flag is important so that a scroll event can be properly attributed to a rotary input. 3919 */ 3920 private static final int PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT = 0x800000; 3921 3922 private static final int PFLAG4_CONTENT_SENSITIVITY_SHIFT = 24; 3923 3924 /** 3925 * Mask for obtaining the bits which specify how to determine whether a view 3926 * displays sensitive content or not. 3927 */ 3928 private static final int PFLAG4_CONTENT_SENSITIVITY_MASK = 3929 (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE 3930 | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT; 3931 3932 /** 3933 * Whether this view has been counted as a sensitive view or not. 3934 * 3935 * @see AttachInfo#mSensitiveViewsCount 3936 */ 3937 private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; 3938 3939 /** 3940 * Whether this view has been drawn once with updateDisplayListIfDirty() or not. 3941 * Used by VRR to for quick detection of scrolling. 3942 */ 3943 private static final int PFLAG4_HAS_DRAWN = 0x8000000; 3944 3945 /** 3946 * Whether this view has been moved with either setTranslationX/Y or setLeft/Top. 3947 * Used by VRR to for quick detection of scrolling. 3948 */ 3949 private static final int PFLAG4_HAS_MOVED = 0x10000000; 3950 3951 /** 3952 * Whether the invalidateViewProperty is involked at current frame. 3953 */ 3954 private static final int PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION = 0x20000000; 3955 3956 /* End of masks for mPrivateFlags4 */ 3957 3958 /** @hide */ 3959 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3960 /** @hide */ 3961 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3962 /** @hide */ 3963 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3964 3965 /** @hide */ 3966 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3967 VIEW_STRUCTURE_FOR_ASSIST, 3968 VIEW_STRUCTURE_FOR_AUTOFILL, 3969 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3970 }) 3971 @Retention(RetentionPolicy.SOURCE) 3972 public @interface ViewStructureType {} 3973 3974 /** 3975 * Always allow a user to over-scroll this view, provided it is a 3976 * view that can scroll. 3977 * 3978 * @see #getOverScrollMode() 3979 * @see #setOverScrollMode(int) 3980 */ 3981 public static final int OVER_SCROLL_ALWAYS = 0; 3982 3983 /** 3984 * Allow a user to over-scroll this view only if the content is large 3985 * enough to meaningfully scroll, provided it is a view that can scroll. 3986 * 3987 * @see #getOverScrollMode() 3988 * @see #setOverScrollMode(int) 3989 */ 3990 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3991 3992 /** 3993 * Never allow a user to over-scroll this view. 3994 * 3995 * @see #getOverScrollMode() 3996 * @see #setOverScrollMode(int) 3997 */ 3998 public static final int OVER_SCROLL_NEVER = 2; 3999 4000 /** 4001 * Special constant for {@link #setSystemUiVisibility(int)}: View has 4002 * requested the system UI (status bar) to be visible (the default). 4003 * 4004 * @see #setSystemUiVisibility(int) 4005 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 4006 * instead. 4007 */ 4008 @Deprecated 4009 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 4010 4011 /** 4012 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 4013 * system UI to enter an unobtrusive "low profile" mode. 4014 * 4015 * <p>This is for use in games, book readers, video players, or any other 4016 * "immersive" application where the usual system chrome is deemed too distracting. 4017 * 4018 * <p>In low profile mode, the status bar and/or navigation icons may dim. 4019 * 4020 * @see #setSystemUiVisibility(int) 4021 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 4022 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 4023 * {@link Type#systemBars()}. 4024 */ 4025 @Deprecated 4026 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 4027 4028 /** 4029 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 4030 * system navigation be temporarily hidden. 4031 * 4032 * <p>This is an even less obtrusive state than that called for by 4033 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 4034 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 4035 * those to disappear. This is useful (in conjunction with the 4036 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 4037 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 4038 * window flags) for displaying content using every last pixel on the display. 4039 * 4040 * <p>There is a limitation: because navigation controls are so important, the least user 4041 * interaction will cause them to reappear immediately. When this happens, both 4042 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 4043 * so that both elements reappear at the same time. 4044 * 4045 * @see #setSystemUiVisibility(int) 4046 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 4047 * instead. 4048 */ 4049 @Deprecated 4050 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 4051 4052 /** 4053 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 4054 * into the normal fullscreen mode so that its content can take over the screen 4055 * while still allowing the user to interact with the application. 4056 * 4057 * <p>This has the same visual effect as 4058 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 4059 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 4060 * meaning that non-critical screen decorations (such as the status bar) will be 4061 * hidden while the user is in the View's window, focusing the experience on 4062 * that content. Unlike the window flag, if you are using ActionBar in 4063 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 4064 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 4065 * hide the action bar. 4066 * 4067 * <p>This approach to going fullscreen is best used over the window flag when 4068 * it is a transient state -- that is, the application does this at certain 4069 * points in its user interaction where it wants to allow the user to focus 4070 * on content, but not as a continuous state. For situations where the application 4071 * would like to simply stay full screen the entire time (such as a game that 4072 * wants to take over the screen), the 4073 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 4074 * is usually a better approach. The state set here will be removed by the system 4075 * in various situations (such as the user moving to another application) like 4076 * the other system UI states. 4077 * 4078 * <p>When using this flag, the application should provide some easy facility 4079 * for the user to go out of it. A common example would be in an e-book 4080 * reader, where tapping on the screen brings back whatever screen and UI 4081 * decorations that had been hidden while the user was immersed in reading 4082 * the book. 4083 * 4084 * @see #setSystemUiVisibility(int) 4085 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 4086 * instead. 4087 */ 4088 @Deprecated 4089 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 4090 4091 /** 4092 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 4093 * flags, we would like a stable view of the content insets given to 4094 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 4095 * will always represent the worst case that the application can expect 4096 * as a continuous state. In the stock Android UI this is the space for 4097 * the system bar, nav bar, and status bar, but not more transient elements 4098 * such as an input method. 4099 * 4100 * The stable layout your UI sees is based on the system UI modes you can 4101 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 4102 * then you will get a stable layout for changes of the 4103 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 4104 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 4105 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 4106 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 4107 * with a stable layout. (Note that you should avoid using 4108 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 4109 * 4110 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 4111 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 4112 * then a hidden status bar will be considered a "stable" state for purposes 4113 * here. This allows your UI to continually hide the status bar, while still 4114 * using the system UI flags to hide the action bar while still retaining 4115 * a stable layout. Note that changing the window fullscreen flag will never 4116 * provide a stable layout for a clean transition. 4117 * 4118 * <p>If you are using ActionBar in 4119 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 4120 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 4121 * insets it adds to those given to the application. 4122 * 4123 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 4124 * insets that don't change when system bars change visibility state. 4125 */ 4126 @Deprecated 4127 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 4128 4129 /** 4130 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 4131 * to be laid out as if it has requested 4132 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 4133 * allows it to avoid artifacts when switching in and out of that mode, at 4134 * the expense that some of its user interface may be covered by screen 4135 * decorations when they are shown. You can perform layout of your inner 4136 * UI elements to account for the navigation system UI through the 4137 * {@link #fitSystemWindows(Rect)} method. 4138 * 4139 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 4140 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 4141 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 4142 */ 4143 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 4144 4145 /** 4146 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 4147 * to be laid out as if it has requested 4148 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 4149 * allows it to avoid artifacts when switching in and out of that mode, at 4150 * the expense that some of its user interface may be covered by screen 4151 * decorations when they are shown. You can perform layout of your inner 4152 * UI elements to account for non-fullscreen system UI through the 4153 * {@link #fitSystemWindows(Rect)} method. 4154 * 4155 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 4156 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 4157 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 4158 * layoutInDisplayCutoutMode} is 4159 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 4160 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 4161 * 4162 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 4163 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 4164 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 4165 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 4166 * 4167 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 4168 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 4169 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 4170 */ 4171 @Deprecated 4172 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 4173 4174 /** 4175 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 4176 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 4177 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 4178 * user interaction. 4179 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 4180 * has an effect when used in combination with that flag.</p> 4181 * 4182 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead. 4183 */ 4184 @Deprecated 4185 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 4186 4187 /** 4188 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 4189 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 4190 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 4191 * experience while also hiding the system bars. If this flag is not set, 4192 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 4193 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 4194 * if the user swipes from the top of the screen. 4195 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 4196 * system gestures, such as swiping from the top of the screen. These transient system bars 4197 * will overlay app's content, may have some degree of transparency, and will automatically 4198 * hide after a short timeout. 4199 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 4200 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 4201 * with one or both of those flags.</p> 4202 * 4203 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 4204 */ 4205 @Deprecated 4206 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 4207 4208 /** 4209 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 4210 * is compatible with light status bar backgrounds. 4211 * 4212 * <p>For this to take effect, the window must request 4213 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 4214 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 4215 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 4216 * FLAG_TRANSLUCENT_STATUS}. 4217 * 4218 * @see android.R.attr#windowLightStatusBar 4219 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 4220 */ 4221 @Deprecated 4222 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 4223 4224 /** 4225 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 4226 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 4227 */ 4228 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 4229 4230 /** 4231 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 4232 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 4233 */ 4234 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 4235 4236 /** 4237 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 4238 * that is compatible with light navigation bar backgrounds. 4239 * 4240 * <p>For this to take effect, the window must request 4241 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 4242 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 4243 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 4244 * FLAG_TRANSLUCENT_NAVIGATION}. 4245 * 4246 * @see android.R.attr#windowLightNavigationBar 4247 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 4248 */ 4249 @Deprecated 4250 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 4251 4252 /** 4253 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 4254 */ 4255 @Deprecated 4256 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 4257 4258 /** 4259 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 4260 */ 4261 @Deprecated 4262 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 4263 4264 /** 4265 * @hide 4266 * 4267 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4268 * out of the public fields to keep the undefined bits out of the developer's way. 4269 * 4270 * Flag to make the status bar not expandable. Unless you also 4271 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 4272 */ 4273 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4274 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 4275 4276 /** 4277 * @hide 4278 * 4279 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4280 * out of the public fields to keep the undefined bits out of the developer's way. 4281 * 4282 * Flag to hide notification icons and scrolling ticker text. 4283 */ 4284 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 4285 4286 /** 4287 * @hide 4288 * 4289 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4290 * out of the public fields to keep the undefined bits out of the developer's way. 4291 * 4292 * Flag to disable incoming notification alerts. This will not block 4293 * icons, but it will block sound, vibrating and other visual or aural notifications. 4294 */ 4295 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 4296 4297 /** 4298 * @hide 4299 * 4300 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4301 * out of the public fields to keep the undefined bits out of the developer's way. 4302 * 4303 * Flag to hide only the scrolling ticker. Note that 4304 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 4305 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 4306 */ 4307 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 4308 4309 /** 4310 * @hide 4311 * 4312 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4313 * out of the public fields to keep the undefined bits out of the developer's way. 4314 * 4315 * Flag to hide the center system info area. 4316 */ 4317 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 4318 4319 /** 4320 * @hide 4321 * 4322 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4323 * out of the public fields to keep the undefined bits out of the developer's way. 4324 * 4325 * Flag to hide only the home button. Don't use this 4326 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4327 */ 4328 @UnsupportedAppUsage 4329 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 4330 4331 /** 4332 * @hide 4333 * 4334 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4335 * out of the public fields to keep the undefined bits out of the developer's way. 4336 * 4337 * Flag to hide only the back button. Don't use this 4338 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4339 */ 4340 @UnsupportedAppUsage 4341 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 4342 4343 /** 4344 * @hide 4345 * 4346 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4347 * out of the public fields to keep the undefined bits out of the developer's way. 4348 * 4349 * Flag to hide only the clock. You might use this if your activity has 4350 * its own clock making the status bar's clock redundant. 4351 */ 4352 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 4353 4354 /** 4355 * @hide 4356 * 4357 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4358 * out of the public fields to keep the undefined bits out of the developer's way. 4359 * 4360 * Flag to hide only the recent apps button. Don't use this 4361 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4362 */ 4363 @UnsupportedAppUsage 4364 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 4365 4366 /** 4367 * @hide 4368 * 4369 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4370 * out of the public fields to keep the undefined bits out of the developer's way. 4371 * 4372 * Flag to disable the global search gesture. Don't use this 4373 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4374 */ 4375 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 4376 4377 /** 4378 * @hide 4379 * 4380 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4381 * out of the public fields to keep the undefined bits out of the developer's way. 4382 * 4383 * Flag to disable the ongoing call chip. 4384 */ 4385 public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; 4386 4387 /** 4388 * @hide 4389 */ 4390 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4391 4392 /** 4393 * These are the system UI flags that can be cleared by events outside 4394 * of an application. Currently this is just the ability to tap on the 4395 * screen while hiding the navigation bar to have it return. 4396 * @hide 4397 */ 4398 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4399 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4400 | SYSTEM_UI_FLAG_FULLSCREEN; 4401 4402 /** 4403 * Flags that can impact the layout in relation to system UI. 4404 * 4405 * @deprecated System UI layout flags are deprecated. 4406 */ 4407 @Deprecated 4408 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4409 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4410 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4411 4412 /** @hide */ 4413 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4414 FIND_VIEWS_WITH_TEXT, 4415 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4416 }) 4417 @Retention(RetentionPolicy.SOURCE) 4418 public @interface FindViewFlags {} 4419 4420 /** 4421 * Find views that render the specified text. 4422 * 4423 * @see #findViewsWithText(ArrayList, CharSequence, int) 4424 */ 4425 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4426 4427 /** 4428 * Find find views that contain the specified content description. 4429 * 4430 * @see #findViewsWithText(ArrayList, CharSequence, int) 4431 */ 4432 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4433 4434 /** 4435 * Find views that contain {@link AccessibilityNodeProvider}. Such 4436 * a View is a root of virtual view hierarchy and may contain the searched 4437 * text. If this flag is set Views with providers are automatically 4438 * added and it is a responsibility of the client to call the APIs of 4439 * the provider to determine whether the virtual tree rooted at this View 4440 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4441 * representing the virtual views with this text. 4442 * 4443 * @see #findViewsWithText(ArrayList, CharSequence, int) 4444 * 4445 * @hide 4446 */ 4447 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4448 4449 /** 4450 * The undefined cursor position. 4451 * 4452 * @hide 4453 */ 4454 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4455 4456 /** 4457 * Indicates that the screen has changed state and is now off. 4458 * 4459 * @see #onScreenStateChanged(int) 4460 */ 4461 public static final int SCREEN_STATE_OFF = 0x0; 4462 4463 /** 4464 * Indicates that the screen has changed state and is now on. 4465 * 4466 * @see #onScreenStateChanged(int) 4467 */ 4468 public static final int SCREEN_STATE_ON = 0x1; 4469 4470 /** 4471 * Indicates no axis of view scrolling. 4472 */ 4473 public static final int SCROLL_AXIS_NONE = 0; 4474 4475 /** 4476 * Indicates scrolling along the horizontal axis. 4477 */ 4478 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4479 4480 /** 4481 * Indicates scrolling along the vertical axis. 4482 */ 4483 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4484 4485 /** 4486 * Controls the over-scroll mode for this view. 4487 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4488 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4489 * and {@link #OVER_SCROLL_NEVER}. 4490 */ 4491 private int mOverScrollMode; 4492 4493 /** 4494 * The parent this view is attached to. 4495 * {@hide} 4496 * 4497 * @see #getParent() 4498 */ 4499 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4500 protected ViewParent mParent; 4501 4502 /** 4503 * {@hide} 4504 * 4505 * Not available for general use. If you need help, hang up and then dial one of the following 4506 * public APIs: 4507 * 4508 * @see #isAttachedToWindow() for current attach state 4509 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4510 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4511 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4512 * @see #getHandler() for posting messages to this view's UI thread/looper 4513 * @see #getParent() for interacting with the parent chain 4514 * @see #getWindowToken() for the current window token 4515 * @see #getRootView() for the view at the root of the attached hierarchy 4516 * @see #getDisplay() for the Display this view is presented on 4517 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4518 * @see #hasWindowFocus() for whether the attached window is currently focused 4519 * @see #getWindowVisibility() for checking the visibility of the attached window 4520 */ 4521 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4522 AttachInfo mAttachInfo; 4523 4524 /** 4525 * {@hide} 4526 */ 4527 @ViewDebug.ExportedProperty(flagMapping = { 4528 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4529 name = "FORCE_LAYOUT"), 4530 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4531 name = "LAYOUT_REQUIRED"), 4532 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4533 name = "DRAWING_CACHE_INVALID", outputIf = false), 4534 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4535 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4536 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4537 }, formatToHexString = true) 4538 4539 /* @hide */ 4540 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4541 public int mPrivateFlags; 4542 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4543 int mPrivateFlags2; 4544 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4545 int mPrivateFlags3; 4546 4547 private int mPrivateFlags4; 4548 4549 /** 4550 * This view's request for the visibility of the status bar. 4551 * @hide 4552 */ 4553 @ViewDebug.ExportedProperty(flagMapping = { 4554 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4555 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4556 name = "LOW_PROFILE"), 4557 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4558 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4559 name = "HIDE_NAVIGATION"), 4560 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4561 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4562 name = "FULLSCREEN"), 4563 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4564 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4565 name = "LAYOUT_STABLE"), 4566 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4567 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4568 name = "LAYOUT_HIDE_NAVIGATION"), 4569 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4570 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4571 name = "LAYOUT_FULLSCREEN"), 4572 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4573 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4574 name = "IMMERSIVE"), 4575 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4576 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4577 name = "IMMERSIVE_STICKY"), 4578 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4579 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4580 name = "LIGHT_STATUS_BAR"), 4581 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4582 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4583 name = "LIGHT_NAVIGATION_BAR"), 4584 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4585 equals = STATUS_BAR_DISABLE_EXPAND, 4586 name = "STATUS_BAR_DISABLE_EXPAND"), 4587 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4588 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4589 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4590 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4591 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4592 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4593 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4594 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4595 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4596 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4597 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4598 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4599 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4600 equals = STATUS_BAR_DISABLE_HOME, 4601 name = "STATUS_BAR_DISABLE_HOME"), 4602 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4603 equals = STATUS_BAR_DISABLE_BACK, 4604 name = "STATUS_BAR_DISABLE_BACK"), 4605 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4606 equals = STATUS_BAR_DISABLE_CLOCK, 4607 name = "STATUS_BAR_DISABLE_CLOCK"), 4608 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4609 equals = STATUS_BAR_DISABLE_RECENT, 4610 name = "STATUS_BAR_DISABLE_RECENT"), 4611 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4612 equals = STATUS_BAR_DISABLE_SEARCH, 4613 name = "STATUS_BAR_DISABLE_SEARCH"), 4614 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4615 equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4616 name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") 4617 }, formatToHexString = true) 4618 @SystemUiVisibility 4619 int mSystemUiVisibility; 4620 4621 /** 4622 * @hide 4623 */ 4624 @IntDef(flag = true, prefix = "", value = { 4625 SYSTEM_UI_FLAG_LOW_PROFILE, 4626 SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4627 SYSTEM_UI_FLAG_FULLSCREEN, 4628 SYSTEM_UI_FLAG_LAYOUT_STABLE, 4629 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4630 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4631 SYSTEM_UI_FLAG_IMMERSIVE, 4632 SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4633 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4634 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4635 STATUS_BAR_DISABLE_EXPAND, 4636 STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4637 STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4638 STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4639 STATUS_BAR_DISABLE_SYSTEM_INFO, 4640 STATUS_BAR_DISABLE_HOME, 4641 STATUS_BAR_DISABLE_BACK, 4642 STATUS_BAR_DISABLE_CLOCK, 4643 STATUS_BAR_DISABLE_RECENT, 4644 STATUS_BAR_DISABLE_SEARCH, 4645 STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4646 }) 4647 @Retention(RetentionPolicy.SOURCE) 4648 public @interface SystemUiVisibility {} 4649 4650 /** 4651 * Reference count for transient state. 4652 * @see #setHasTransientState(boolean) 4653 */ 4654 int mTransientStateCount = 0; 4655 4656 /** 4657 * Count of how many windows this view has been attached to. 4658 */ 4659 int mWindowAttachCount; 4660 4661 /** 4662 * The layout parameters associated with this view and used by the parent 4663 * {@link android.view.ViewGroup} to determine how this view should be 4664 * laid out. 4665 * 4666 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4667 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4668 * state correctness of the class. 4669 * {@hide} 4670 */ 4671 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4672 protected ViewGroup.LayoutParams mLayoutParams; 4673 4674 /** 4675 * The view flags hold various views states. 4676 * 4677 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4678 * triggering updates. 4679 * {@hide} 4680 */ 4681 @ViewDebug.ExportedProperty(formatToHexString = true) 4682 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4683 int mViewFlags; 4684 4685 static class TransformationInfo { 4686 /** 4687 * The transform matrix for the View. This transform is calculated internally 4688 * based on the translation, rotation, and scale properties. 4689 * 4690 * Do *not* use this variable directly; instead call getMatrix(), which will 4691 * load the value from the View's RenderNode. 4692 */ 4693 private final Matrix mMatrix = new Matrix(); 4694 4695 /** 4696 * The inverse transform matrix for the View. This transform is calculated 4697 * internally based on the translation, rotation, and scale properties. 4698 * 4699 * Do *not* use this variable directly; instead call getInverseMatrix(), 4700 * which will load the value from the View's RenderNode. 4701 */ 4702 private Matrix mInverseMatrix; 4703 4704 /** 4705 * The opacity of the View. This is a value from 0 to 1, where 0 means 4706 * completely transparent and 1 means completely opaque. 4707 */ 4708 @ViewDebug.ExportedProperty 4709 private float mAlpha = 1f; 4710 4711 /** 4712 * The opacity of the view as manipulated by the Fade transition. This is a 4713 * property only used by transitions, which is composited with the other alpha 4714 * values to calculate the final visual alpha value. 4715 */ 4716 float mTransitionAlpha = 1f; 4717 } 4718 4719 /** @hide */ 4720 @UnsupportedAppUsage 4721 public TransformationInfo mTransformationInfo; 4722 4723 /** 4724 * Current clip bounds. to which all drawing of this view are constrained. 4725 */ 4726 @ViewDebug.ExportedProperty(category = "drawing") 4727 Rect mClipBounds = null; 4728 4729 private boolean mLastIsOpaque; 4730 4731 /** 4732 * The distance in pixels from the left edge of this view's parent 4733 * to the left edge of this view. 4734 * {@hide} 4735 */ 4736 @ViewDebug.ExportedProperty(category = "layout") 4737 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4738 protected int mLeft; 4739 /** 4740 * The mLeft from the previous frame. Used for detecting movement for purposes of variable 4741 * refresh rate. 4742 */ 4743 private int mLastFrameLeft; 4744 /** 4745 * The distance in pixels from the left edge of this view's parent 4746 * to the right edge of this view. 4747 * {@hide} 4748 */ 4749 @ViewDebug.ExportedProperty(category = "layout") 4750 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4751 protected int mRight; 4752 /** 4753 * The distance in pixels from the top edge of this view's parent 4754 * to the top edge of this view. 4755 * {@hide} 4756 */ 4757 @ViewDebug.ExportedProperty(category = "layout") 4758 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4759 protected int mTop; 4760 /** 4761 * The mTop from the previous frame. Used for detecting movement for purposes of variable 4762 * refresh rate. 4763 */ 4764 private int mLastFrameTop; 4765 /** 4766 * The distance in pixels from the top edge of this view's parent 4767 * to the bottom edge of this view. 4768 * {@hide} 4769 */ 4770 @ViewDebug.ExportedProperty(category = "layout") 4771 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4772 protected int mBottom; 4773 4774 /** 4775 * The offset, in pixels, by which the content of this view is scrolled 4776 * horizontally. 4777 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4778 * accessing these directly. 4779 * {@hide} 4780 */ 4781 @ViewDebug.ExportedProperty(category = "scrolling") 4782 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4783 protected int mScrollX; 4784 /** 4785 * The offset, in pixels, by which the content of this view is scrolled 4786 * vertically. 4787 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4788 * accessing these directly. 4789 * {@hide} 4790 */ 4791 @ViewDebug.ExportedProperty(category = "scrolling") 4792 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4793 protected int mScrollY; 4794 4795 /** 4796 * The final computed left padding in pixels that is used for drawing. This is the distance in 4797 * pixels between the left edge of this view and the left edge of its content. 4798 * {@hide} 4799 */ 4800 @ViewDebug.ExportedProperty(category = "padding") 4801 @UnsupportedAppUsage 4802 protected int mPaddingLeft = 0; 4803 /** 4804 * The final computed right padding in pixels that is used for drawing. This is the distance in 4805 * pixels between the right edge of this view and the right edge of its content. 4806 * {@hide} 4807 */ 4808 @ViewDebug.ExportedProperty(category = "padding") 4809 @UnsupportedAppUsage 4810 protected int mPaddingRight = 0; 4811 /** 4812 * The final computed top padding in pixels that is used for drawing. This is the distance in 4813 * pixels between the top edge of this view and the top edge of its content. 4814 * {@hide} 4815 */ 4816 @ViewDebug.ExportedProperty(category = "padding") 4817 @UnsupportedAppUsage 4818 protected int mPaddingTop; 4819 /** 4820 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4821 * pixels between the bottom edge of this view and the bottom edge of its content. 4822 * {@hide} 4823 */ 4824 @ViewDebug.ExportedProperty(category = "padding") 4825 @UnsupportedAppUsage 4826 protected int mPaddingBottom; 4827 4828 /** 4829 * The amount of pixel offset applied to the left edge of this view's handwriting bounds. 4830 */ 4831 private float mHandwritingBoundsOffsetLeft; 4832 4833 /** 4834 * The amount of pixel offset applied to the top edge of this view's handwriting bounds. 4835 */ 4836 private float mHandwritingBoundsOffsetTop; 4837 4838 /** 4839 * The amount of pixel offset applied to the right edge of this view's handwriting bounds. 4840 */ 4841 private float mHandwritingBoundsOffsetRight; 4842 4843 /** 4844 * The amount of pixel offset applied to the bottom edge of this view's handwriting bounds. 4845 */ 4846 private float mHandwritingBoundsOffsetBottom; 4847 4848 /** 4849 * The layout insets in pixels, that is the distance in pixels between the 4850 * visible edges of this view its bounds. 4851 */ 4852 private Insets mLayoutInsets; 4853 4854 /** 4855 * Briefly describes the state of the view and is primarily used for accessibility support. 4856 */ 4857 private CharSequence mStateDescription; 4858 4859 /** 4860 * Briefly describes the view and is primarily used for accessibility support. 4861 */ 4862 private CharSequence mContentDescription; 4863 4864 /** 4865 * If this view represents a distinct part of the window, it can have a title that labels the 4866 * area. 4867 */ 4868 private CharSequence mAccessibilityPaneTitle; 4869 4870 /** 4871 * Describes whether this view should only allow interactions from 4872 * {@link android.accessibilityservice.AccessibilityService}s with the 4873 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 4874 * set to true. 4875 */ 4876 private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; 4877 /** Used to calculate and cache {@link #isAccessibilityDataSensitive()}. */ 4878 private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; 4879 4880 /** 4881 * Specifies the id of a view for which this view serves as a label for 4882 * accessibility purposes. 4883 */ 4884 private int mLabelForId = View.NO_ID; 4885 4886 /** 4887 * Predicate for matching labeled view id with its label for 4888 * accessibility purposes. 4889 */ 4890 private MatchLabelForPredicate mMatchLabelForPredicate; 4891 4892 /** 4893 * Specifies a view before which this one is visited in accessibility traversal. 4894 */ 4895 private int mAccessibilityTraversalBeforeId = NO_ID; 4896 4897 /** 4898 * Specifies a view after which this one is visited in accessibility traversal. 4899 */ 4900 private int mAccessibilityTraversalAfterId = NO_ID; 4901 4902 /** 4903 * Predicate for matching a view by its id. 4904 */ 4905 private MatchIdPredicate mMatchIdPredicate; 4906 4907 /** 4908 * The right padding after RTL resolution, but before taking account of scroll bars. 4909 * 4910 * @hide 4911 */ 4912 @ViewDebug.ExportedProperty(category = "padding") 4913 protected int mUserPaddingRight; 4914 4915 /** 4916 * The resolved bottom padding before taking account of scroll bars. 4917 * 4918 * @hide 4919 */ 4920 @ViewDebug.ExportedProperty(category = "padding") 4921 protected int mUserPaddingBottom; 4922 4923 /** 4924 * The left padding after RTL resolution, but before taking account of scroll bars. 4925 * 4926 * @hide 4927 */ 4928 @ViewDebug.ExportedProperty(category = "padding") 4929 protected int mUserPaddingLeft; 4930 4931 /** 4932 * Cache the paddingStart set by the user to append to the scrollbar's size. 4933 * 4934 */ 4935 @ViewDebug.ExportedProperty(category = "padding") 4936 int mUserPaddingStart; 4937 4938 /** 4939 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4940 * 4941 */ 4942 @ViewDebug.ExportedProperty(category = "padding") 4943 int mUserPaddingEnd; 4944 4945 /** 4946 * The left padding as set by a setter method, a background's padding, or via XML property 4947 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4948 * 4949 * @hide 4950 */ 4951 int mUserPaddingLeftInitial; 4952 4953 /** 4954 * The right padding as set by a setter method, a background's padding, or via XML property 4955 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4956 * 4957 * @hide 4958 */ 4959 int mUserPaddingRightInitial; 4960 4961 /** 4962 * Default undefined padding 4963 */ 4964 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4965 4966 /** 4967 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4968 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4969 */ 4970 private boolean mLeftPaddingDefined = false; 4971 4972 /** 4973 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4974 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4975 */ 4976 private boolean mRightPaddingDefined = false; 4977 4978 /** 4979 * @hide 4980 */ 4981 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4982 /** 4983 * @hide 4984 */ 4985 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4986 4987 private LongSparseLongArray mMeasureCache; 4988 4989 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4990 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4991 private Drawable mBackground; 4992 private TintInfo mBackgroundTint; 4993 4994 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4995 private ForegroundInfo mForegroundInfo; 4996 4997 private Drawable mScrollIndicatorDrawable; 4998 4999 /** 5000 * RenderNode used for backgrounds. 5001 * <p> 5002 * When non-null and valid, this is expected to contain an up-to-date copy 5003 * of the background drawable. It is cleared on temporary detach, and reset 5004 * on cleanup. 5005 * @hide 5006 */ 5007 RenderNode mBackgroundRenderNode; 5008 5009 @UnsupportedAppUsage 5010 private int mBackgroundResource; 5011 private boolean mBackgroundSizeChanged; 5012 5013 /** The default focus highlight. 5014 * @see #mDefaultFocusHighlightEnabled 5015 * @see Drawable#hasFocusStateSpecified() 5016 */ 5017 private Drawable mDefaultFocusHighlight; 5018 private Drawable mDefaultFocusHighlightCache; 5019 private boolean mDefaultFocusHighlightSizeChanged; 5020 /** 5021 * True if the default focus highlight is needed on the target device. 5022 */ 5023 private static boolean sUseDefaultFocusHighlight; 5024 5025 /** 5026 * True if zero-sized views can be focused. 5027 */ 5028 private static boolean sCanFocusZeroSized; 5029 5030 /** 5031 * Always assign focus if a focusable View is available. 5032 */ 5033 private static boolean sAlwaysAssignFocus; 5034 5035 private String mTransitionName; 5036 5037 static class TintInfo { 5038 ColorStateList mTintList; 5039 BlendMode mBlendMode; 5040 boolean mHasTintMode; 5041 boolean mHasTintList; 5042 } 5043 5044 private static class ForegroundInfo { 5045 private Drawable mDrawable; 5046 private TintInfo mTintInfo; 5047 private int mGravity = Gravity.FILL; 5048 private boolean mInsidePadding = true; 5049 private boolean mBoundsChanged = true; 5050 private final Rect mSelfBounds = new Rect(); 5051 private final Rect mOverlayBounds = new Rect(); 5052 } 5053 5054 static class ListenerInfo { 5055 5056 @UnsupportedAppUsage ListenerInfo()5057 ListenerInfo() { 5058 } 5059 5060 /** 5061 * Listener used to dispatch focus change events. 5062 * This field should be made private, so it is hidden from the SDK. 5063 * {@hide} 5064 */ 5065 @UnsupportedAppUsage 5066 protected OnFocusChangeListener mOnFocusChangeListener; 5067 5068 /** 5069 * Listeners for layout change events. 5070 */ 5071 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 5072 5073 protected OnScrollChangeListener mOnScrollChangeListener; 5074 5075 /** 5076 * Listeners for attach events. 5077 */ 5078 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 5079 5080 /** 5081 * Listener used to dispatch click events. 5082 * This field should be made private, so it is hidden from the SDK. 5083 * {@hide} 5084 */ 5085 @UnsupportedAppUsage 5086 public OnClickListener mOnClickListener; 5087 5088 /** 5089 * Listener used to dispatch long click events. 5090 * This field should be made private, so it is hidden from the SDK. 5091 * {@hide} 5092 */ 5093 @UnsupportedAppUsage 5094 protected OnLongClickListener mOnLongClickListener; 5095 5096 /** 5097 * Listener used to dispatch context click events. This field should be made private, so it 5098 * is hidden from the SDK. 5099 * {@hide} 5100 */ 5101 protected OnContextClickListener mOnContextClickListener; 5102 5103 /** 5104 * Listener used to build the context menu. 5105 * This field should be made private, so it is hidden from the SDK. 5106 * {@hide} 5107 */ 5108 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5109 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 5110 5111 @UnsupportedAppUsage 5112 private OnKeyListener mOnKeyListener; 5113 5114 @UnsupportedAppUsage 5115 private OnTouchListener mOnTouchListener; 5116 5117 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5118 private OnHoverListener mOnHoverListener; 5119 5120 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5121 private OnGenericMotionListener mOnGenericMotionListener; 5122 5123 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5124 private OnDragListener mOnDragListener; 5125 5126 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 5127 5128 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 5129 5130 OnCapturedPointerListener mOnCapturedPointerListener; 5131 5132 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 5133 5134 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 5135 5136 /** 5137 * This lives here since it's only valid for interactive views. This list is null 5138 * until its first use. 5139 */ 5140 private List<Rect> mSystemGestureExclusionRects = null; 5141 private List<Rect> mKeepClearRects = null; 5142 private List<Rect> mUnrestrictedKeepClearRects = null; 5143 private boolean mPreferKeepClear = false; 5144 private Rect mHandwritingArea = null; 5145 5146 /** 5147 * Used to track {@link #mSystemGestureExclusionRects}, {@link #mKeepClearRects} and 5148 * {@link #mHandwritingArea}. 5149 */ 5150 public RenderNode.PositionUpdateListener mPositionUpdateListener; 5151 private Runnable mPositionChangedUpdate; 5152 5153 /** 5154 * Allows the application to implement custom scroll capture support. 5155 */ 5156 ScrollCaptureCallback mScrollCaptureCallback; 5157 5158 @Nullable 5159 private OnReceiveContentListener mOnReceiveContentListener; 5160 } 5161 5162 @UnsupportedAppUsage 5163 ListenerInfo mListenerInfo; 5164 5165 private static class TooltipInfo { 5166 /** 5167 * Text to be displayed in a tooltip popup. 5168 */ 5169 @Nullable 5170 CharSequence mTooltipText; 5171 5172 /** 5173 * View-relative position of the tooltip anchor point. 5174 */ 5175 int mAnchorX; 5176 int mAnchorY; 5177 5178 /** 5179 * The tooltip popup. 5180 */ 5181 @Nullable 5182 TooltipPopup mTooltipPopup; 5183 5184 /** 5185 * Set to true if the tooltip was shown as a result of a long click. 5186 */ 5187 boolean mTooltipFromLongClick; 5188 5189 /** 5190 * Keep these Runnables so that they can be used to reschedule. 5191 */ 5192 Runnable mShowTooltipRunnable; 5193 Runnable mHideTooltipRunnable; 5194 5195 /** 5196 * Hover move is ignored if it is within this distance in pixels from the previous one. 5197 */ 5198 int mHoverSlop; 5199 5200 /** 5201 * Update the anchor position if it significantly (that is by at least mHoverSlop) 5202 * different from the previously stored position. Ignoring insignificant changes 5203 * filters out the jitter which is typical for such input sources as stylus. 5204 * 5205 * @return True if the position has been updated. 5206 */ updateAnchorPos(MotionEvent event)5207 private boolean updateAnchorPos(MotionEvent event) { 5208 final int newAnchorX = (int) event.getX(); 5209 final int newAnchorY = (int) event.getY(); 5210 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 5211 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 5212 return false; 5213 } 5214 mAnchorX = newAnchorX; 5215 mAnchorY = newAnchorY; 5216 return true; 5217 } 5218 5219 /** 5220 * Clear the anchor position to ensure that the next change is considered significant. 5221 */ clearAnchorPos()5222 private void clearAnchorPos() { 5223 mAnchorX = Integer.MAX_VALUE; 5224 mAnchorY = Integer.MAX_VALUE; 5225 } 5226 } 5227 5228 TooltipInfo mTooltipInfo; 5229 5230 // Temporary values used to hold (x,y) coordinates when delegating from the 5231 // two-arg performLongClick() method to the legacy no-arg version. 5232 private float mLongClickX = Float.NaN; 5233 private float mLongClickY = Float.NaN; 5234 5235 /** 5236 * The application environment this view lives in. 5237 * This field should be made private, so it is hidden from the SDK. 5238 * {@hide} 5239 */ 5240 @ViewDebug.ExportedProperty(deepExport = true) 5241 @UnsupportedAppUsage 5242 @UiContext 5243 protected Context mContext; 5244 5245 @UnsupportedAppUsage 5246 private final Resources mResources; 5247 5248 @UnsupportedAppUsage 5249 private ScrollabilityCache mScrollCache; 5250 5251 private int[] mDrawableState = null; 5252 5253 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 5254 5255 /** 5256 * Animator that automatically runs based on state changes. 5257 */ 5258 private StateListAnimator mStateListAnimator; 5259 5260 /** 5261 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 5262 * the user may specify which view to go to next. 5263 */ 5264 private int mNextFocusLeftId = View.NO_ID; 5265 5266 /** 5267 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 5268 * the user may specify which view to go to next. 5269 */ 5270 private int mNextFocusRightId = View.NO_ID; 5271 5272 /** 5273 * When this view has focus and the next focus is {@link #FOCUS_UP}, 5274 * the user may specify which view to go to next. 5275 */ 5276 private int mNextFocusUpId = View.NO_ID; 5277 5278 /** 5279 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 5280 * the user may specify which view to go to next. 5281 */ 5282 private int mNextFocusDownId = View.NO_ID; 5283 5284 /** 5285 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 5286 * the user may specify which view to go to next. 5287 */ 5288 int mNextFocusForwardId = View.NO_ID; 5289 5290 /** 5291 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 5292 * 5293 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 5294 */ 5295 int mNextClusterForwardId = View.NO_ID; 5296 5297 /** 5298 * Whether this View should use a default focus highlight when it gets focused but doesn't 5299 * have {@link android.R.attr#state_focused} defined in its background. 5300 */ 5301 boolean mDefaultFocusHighlightEnabled = true; 5302 5303 private CheckForLongPress mPendingCheckForLongPress; 5304 @UnsupportedAppUsage 5305 private CheckForTap mPendingCheckForTap = null; 5306 private PerformClick mPerformClick; 5307 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 5308 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 5309 private UnsetPressedState mUnsetPressedState; 5310 5311 /** 5312 * Whether the long press's action has been invoked. The tap's action is invoked on the 5313 * up event while a long press is invoked as soon as the long press duration is reached, so 5314 * a long press could be performed before the tap is checked, in which case the tap's action 5315 * should not be invoked. 5316 */ 5317 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5318 private boolean mHasPerformedLongPress; 5319 5320 /** 5321 * Whether a context click button is currently pressed down. This is true when the stylus is 5322 * touching the screen and the primary button has been pressed, or if a mouse's right button is 5323 * pressed. This is false once the button is released or if the stylus has been lifted. 5324 */ 5325 private boolean mInContextButtonPress; 5326 5327 /** 5328 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 5329 * true after a stylus button press has occured, when the next up event should not be recognized 5330 * as a tap. 5331 */ 5332 private boolean mIgnoreNextUpEvent; 5333 5334 /** 5335 * The minimum height of the view. We'll try our best to have the height 5336 * of this view to at least this amount. 5337 */ 5338 @ViewDebug.ExportedProperty(category = "measurement") 5339 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 5340 private int mMinHeight; 5341 5342 /** 5343 * The minimum width of the view. We'll try our best to have the width 5344 * of this view to at least this amount. 5345 */ 5346 @ViewDebug.ExportedProperty(category = "measurement") 5347 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 5348 private int mMinWidth; 5349 5350 /** 5351 * The delegate to handle touch events that are physically in this view 5352 * but should be handled by another view. 5353 */ 5354 private TouchDelegate mTouchDelegate = null; 5355 5356 /** 5357 * While touch exploration is in use, set to true when hovering across boundaries and 5358 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 5359 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 5360 * {@link MotionEvent#ACTION_HOVER_EXIT}. 5361 * Note that children of view group are excluded in the touch area. 5362 * @see #dispatchTouchExplorationHoverEvent 5363 */ 5364 private boolean mHoveringTouchDelegate = false; 5365 5366 // These two fields are set if the view is a handwriting delegator. 5367 private Runnable mHandwritingDelegatorCallback; 5368 private String mAllowedHandwritingDelegatePackageName; 5369 5370 // These three fields are set if the view is a handwriting delegate. 5371 private boolean mIsHandwritingDelegate; 5372 private String mAllowedHandwritingDelegatorPackageName; 5373 private @InputMethodManager.HandwritingDelegateFlags int mHandwritingDelegateFlags; 5374 5375 /** 5376 * Solid color to use as a background when creating the drawing cache. Enables 5377 * the cache to use 16 bit bitmaps instead of 32 bit. 5378 */ 5379 private int mDrawingCacheBackgroundColor = 0; 5380 5381 /** 5382 * Special tree observer used when mAttachInfo is null. 5383 */ 5384 private ViewTreeObserver mFloatingTreeObserver; 5385 5386 /** 5387 * Cache the touch slop from the context that created the view. 5388 */ 5389 private int mTouchSlop; 5390 5391 /** 5392 * Cache the ambiguous gesture multiplier from the context that created the view. 5393 */ 5394 private float mAmbiguousGestureMultiplier; 5395 5396 /** 5397 * Object that handles automatic animation of view properties. 5398 */ 5399 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5400 private ViewPropertyAnimator mAnimator = null; 5401 5402 /** 5403 * List of registered FrameMetricsObservers. 5404 */ 5405 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 5406 5407 /** 5408 * Flag indicating that a drag can cross window boundaries. When 5409 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5410 * with this flag set, all visible applications with targetSdkVersion >= 5411 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 5412 * in the drag operation and receive the dragged content. 5413 * 5414 * <p>If this is the only flag set, then the drag recipient will only have access to text data 5415 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 5416 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 5417 */ 5418 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 5419 5420 /** 5421 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5422 * request read access to the content URI(s) contained in the {@link ClipData} object. 5423 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5424 */ 5425 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5426 5427 /** 5428 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5429 * request write access to the content URI(s) contained in the {@link ClipData} object. 5430 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5431 */ 5432 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5433 5434 /** 5435 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5436 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5437 * reboots until explicitly revoked with 5438 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5439 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5440 */ 5441 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5442 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5443 5444 /** 5445 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5446 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5447 * match against the original granted URI. 5448 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5449 */ 5450 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5451 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5452 5453 /** 5454 * Flag indicating that the drag shadow will be opaque. When 5455 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5456 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5457 */ 5458 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5459 5460 /** 5461 * Flag indicating that the drag was initiated with 5462 * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. When 5463 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called, this 5464 * is used by the system to perform a drag without animations. 5465 */ 5466 public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; 5467 5468 /** 5469 * Flag indicating that the caller desires to take ownership of the drag surface for handling 5470 * the animation associated with an unhandled drag. It is mainly useful if the view starting 5471 * a global drag changes visibility during the gesture and the default animation of animating 5472 * the surface back to the origin is not sufficient. 5473 * 5474 * The calling app must hold the {@link android.Manifest.permission#START_TASKS_FROM_RECENTS} 5475 * permission and will receive the drag surface as a part of 5476 * {@link action.view.DragEvent#ACTION_DRAG_ENDED} only if the drag event's 5477 * {@link action.view.DragEvent#getDragResult()} is {@code false}. The caller is responsible 5478 * for removing the surface after its animation. 5479 * 5480 * This flag has no effect if the system decides that a cancel-drag animation does not need to 5481 * occur. 5482 * @hide 5483 */ 5484 public static final int DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION = 1 << 11; 5485 5486 /** 5487 * Flag indicating that a drag can cross window boundaries (within the same application). When 5488 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5489 * with this flag set, only visible windows belonging to the same application (ie. share the 5490 * same UID) with targetSdkVersion >= {@link android.os.Build.VERSION_CODES#N API 24} will be 5491 * able to participate in the drag operation and receive the dragged content. 5492 * 5493 * If both DRAG_FLAG_GLOBAL_SAME_APPLICATION and DRAG_FLAG_GLOBAL are set, then 5494 * DRAG_FLAG_GLOBAL_SAME_APPLICATION takes precedence and the drag will only go to visible 5495 * windows from the same application. 5496 */ 5497 @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) 5498 public static final int DRAG_FLAG_GLOBAL_SAME_APPLICATION = 1 << 12; 5499 5500 /** 5501 * Flag indicating that an unhandled drag should be delegated to the system to be started if no 5502 * visible window wishes to handle the drop. When using this flag, the caller must provide 5503 * ClipData with an Item that contains an immutable IntentSender to an activity to be launched 5504 * (not a broadcast, service, etc). See 5505 * {@link ClipData.Item.Builder#setIntentSender(IntentSender)}. 5506 * 5507 * The system can decide to launch the intent or not based on factors like the current screen 5508 * size or windowing mode. If the system does not launch the intent, it will be canceled via the 5509 * normal drag and drop flow. 5510 */ 5511 @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) 5512 public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 1 << 13; 5513 5514 /** 5515 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5516 */ 5517 private float mVerticalScrollFactor; 5518 5519 /** 5520 * Position of the vertical scroll bar. 5521 */ 5522 @UnsupportedAppUsage 5523 private int mVerticalScrollbarPosition; 5524 5525 /** 5526 * Position the scroll bar at the default position as determined by the system. 5527 */ 5528 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5529 5530 /** 5531 * Position the scroll bar along the left edge. 5532 */ 5533 public static final int SCROLLBAR_POSITION_LEFT = 1; 5534 5535 /** 5536 * Position the scroll bar along the right edge. 5537 */ 5538 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5539 5540 /** 5541 * Indicates that the view does not have a layer. 5542 * 5543 * @see #getLayerType() 5544 * @see #setLayerType(int, android.graphics.Paint) 5545 * @see #LAYER_TYPE_SOFTWARE 5546 * @see #LAYER_TYPE_HARDWARE 5547 */ 5548 public static final int LAYER_TYPE_NONE = 0; 5549 5550 /** 5551 * <p>Indicates that the view has a software layer. A software layer is backed 5552 * by a bitmap and causes the view to be rendered using Android's software 5553 * rendering pipeline, even if hardware acceleration is enabled.</p> 5554 * 5555 * <p>Software layers have various usages:</p> 5556 * <p>When the application is not using hardware acceleration, a software layer 5557 * is useful to apply a specific color filter and/or blending mode and/or 5558 * translucency to a view and all its children.</p> 5559 * <p>When the application is using hardware acceleration, a software layer 5560 * is useful to render drawing primitives not supported by the hardware 5561 * accelerated pipeline. It can also be used to cache a complex view tree 5562 * into a texture and reduce the complexity of drawing operations. For instance, 5563 * when animating a complex view tree with a translation, a software layer can 5564 * be used to render the view tree only once.</p> 5565 * <p>Software layers should be avoided when the affected view tree updates 5566 * often. Every update will require to re-render the software layer, which can 5567 * potentially be slow (particularly when hardware acceleration is turned on 5568 * since the layer will have to be uploaded into a hardware texture after every 5569 * update.)</p> 5570 * 5571 * @see #getLayerType() 5572 * @see #setLayerType(int, android.graphics.Paint) 5573 * @see #LAYER_TYPE_NONE 5574 * @see #LAYER_TYPE_HARDWARE 5575 */ 5576 public static final int LAYER_TYPE_SOFTWARE = 1; 5577 5578 /** 5579 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5580 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5581 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5582 * rendering pipeline, but only if hardware acceleration is turned on for the 5583 * view hierarchy. When hardware acceleration is turned off, hardware layers 5584 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5585 * 5586 * <p>A hardware layer is useful to apply a specific color filter and/or 5587 * blending mode and/or translucency to a view and all its children.</p> 5588 * <p>A hardware layer can be used to cache a complex view tree into a 5589 * texture and reduce the complexity of drawing operations. For instance, 5590 * when animating a complex view tree with a translation, a hardware layer can 5591 * be used to render the view tree only once.</p> 5592 * <p>A hardware layer can also be used to increase the rendering quality when 5593 * rotation transformations are applied on a view. It can also be used to 5594 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5595 * 5596 * @see #getLayerType() 5597 * @see #setLayerType(int, android.graphics.Paint) 5598 * @see #LAYER_TYPE_NONE 5599 * @see #LAYER_TYPE_SOFTWARE 5600 */ 5601 public static final int LAYER_TYPE_HARDWARE = 2; 5602 5603 /** @hide */ 5604 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5605 LAYER_TYPE_NONE, 5606 LAYER_TYPE_SOFTWARE, 5607 LAYER_TYPE_HARDWARE 5608 }) 5609 @Retention(RetentionPolicy.SOURCE) 5610 public @interface LayerType {} 5611 5612 int mLayerType = LAYER_TYPE_NONE; 5613 Paint mLayerPaint; 5614 5615 /** 5616 * Set to true when drawing cache is enabled and cannot be created. 5617 * 5618 * @hide 5619 */ 5620 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5621 public boolean mCachingFailed; 5622 @UnsupportedAppUsage 5623 private Bitmap mDrawingCache; 5624 @UnsupportedAppUsage 5625 private Bitmap mUnscaledDrawingCache; 5626 5627 /** 5628 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5629 * <p> 5630 * When non-null and valid, this is expected to contain an up-to-date copy 5631 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5632 * cleanup. 5633 */ 5634 @UnsupportedAppUsage 5635 final RenderNode mRenderNode; 5636 5637 /** 5638 * Set to true when the view is sending hover accessibility events because it 5639 * is the innermost hovered view. 5640 */ 5641 private boolean mSendingHoverAccessibilityEvents; 5642 5643 /** 5644 * Delegate for injecting accessibility functionality. 5645 */ 5646 @UnsupportedAppUsage 5647 AccessibilityDelegate mAccessibilityDelegate; 5648 5649 /** 5650 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5651 * and add/remove objects to/from the overlay directly through the Overlay methods. 5652 */ 5653 ViewOverlay mOverlay; 5654 5655 /** 5656 * The currently active parent view for receiving delegated nested scrolling events. 5657 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5658 * by {@link #stopNestedScroll()} at the same point where we clear 5659 * requestDisallowInterceptTouchEvent. 5660 */ 5661 private ViewParent mNestedScrollingParent; 5662 5663 /** 5664 * Consistency verifier for debugging purposes. 5665 * @hide 5666 */ 5667 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5668 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5669 new InputEventConsistencyVerifier(this, 0) : null; 5670 5671 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5672 5673 private int[] mTempNestedScrollConsumed; 5674 5675 /** 5676 * An overlay is going to draw this View instead of being drawn as part of this 5677 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5678 * when this view is invalidated. 5679 */ 5680 GhostView mGhostView; 5681 5682 /** 5683 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5684 * @hide 5685 */ 5686 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5687 public String[] mAttributes; 5688 5689 /** 5690 * Maps a Resource id to its name. 5691 */ 5692 private static SparseArray<String> mAttributeMap; 5693 5694 /** 5695 * Queue of pending runnables. Used to postpone calls to post() until this 5696 * view is attached and has a handler. 5697 */ 5698 private HandlerActionQueue mRunQueue; 5699 5700 /** 5701 * The pointer icon when the mouse hovers on this view. The default is null. 5702 */ 5703 private PointerIcon mMousePointerIcon; 5704 5705 /** Vibrator for haptic feedback. */ 5706 private Vibrator mVibrator; 5707 5708 /** 5709 * @hide 5710 */ 5711 @UnsupportedAppUsage 5712 String mStartActivityRequestWho; 5713 5714 @Nullable 5715 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5716 5717 /** Used to delay visibility updates sent to the autofill manager */ 5718 private Handler mVisibilityChangeForAutofillHandler; 5719 5720 /** 5721 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5722 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5723 */ 5724 @Nullable 5725 private ContentCaptureSession mContentCaptureSession; 5726 5727 /** 5728 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5729 */ 5730 private boolean mContentCaptureSessionCached; 5731 5732 @LayoutRes 5733 private int mSourceLayoutId = ID_NULL; 5734 5735 @Nullable 5736 private SparseIntArray mAttributeSourceResId; 5737 5738 @Nullable 5739 private SparseArray<int[]> mAttributeResolutionStacks; 5740 5741 @StyleRes 5742 private int mExplicitStyle; 5743 5744 /** 5745 * Specifies which input source classes should provide unbuffered input events to this view 5746 * 5747 * @see View#requestUnbufferedDispatch(int) 5748 */ 5749 @InputSourceClass 5750 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5751 5752 @Nullable 5753 private String[] mReceiveContentMimeTypes; 5754 5755 @Nullable 5756 private ViewTranslationCallback mViewTranslationCallback; 5757 5758 private float mFrameContentVelocity = -1; 5759 5760 @Nullable 5761 5762 private ViewTranslationResponse mViewTranslationResponse; 5763 5764 /** 5765 * The size in DP that is considered small for VRR purposes, if square. 5766 */ 5767 private static final float FRAME_RATE_SQUARE_SMALL_SIZE_DP = 40f; 5768 5769 /** 5770 * The size in DP that is considered small for VRR purposes in the narrow dimension. Used for 5771 * narrow Views like a progress bar. 5772 */ 5773 private static final float FRAME_RATE_NARROW_SIZE_DP = 10f; 5774 5775 /** 5776 * A threshold value to determine the frame rate category of the View based on the size. 5777 */ 5778 private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f; 5779 5780 static final float MAX_FRAME_RATE = 120; 5781 5782 // The preferred frame rate of the view that is mainly used for 5783 // touch boosting, view velocity handling, and TextureView. 5784 private float mPreferredFrameRate = REQUESTED_FRAME_RATE_CATEGORY_DEFAULT; 5785 5786 private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; 5787 5788 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5789 public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; 5790 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5791 public static final float REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE = -1; 5792 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5793 public static final float REQUESTED_FRAME_RATE_CATEGORY_LOW = -2; 5794 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5795 public static final float REQUESTED_FRAME_RATE_CATEGORY_NORMAL = -3; 5796 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5797 public static final float REQUESTED_FRAME_RATE_CATEGORY_HIGH = -4; 5798 5799 private int mSizeBasedFrameRateCategoryAndReason; 5800 5801 /** 5802 * Simple constructor to use when creating a view from code. 5803 * 5804 * @param context The Context the view is running in, through which it can 5805 * access the current theme, resources, etc. 5806 */ View(Context context)5807 public View(Context context) { 5808 mContext = context; 5809 mResources = context != null ? context.getResources() : null; 5810 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5811 // Set some flags defaults 5812 mPrivateFlags2 = 5813 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5814 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5815 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5816 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5817 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5818 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5819 5820 final ViewConfiguration configuration = ViewConfiguration.get(context); 5821 mTouchSlop = configuration.getScaledTouchSlop(); 5822 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5823 5824 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5825 mUserPaddingStart = UNDEFINED_PADDING; 5826 mUserPaddingEnd = UNDEFINED_PADDING; 5827 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5828 5829 if (!sCompatibilityDone && context != null) { 5830 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5831 5832 // Old versions of the platform would give different results from 5833 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5834 // modes, so we always need to run an additional EXACTLY pass. 5835 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5836 5837 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5838 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5839 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5840 5841 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5842 // in apps so we target check it to avoid breaking existing apps. 5843 sPreserveMarginParamsInLayoutParamConversion = 5844 targetSdkVersion >= Build.VERSION_CODES.N; 5845 5846 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5847 5848 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5849 5850 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5851 5852 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5853 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5854 5855 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5856 5857 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5858 5859 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5860 5861 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5862 5863 sBrokenInsetsDispatch = targetSdkVersion < Build.VERSION_CODES.R; 5864 5865 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5866 5867 GradientDrawable.sWrapNegativeAngleMeasurements = 5868 targetSdkVersion >= Build.VERSION_CODES.Q; 5869 5870 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5871 5872 sCompatibilityDone = true; 5873 } 5874 } 5875 5876 /** 5877 * Constructor that is called when inflating a view from XML. This is called 5878 * when a view is being constructed from an XML file, supplying attributes 5879 * that were specified in the XML file. This version uses a default style of 5880 * 0, so the only attribute values applied are those in the Context's Theme 5881 * and the given AttributeSet. 5882 * 5883 * <p> 5884 * The method onFinishInflate() will be called after all children have been 5885 * added. 5886 * 5887 * @param context The Context the view is running in, through which it can 5888 * access the current theme, resources, etc. 5889 * @param attrs The attributes of the XML tag that is inflating the view. 5890 * @see #View(Context, AttributeSet, int) 5891 */ 5892 public View(Context context, @Nullable AttributeSet attrs) { 5893 this(context, attrs, 0); 5894 } 5895 5896 /** 5897 * Perform inflation from XML and apply a class-specific base style from a 5898 * theme attribute. This constructor of View allows subclasses to use their 5899 * own base style when they are inflating. For example, a Button class's 5900 * constructor would call this version of the super class constructor and 5901 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5902 * allows the theme's button style to modify all of the base view attributes 5903 * (in particular its background) as well as the Button class's attributes. 5904 * 5905 * @param context The Context the view is running in, through which it can 5906 * access the current theme, resources, etc. 5907 * @param attrs The attributes of the XML tag that is inflating the view. 5908 * @param defStyleAttr An attribute in the current theme that contains a 5909 * reference to a style resource that supplies default values for 5910 * the view. Can be 0 to not look for defaults. 5911 * @see #View(Context, AttributeSet) 5912 */ 5913 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5914 this(context, attrs, defStyleAttr, 0); 5915 } 5916 5917 /** 5918 * Perform inflation from XML and apply a class-specific base style from a 5919 * theme attribute or style resource. This constructor of View allows 5920 * subclasses to use their own base style when they are inflating. 5921 * <p> 5922 * When determining the final value of a particular attribute, there are 5923 * four inputs that come into play: 5924 * <ol> 5925 * <li>Any attribute values in the given AttributeSet. 5926 * <li>The style resource specified in the AttributeSet (named "style"). 5927 * <li>The default style specified by <var>defStyleAttr</var>. 5928 * <li>The default style specified by <var>defStyleRes</var>. 5929 * <li>The base values in this theme. 5930 * </ol> 5931 * <p> 5932 * Each of these inputs is considered in-order, with the first listed taking 5933 * precedence over the following ones. In other words, if in the 5934 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5935 * , then the button's text will <em>always</em> be black, regardless of 5936 * what is specified in any of the styles. 5937 * 5938 * @param context The Context the view is running in, through which it can 5939 * access the current theme, resources, etc. 5940 * @param attrs The attributes of the XML tag that is inflating the view. 5941 * @param defStyleAttr An attribute in the current theme that contains a 5942 * reference to a style resource that supplies default values for 5943 * the view. Can be 0 to not look for defaults. 5944 * @param defStyleRes A resource identifier of a style resource that 5945 * supplies default values for the view, used only if 5946 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5947 * to not look for defaults. 5948 * @see #View(Context, AttributeSet, int) 5949 */ 5950 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5951 this(context); 5952 5953 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5954 5955 final TypedArray a = context.obtainStyledAttributes( 5956 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5957 5958 retrieveExplicitStyle(context.getTheme(), attrs); 5959 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5960 defStyleAttr, defStyleRes); 5961 5962 if (sDebugViewAttributes) { 5963 saveAttributeData(attrs, a); 5964 } 5965 5966 Drawable background = null; 5967 5968 int leftPadding = -1; 5969 int topPadding = -1; 5970 int rightPadding = -1; 5971 int bottomPadding = -1; 5972 int startPadding = UNDEFINED_PADDING; 5973 int endPadding = UNDEFINED_PADDING; 5974 5975 int padding = -1; 5976 int paddingHorizontal = -1; 5977 int paddingVertical = -1; 5978 5979 int viewFlagValues = 0; 5980 int viewFlagMasks = 0; 5981 5982 boolean setScrollContainer = false; 5983 5984 int x = 0; 5985 int y = 0; 5986 5987 float tx = 0; 5988 float ty = 0; 5989 float tz = 0; 5990 float elevation = 0; 5991 float rotation = 0; 5992 float rotationX = 0; 5993 float rotationY = 0; 5994 float sx = 1f; 5995 float sy = 1f; 5996 boolean transformSet = false; 5997 5998 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5999 int overScrollMode = mOverScrollMode; 6000 boolean initializeScrollbars = false; 6001 boolean initializeScrollIndicators = false; 6002 6003 boolean startPaddingDefined = false; 6004 boolean endPaddingDefined = false; 6005 boolean leftPaddingDefined = false; 6006 boolean rightPaddingDefined = false; 6007 6008 // Set default values. 6009 viewFlagValues |= FOCUSABLE_AUTO; 6010 viewFlagMasks |= FOCUSABLE_AUTO; 6011 6012 final int N = a.getIndexCount(); 6013 for (int i = 0; i < N; i++) { 6014 int attr = a.getIndex(i); 6015 switch (attr) { 6016 case com.android.internal.R.styleable.View_background: 6017 background = a.getDrawable(attr); 6018 break; 6019 case com.android.internal.R.styleable.View_padding: 6020 padding = a.getDimensionPixelSize(attr, -1); 6021 mUserPaddingLeftInitial = padding; 6022 mUserPaddingRightInitial = padding; 6023 leftPaddingDefined = true; 6024 rightPaddingDefined = true; 6025 break; 6026 case com.android.internal.R.styleable.View_paddingHorizontal: 6027 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 6028 mUserPaddingLeftInitial = paddingHorizontal; 6029 mUserPaddingRightInitial = paddingHorizontal; 6030 leftPaddingDefined = true; 6031 rightPaddingDefined = true; 6032 break; 6033 case com.android.internal.R.styleable.View_paddingVertical: 6034 paddingVertical = a.getDimensionPixelSize(attr, -1); 6035 break; 6036 case com.android.internal.R.styleable.View_paddingLeft: 6037 leftPadding = a.getDimensionPixelSize(attr, -1); 6038 mUserPaddingLeftInitial = leftPadding; 6039 leftPaddingDefined = true; 6040 break; 6041 case com.android.internal.R.styleable.View_paddingTop: 6042 topPadding = a.getDimensionPixelSize(attr, -1); 6043 break; 6044 case com.android.internal.R.styleable.View_paddingRight: 6045 rightPadding = a.getDimensionPixelSize(attr, -1); 6046 mUserPaddingRightInitial = rightPadding; 6047 rightPaddingDefined = true; 6048 break; 6049 case com.android.internal.R.styleable.View_paddingBottom: 6050 bottomPadding = a.getDimensionPixelSize(attr, -1); 6051 break; 6052 case com.android.internal.R.styleable.View_paddingStart: 6053 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 6054 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 6055 break; 6056 case com.android.internal.R.styleable.View_paddingEnd: 6057 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 6058 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 6059 break; 6060 case com.android.internal.R.styleable.View_scrollX: 6061 x = a.getDimensionPixelOffset(attr, 0); 6062 break; 6063 case com.android.internal.R.styleable.View_scrollY: 6064 y = a.getDimensionPixelOffset(attr, 0); 6065 break; 6066 case com.android.internal.R.styleable.View_alpha: 6067 setAlpha(a.getFloat(attr, 1f)); 6068 break; 6069 case com.android.internal.R.styleable.View_transformPivotX: 6070 setPivotX(a.getDimension(attr, 0)); 6071 break; 6072 case com.android.internal.R.styleable.View_transformPivotY: 6073 setPivotY(a.getDimension(attr, 0)); 6074 break; 6075 case com.android.internal.R.styleable.View_translationX: 6076 tx = a.getDimension(attr, 0); 6077 transformSet = true; 6078 break; 6079 case com.android.internal.R.styleable.View_translationY: 6080 ty = a.getDimension(attr, 0); 6081 transformSet = true; 6082 break; 6083 case com.android.internal.R.styleable.View_translationZ: 6084 tz = a.getDimension(attr, 0); 6085 transformSet = true; 6086 break; 6087 case com.android.internal.R.styleable.View_elevation: 6088 elevation = a.getDimension(attr, 0); 6089 transformSet = true; 6090 break; 6091 case com.android.internal.R.styleable.View_rotation: 6092 rotation = a.getFloat(attr, 0); 6093 transformSet = true; 6094 break; 6095 case com.android.internal.R.styleable.View_rotationX: 6096 rotationX = a.getFloat(attr, 0); 6097 transformSet = true; 6098 break; 6099 case com.android.internal.R.styleable.View_rotationY: 6100 rotationY = a.getFloat(attr, 0); 6101 transformSet = true; 6102 break; 6103 case com.android.internal.R.styleable.View_scaleX: 6104 sx = a.getFloat(attr, 1f); 6105 transformSet = true; 6106 break; 6107 case com.android.internal.R.styleable.View_scaleY: 6108 sy = a.getFloat(attr, 1f); 6109 transformSet = true; 6110 break; 6111 case com.android.internal.R.styleable.View_id: 6112 mID = a.getResourceId(attr, NO_ID); 6113 break; 6114 case com.android.internal.R.styleable.View_tag: 6115 mTag = a.getText(attr); 6116 break; 6117 case com.android.internal.R.styleable.View_fitsSystemWindows: 6118 if (a.getBoolean(attr, false)) { 6119 viewFlagValues |= FITS_SYSTEM_WINDOWS; 6120 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 6121 } 6122 break; 6123 case com.android.internal.R.styleable.View_focusable: 6124 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 6125 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 6126 viewFlagMasks |= FOCUSABLE_MASK; 6127 } 6128 break; 6129 case com.android.internal.R.styleable.View_focusableInTouchMode: 6130 if (a.getBoolean(attr, false)) { 6131 // unset auto focus since focusableInTouchMode implies explicit focusable 6132 viewFlagValues &= ~FOCUSABLE_AUTO; 6133 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 6134 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 6135 } 6136 break; 6137 case com.android.internal.R.styleable.View_clickable: 6138 if (a.getBoolean(attr, false)) { 6139 viewFlagValues |= CLICKABLE; 6140 viewFlagMasks |= CLICKABLE; 6141 } 6142 break; 6143 case com.android.internal.R.styleable.View_allowClickWhenDisabled: 6144 setAllowClickWhenDisabled(a.getBoolean(attr, false)); 6145 break; 6146 case com.android.internal.R.styleable.View_longClickable: 6147 if (a.getBoolean(attr, false)) { 6148 viewFlagValues |= LONG_CLICKABLE; 6149 viewFlagMasks |= LONG_CLICKABLE; 6150 } 6151 break; 6152 case com.android.internal.R.styleable.View_contextClickable: 6153 if (a.getBoolean(attr, false)) { 6154 viewFlagValues |= CONTEXT_CLICKABLE; 6155 viewFlagMasks |= CONTEXT_CLICKABLE; 6156 } 6157 break; 6158 case com.android.internal.R.styleable.View_saveEnabled: 6159 if (!a.getBoolean(attr, true)) { 6160 viewFlagValues |= SAVE_DISABLED; 6161 viewFlagMasks |= SAVE_DISABLED_MASK; 6162 } 6163 break; 6164 case com.android.internal.R.styleable.View_duplicateParentState: 6165 if (a.getBoolean(attr, false)) { 6166 viewFlagValues |= DUPLICATE_PARENT_STATE; 6167 viewFlagMasks |= DUPLICATE_PARENT_STATE; 6168 } 6169 break; 6170 case com.android.internal.R.styleable.View_visibility: 6171 final int visibility = a.getInt(attr, 0); 6172 if (visibility != 0) { 6173 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 6174 viewFlagMasks |= VISIBILITY_MASK; 6175 } 6176 break; 6177 case com.android.internal.R.styleable.View_layoutDirection: 6178 // Clear any layout direction flags (included resolved bits) already set 6179 mPrivateFlags2 &= 6180 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 6181 // Set the layout direction flags depending on the value of the attribute 6182 final int layoutDirection = a.getInt(attr, -1); 6183 final int value = (layoutDirection != -1) ? 6184 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 6185 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 6186 break; 6187 case com.android.internal.R.styleable.View_drawingCacheQuality: 6188 final int cacheQuality = a.getInt(attr, 0); 6189 if (cacheQuality != 0) { 6190 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 6191 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 6192 } 6193 break; 6194 case com.android.internal.R.styleable.View_contentDescription: 6195 setContentDescription(a.getString(attr)); 6196 break; 6197 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 6198 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 6199 break; 6200 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 6201 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 6202 break; 6203 case com.android.internal.R.styleable.View_labelFor: 6204 setLabelFor(a.getResourceId(attr, NO_ID)); 6205 break; 6206 case com.android.internal.R.styleable.View_soundEffectsEnabled: 6207 if (!a.getBoolean(attr, true)) { 6208 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 6209 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 6210 } 6211 break; 6212 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 6213 if (!a.getBoolean(attr, true)) { 6214 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 6215 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 6216 } 6217 break; 6218 case R.styleable.View_scrollbars: 6219 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 6220 if (scrollbars != SCROLLBARS_NONE) { 6221 viewFlagValues |= scrollbars; 6222 viewFlagMasks |= SCROLLBARS_MASK; 6223 initializeScrollbars = true; 6224 } 6225 break; 6226 //noinspection deprecation 6227 case R.styleable.View_fadingEdge: 6228 break; 6229 case R.styleable.View_requiresFadingEdge: 6230 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 6231 if (fadingEdge != FADING_EDGE_NONE) { 6232 viewFlagValues |= fadingEdge; 6233 viewFlagMasks |= FADING_EDGE_MASK; 6234 initializeFadingEdgeInternal(a); 6235 } 6236 break; 6237 case R.styleable.View_scrollbarStyle: 6238 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 6239 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6240 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 6241 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 6242 } 6243 break; 6244 case R.styleable.View_isScrollContainer: 6245 setScrollContainer = true; 6246 if (a.getBoolean(attr, false)) { 6247 setScrollContainer(true); 6248 } 6249 break; 6250 case com.android.internal.R.styleable.View_keepScreenOn: 6251 if (a.getBoolean(attr, false)) { 6252 viewFlagValues |= KEEP_SCREEN_ON; 6253 viewFlagMasks |= KEEP_SCREEN_ON; 6254 } 6255 break; 6256 case R.styleable.View_filterTouchesWhenObscured: 6257 if (a.getBoolean(attr, false)) { 6258 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 6259 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 6260 } 6261 break; 6262 case R.styleable.View_nextFocusLeft: 6263 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 6264 break; 6265 case R.styleable.View_nextFocusRight: 6266 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 6267 break; 6268 case R.styleable.View_nextFocusUp: 6269 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 6270 break; 6271 case R.styleable.View_nextFocusDown: 6272 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 6273 break; 6274 case R.styleable.View_nextFocusForward: 6275 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 6276 break; 6277 case R.styleable.View_nextClusterForward: 6278 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 6279 break; 6280 case R.styleable.View_minWidth: 6281 mMinWidth = a.getDimensionPixelSize(attr, 0); 6282 break; 6283 case R.styleable.View_minHeight: 6284 mMinHeight = a.getDimensionPixelSize(attr, 0); 6285 break; 6286 case R.styleable.View_onClick: 6287 if (context.isRestricted()) { 6288 throw new IllegalStateException("The android:onClick attribute cannot " 6289 + "be used within a restricted context"); 6290 } 6291 6292 final String handlerName = a.getString(attr); 6293 if (handlerName != null) { 6294 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 6295 } 6296 break; 6297 case R.styleable.View_overScrollMode: 6298 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 6299 break; 6300 case R.styleable.View_verticalScrollbarPosition: 6301 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 6302 break; 6303 case R.styleable.View_layerType: 6304 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 6305 break; 6306 case R.styleable.View_textDirection: 6307 // Clear any text direction flag already set 6308 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 6309 // Set the text direction flags depending on the value of the attribute 6310 final int textDirection = a.getInt(attr, -1); 6311 if (textDirection != -1) { 6312 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 6313 } 6314 break; 6315 case R.styleable.View_textAlignment: 6316 // Clear any text alignment flag already set 6317 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 6318 // Set the text alignment flag depending on the value of the attribute 6319 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 6320 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 6321 break; 6322 case R.styleable.View_importantForAccessibility: 6323 setImportantForAccessibility(a.getInt(attr, 6324 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 6325 break; 6326 case R.styleable.View_accessibilityDataSensitive: 6327 setAccessibilityDataSensitive(a.getInt(attr, 6328 ACCESSIBILITY_DATA_SENSITIVE_AUTO)); 6329 break; 6330 case R.styleable.View_accessibilityLiveRegion: 6331 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 6332 break; 6333 case R.styleable.View_transitionName: 6334 setTransitionName(a.getString(attr)); 6335 break; 6336 case R.styleable.View_nestedScrollingEnabled: 6337 setNestedScrollingEnabled(a.getBoolean(attr, false)); 6338 break; 6339 case R.styleable.View_stateListAnimator: 6340 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 6341 a.getResourceId(attr, 0))); 6342 break; 6343 case R.styleable.View_backgroundTint: 6344 // This will get applied later during setBackground(). 6345 if (mBackgroundTint == null) { 6346 mBackgroundTint = new TintInfo(); 6347 } 6348 mBackgroundTint.mTintList = a.getColorStateList( 6349 R.styleable.View_backgroundTint); 6350 mBackgroundTint.mHasTintList = true; 6351 break; 6352 case R.styleable.View_backgroundTintMode: 6353 // This will get applied later during setBackground(). 6354 if (mBackgroundTint == null) { 6355 mBackgroundTint = new TintInfo(); 6356 } 6357 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 6358 R.styleable.View_backgroundTintMode, -1), null); 6359 mBackgroundTint.mHasTintMode = true; 6360 break; 6361 case R.styleable.View_outlineProvider: 6362 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 6363 PROVIDER_BACKGROUND)); 6364 break; 6365 case R.styleable.View_foreground: 6366 setForeground(a.getDrawable(attr)); 6367 break; 6368 case R.styleable.View_foregroundGravity: 6369 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 6370 break; 6371 case R.styleable.View_foregroundTintMode: 6372 setForegroundTintBlendMode( 6373 Drawable.parseBlendMode(a.getInt(attr, -1), 6374 null)); 6375 break; 6376 case R.styleable.View_foregroundTint: 6377 setForegroundTintList(a.getColorStateList(attr)); 6378 break; 6379 case R.styleable.View_foregroundInsidePadding: 6380 if (mForegroundInfo == null) { 6381 mForegroundInfo = new ForegroundInfo(); 6382 } 6383 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 6384 mForegroundInfo.mInsidePadding); 6385 break; 6386 case R.styleable.View_scrollIndicators: 6387 final int scrollIndicators = 6388 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 6389 & SCROLL_INDICATORS_PFLAG3_MASK; 6390 if (scrollIndicators != 0) { 6391 mPrivateFlags3 |= scrollIndicators; 6392 initializeScrollIndicators = true; 6393 } 6394 break; 6395 case R.styleable.View_pointerIcon: 6396 final int resourceId = a.getResourceId(attr, 0); 6397 if (resourceId != 0) { 6398 setPointerIcon(PointerIcon.load( 6399 context.getResources(), resourceId)); 6400 } else { 6401 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 6402 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 6403 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 6404 } 6405 } 6406 break; 6407 case R.styleable.View_forceHasOverlappingRendering: 6408 if (a.peekValue(attr) != null) { 6409 forceHasOverlappingRendering(a.getBoolean(attr, true)); 6410 } 6411 break; 6412 case R.styleable.View_tooltipText: 6413 setTooltipText(a.getText(attr)); 6414 break; 6415 case R.styleable.View_keyboardNavigationCluster: 6416 if (a.peekValue(attr) != null) { 6417 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 6418 } 6419 break; 6420 case R.styleable.View_focusedByDefault: 6421 if (a.peekValue(attr) != null) { 6422 setFocusedByDefault(a.getBoolean(attr, true)); 6423 } 6424 break; 6425 case R.styleable.View_autofillHints: 6426 if (a.peekValue(attr) != null) { 6427 CharSequence[] rawHints = null; 6428 String rawString = null; 6429 6430 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 6431 int resId = a.getResourceId(attr, 0); 6432 6433 try { 6434 rawHints = a.getTextArray(attr); 6435 } catch (Resources.NotFoundException e) { 6436 rawString = getResources().getString(resId); 6437 } 6438 } else { 6439 rawString = a.getString(attr); 6440 } 6441 6442 if (rawHints == null) { 6443 if (rawString == null) { 6444 throw new IllegalArgumentException( 6445 "Could not resolve autofillHints"); 6446 } else { 6447 rawHints = rawString.split(","); 6448 } 6449 } 6450 6451 String[] hints = new String[rawHints.length]; 6452 6453 int numHints = rawHints.length; 6454 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 6455 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 6456 } 6457 setAutofillHints(hints); 6458 } 6459 break; 6460 case R.styleable.View_importantForAutofill: 6461 if (a.peekValue(attr) != null) { 6462 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 6463 } 6464 break; 6465 case R.styleable.View_importantForContentCapture: 6466 if (a.peekValue(attr) != null) { 6467 setImportantForContentCapture(a.getInt(attr, 6468 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 6469 } 6470 break; 6471 case R.styleable.View_isCredential: 6472 if (a.peekValue(attr) != null) { 6473 setIsCredential(a.getBoolean(attr, false)); 6474 } 6475 break; 6476 case R.styleable.View_defaultFocusHighlightEnabled: 6477 if (a.peekValue(attr) != null) { 6478 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 6479 } 6480 break; 6481 case R.styleable.View_screenReaderFocusable: 6482 if (a.peekValue(attr) != null) { 6483 setScreenReaderFocusable(a.getBoolean(attr, false)); 6484 } 6485 break; 6486 case R.styleable.View_accessibilityPaneTitle: 6487 if (a.peekValue(attr) != null) { 6488 setAccessibilityPaneTitle(a.getString(attr)); 6489 } 6490 break; 6491 case R.styleable.View_outlineSpotShadowColor: 6492 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6493 break; 6494 case R.styleable.View_outlineAmbientShadowColor: 6495 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6496 break; 6497 case com.android.internal.R.styleable.View_accessibilityHeading: 6498 setAccessibilityHeading(a.getBoolean(attr, false)); 6499 break; 6500 case R.styleable.View_forceDarkAllowed: 6501 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6502 break; 6503 case R.styleable.View_scrollCaptureHint: 6504 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6505 break; 6506 case R.styleable.View_clipToOutline: 6507 setClipToOutline(a.getBoolean(attr, false)); 6508 break; 6509 case R.styleable.View_preferKeepClear: 6510 setPreferKeepClear(a.getBoolean(attr, false)); 6511 break; 6512 case R.styleable.View_autoHandwritingEnabled: 6513 setAutoHandwritingEnabled(a.getBoolean(attr, false)); 6514 break; 6515 case R.styleable.View_handwritingBoundsOffsetLeft: 6516 mHandwritingBoundsOffsetLeft = a.getDimension(attr, 0); 6517 break; 6518 case R.styleable.View_handwritingBoundsOffsetTop: 6519 mHandwritingBoundsOffsetTop = a.getDimension(attr, 0); 6520 break; 6521 case R.styleable.View_handwritingBoundsOffsetRight: 6522 mHandwritingBoundsOffsetRight = a.getDimension(attr, 0); 6523 break; 6524 case R.styleable.View_handwritingBoundsOffsetBottom: 6525 mHandwritingBoundsOffsetBottom = a.getDimension(attr, 0); 6526 break; 6527 case R.styleable.View_contentSensitivity: 6528 setContentSensitivity(a.getInt(attr, CONTENT_SENSITIVITY_AUTO)); 6529 break; 6530 } 6531 } 6532 6533 setOverScrollMode(overScrollMode); 6534 6535 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6536 // the resolved layout direction). Those cached values will be used later during padding 6537 // resolution. 6538 mUserPaddingStart = startPadding; 6539 mUserPaddingEnd = endPadding; 6540 6541 if (background != null) { 6542 setBackground(background); 6543 } 6544 6545 // setBackground above will record that padding is currently provided by the background. 6546 // If we have padding specified via xml, record that here instead and use it. 6547 mLeftPaddingDefined = leftPaddingDefined; 6548 mRightPaddingDefined = rightPaddingDefined; 6549 6550 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6551 // bottomPadding, and padding set by background. Valid padding beats everything. 6552 if (padding >= 0) { 6553 leftPadding = padding; 6554 topPadding = padding; 6555 rightPadding = padding; 6556 bottomPadding = padding; 6557 mUserPaddingLeftInitial = padding; 6558 mUserPaddingRightInitial = padding; 6559 } else { 6560 if (paddingHorizontal >= 0) { 6561 leftPadding = paddingHorizontal; 6562 rightPadding = paddingHorizontal; 6563 mUserPaddingLeftInitial = paddingHorizontal; 6564 mUserPaddingRightInitial = paddingHorizontal; 6565 } 6566 if (paddingVertical >= 0) { 6567 topPadding = paddingVertical; 6568 bottomPadding = paddingVertical; 6569 } 6570 } 6571 6572 if (isRtlCompatibilityMode()) { 6573 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6574 // left / right padding are used if defined (meaning here nothing to do). If they are not 6575 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6576 // start / end and resolve them as left / right (layout direction is not taken into account). 6577 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6578 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6579 // defined. 6580 if (!mLeftPaddingDefined && startPaddingDefined) { 6581 leftPadding = startPadding; 6582 } 6583 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6584 if (!mRightPaddingDefined && endPaddingDefined) { 6585 rightPadding = endPadding; 6586 } 6587 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6588 } else { 6589 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6590 // values defined. Otherwise, left /right values are used. 6591 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6592 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6593 // defined. 6594 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6595 6596 if (mLeftPaddingDefined && !hasRelativePadding) { 6597 mUserPaddingLeftInitial = leftPadding; 6598 } 6599 if (mRightPaddingDefined && !hasRelativePadding) { 6600 mUserPaddingRightInitial = rightPadding; 6601 } 6602 } 6603 6604 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6605 // them on if topPadding or bottomPadding are not valid. 6606 internalSetPadding( 6607 mUserPaddingLeftInitial, 6608 topPadding >= 0 ? topPadding : mPaddingTop, 6609 mUserPaddingRightInitial, 6610 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6611 6612 if (viewFlagMasks != 0) { 6613 setFlags(viewFlagValues, viewFlagMasks); 6614 } 6615 6616 if (initializeScrollbars) { 6617 initializeScrollbarsInternal(a); 6618 } 6619 6620 if (initializeScrollIndicators) { 6621 initializeScrollIndicatorsInternal(); 6622 } 6623 6624 a.recycle(); 6625 6626 // Needs to be called after mViewFlags is set 6627 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6628 recomputePadding(); 6629 } 6630 6631 if (x != 0 || y != 0) { 6632 scrollTo(x, y); 6633 } 6634 6635 if (transformSet) { 6636 setTranslationX(tx); 6637 setTranslationY(ty); 6638 setTranslationZ(tz); 6639 setElevation(elevation); 6640 setRotation(rotation); 6641 setRotationX(rotationX); 6642 setRotationY(rotationY); 6643 setScaleX(sx); 6644 setScaleY(sy); 6645 } 6646 6647 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6648 setScrollContainer(true); 6649 } 6650 6651 computeOpaqueFlags(); 6652 } 6653 6654 /** 6655 * Returns the ordered list of resource ID that are considered when resolving attribute values 6656 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6657 * XML. It will also include a set of explicit styles if specified in XML using 6658 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6659 * 6660 * <p> 6661 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6662 * is enabled in Android developer options. 6663 * 6664 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6665 * @return ordered list of resource ID that are considered when resolving attribute values for 6666 * this {@link View}. 6667 */ 6668 @NonNull 6669 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6670 if (!sDebugViewAttributes 6671 || mAttributeResolutionStacks == null 6672 || mAttributeResolutionStacks.get(attribute) == null) { 6673 return new int[0]; 6674 } 6675 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6676 int stackSize = attributeResolutionStack.length; 6677 if (mSourceLayoutId != ID_NULL) { 6678 stackSize++; 6679 } 6680 6681 int currentIndex = 0; 6682 int[] stack = new int[stackSize]; 6683 6684 if (mSourceLayoutId != ID_NULL) { 6685 stack[currentIndex] = mSourceLayoutId; 6686 currentIndex++; 6687 } 6688 for (int i = 0; i < attributeResolutionStack.length; i++) { 6689 stack[currentIndex] = attributeResolutionStack[i]; 6690 currentIndex++; 6691 } 6692 return stack; 6693 } 6694 6695 /** 6696 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6697 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6698 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6699 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6700 * 6701 * <p> 6702 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6703 * is enabled in Android developer options. 6704 * 6705 * @return mapping of attribute resource ID to source resource ID where the attribute value 6706 * was set. 6707 */ 6708 @NonNull 6709 @SuppressWarnings("AndroidFrameworkEfficientCollections") 6710 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6711 HashMap<Integer, Integer> map = new HashMap<>(); 6712 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6713 return map; 6714 } 6715 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6716 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6717 } 6718 return map; 6719 } 6720 6721 /** 6722 * Returns the resource ID for the style specified using {@code style="..."} in the 6723 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6724 * specified or otherwise not applicable. 6725 * <p> 6726 * Each {@link View} can have an explicit style specified in the layout file. 6727 * This style is used first during the {@link View} attribute resolution, then if an attribute 6728 * is not defined there the resource system looks at default style and theme as fallbacks. 6729 * 6730 * <p> 6731 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6732 * is enabled in Android developer options. 6733 * 6734 * @return The resource ID for the style specified using {@code style="..."} in the 6735 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6736 * if not specified or otherwise not applicable. 6737 */ 6738 @StyleRes 6739 public int getExplicitStyle() { 6740 if (!sDebugViewAttributes) { 6741 return ID_NULL; 6742 } 6743 return mExplicitStyle; 6744 } 6745 6746 /** 6747 * An implementation of OnClickListener that attempts to lazily load a 6748 * named click handling method from a parent or ancestor context. 6749 */ 6750 private static class DeclaredOnClickListener implements OnClickListener { 6751 private final View mHostView; 6752 private final String mMethodName; 6753 6754 private Method mResolvedMethod; 6755 private Context mResolvedContext; 6756 6757 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6758 mHostView = hostView; 6759 mMethodName = methodName; 6760 } 6761 6762 @Override 6763 public void onClick(@NonNull View v) { 6764 if (mResolvedMethod == null) { 6765 resolveMethod(mHostView.getContext(), mMethodName); 6766 } 6767 6768 try { 6769 mResolvedMethod.invoke(mResolvedContext, v); 6770 } catch (IllegalAccessException e) { 6771 throw new IllegalStateException( 6772 "Could not execute non-public method for android:onClick", e); 6773 } catch (InvocationTargetException e) { 6774 throw new IllegalStateException( 6775 "Could not execute method for android:onClick", e); 6776 } 6777 } 6778 6779 @NonNull 6780 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6781 while (context != null) { 6782 try { 6783 if (!context.isRestricted()) { 6784 final Method method = context.getClass().getMethod(mMethodName, View.class); 6785 if (method != null) { 6786 mResolvedMethod = method; 6787 mResolvedContext = context; 6788 return; 6789 } 6790 } 6791 } catch (NoSuchMethodException e) { 6792 // Failed to find method, keep searching up the hierarchy. 6793 } 6794 6795 if (context instanceof ContextWrapper) { 6796 context = ((ContextWrapper) context).getBaseContext(); 6797 } else { 6798 // Can't search up the hierarchy, null out and fail. 6799 context = null; 6800 } 6801 } 6802 6803 final int id = mHostView.getId(); 6804 final String idText = id == NO_ID ? "" : " with id '" 6805 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6806 throw new IllegalStateException("Could not find method " + mMethodName 6807 + "(View) in a parent or ancestor Context for android:onClick " 6808 + "attribute defined on view " + mHostView.getClass() + idText); 6809 } 6810 } 6811 6812 /** 6813 * Non-public constructor for use in testing 6814 */ 6815 @UnsupportedAppUsage 6816 View() { 6817 mResources = null; 6818 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6819 } 6820 6821 /** 6822 * Returns {@code true} when the View is attached and the system developer setting to show 6823 * the layout bounds is enabled or {@code false} otherwise. 6824 */ 6825 public final boolean isShowingLayoutBounds() { 6826 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6827 } 6828 6829 /** 6830 * Used to test isShowingLayoutBounds(). This sets the local value used 6831 * by that function. This method does nothing if the layout isn't attached. 6832 * 6833 * @hide 6834 */ 6835 @TestApi 6836 public final void setShowingLayoutBounds(boolean debugLayout) { 6837 if (mAttachInfo != null) { 6838 mAttachInfo.mDebugLayout = debugLayout; 6839 } 6840 } 6841 6842 private static SparseArray<String> getAttributeMap() { 6843 if (mAttributeMap == null) { 6844 mAttributeMap = new SparseArray<>(); 6845 } 6846 return mAttributeMap; 6847 } 6848 6849 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6850 @Nullable AttributeSet attrs) { 6851 if (!sDebugViewAttributes) { 6852 return; 6853 } 6854 mExplicitStyle = theme.getExplicitStyle(attrs); 6855 } 6856 6857 /** 6858 * Stores debugging information about attributes. This should be called in a constructor by 6859 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6860 * then the custom attributes used by this view will not be visible in layout inspection tools. 6861 * 6862 * @param context Context under which this view is created. 6863 * @param styleable A reference to styleable array R.styleable.Foo 6864 * @param attrs AttributeSet used to construct this view. 6865 * @param t Resolved {@link TypedArray} returned by a call to 6866 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6867 * @param defStyleAttr Default style attribute passed into the view constructor. 6868 * @param defStyleRes Default style resource passed into the view constructor. 6869 */ 6870 public final void saveAttributeDataForStyleable(@NonNull Context context, 6871 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6872 int defStyleAttr, int defStyleRes) { 6873 if (!sDebugViewAttributes) { 6874 return; 6875 } 6876 6877 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6878 defStyleAttr, defStyleRes, mExplicitStyle); 6879 6880 if (mAttributeResolutionStacks == null) { 6881 mAttributeResolutionStacks = new SparseArray<>(); 6882 } 6883 6884 if (mAttributeSourceResId == null) { 6885 mAttributeSourceResId = new SparseIntArray(); 6886 } 6887 6888 final int indexCount = t.getIndexCount(); 6889 for (int j = 0; j < indexCount; ++j) { 6890 final int index = t.getIndex(j); 6891 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6892 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6893 } 6894 } 6895 6896 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6897 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6898 final int indexCount = t.getIndexCount(); 6899 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6900 6901 int i = 0; 6902 6903 // Store raw XML attributes. 6904 for (int j = 0; j < attrsCount; ++j) { 6905 attributes[i] = attrs.getAttributeName(j); 6906 attributes[i + 1] = attrs.getAttributeValue(j); 6907 i += 2; 6908 } 6909 6910 // Store resolved styleable attributes. 6911 final Resources res = t.getResources(); 6912 final SparseArray<String> attributeMap = getAttributeMap(); 6913 for (int j = 0; j < indexCount; ++j) { 6914 final int index = t.getIndex(j); 6915 if (!t.hasValueOrEmpty(index)) { 6916 // Value is undefined. Skip it. 6917 continue; 6918 } 6919 6920 final int resourceId = t.getResourceId(index, 0); 6921 if (resourceId == 0) { 6922 // Value is not a reference. Skip it. 6923 continue; 6924 } 6925 6926 String resourceName = attributeMap.get(resourceId); 6927 if (resourceName == null) { 6928 try { 6929 resourceName = res.getResourceName(resourceId); 6930 } catch (Resources.NotFoundException e) { 6931 resourceName = "0x" + Integer.toHexString(resourceId); 6932 } 6933 attributeMap.put(resourceId, resourceName); 6934 } 6935 6936 attributes[i] = resourceName; 6937 attributes[i + 1] = t.getString(index); 6938 i += 2; 6939 } 6940 6941 // Trim to fit contents. 6942 final String[] trimmed = new String[i]; 6943 System.arraycopy(attributes, 0, trimmed, 0, i); 6944 mAttributes = trimmed; 6945 } 6946 6947 @Override 6948 public String toString() { 6949 StringBuilder out = new StringBuilder(256); 6950 out.append(getClass().getName()); 6951 out.append('{'); 6952 out.append(Integer.toHexString(System.identityHashCode(this))); 6953 out.append(' '); 6954 switch (mViewFlags&VISIBILITY_MASK) { 6955 case VISIBLE: out.append('V'); break; 6956 case INVISIBLE: out.append('I'); break; 6957 case GONE: out.append('G'); break; 6958 default: out.append('.'); break; 6959 } 6960 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6961 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6962 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6963 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6964 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6965 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6966 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6967 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6968 out.append(' '); 6969 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6970 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6971 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6972 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6973 out.append('p'); 6974 } else { 6975 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6976 } 6977 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6978 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6979 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6980 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6981 out.append(' '); 6982 out.append(mLeft); 6983 out.append(','); 6984 out.append(mTop); 6985 out.append('-'); 6986 out.append(mRight); 6987 out.append(','); 6988 out.append(mBottom); 6989 appendId(out); 6990 if (mAutofillId != null) { 6991 out.append(" aid="); out.append(mAutofillId); 6992 } 6993 out.append("}"); 6994 return out.toString(); 6995 } 6996 6997 void appendId(StringBuilder out) { 6998 final int id = getId(); 6999 if (id != NO_ID) { 7000 out.append(" #"); 7001 out.append(Integer.toHexString(id)); 7002 final Resources r = mResources; 7003 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 7004 try { 7005 String pkgname; 7006 switch (id&0xff000000) { 7007 case 0x7f000000: 7008 pkgname="app"; 7009 break; 7010 case 0x01000000: 7011 pkgname="android"; 7012 break; 7013 default: 7014 pkgname = r.getResourcePackageName(id); 7015 break; 7016 } 7017 String typename = r.getResourceTypeName(id); 7018 String entryname = r.getResourceEntryName(id); 7019 out.append(" "); 7020 out.append(pkgname); 7021 out.append(":"); 7022 out.append(typename); 7023 out.append("/"); 7024 out.append(entryname); 7025 } catch (Resources.NotFoundException e) { 7026 } 7027 } 7028 } 7029 } 7030 7031 /** 7032 * <p> 7033 * Initializes the fading edges from a given set of styled attributes. This 7034 * method should be called by subclasses that need fading edges and when an 7035 * instance of these subclasses is created programmatically rather than 7036 * being inflated from XML. This method is automatically called when the XML 7037 * is inflated. 7038 * </p> 7039 * 7040 * @param a the styled attributes set to initialize the fading edges from 7041 * 7042 * @removed 7043 */ 7044 protected void initializeFadingEdge(TypedArray a) { 7045 // This method probably shouldn't have been included in the SDK to begin with. 7046 // It relies on 'a' having been initialized using an attribute filter array that is 7047 // not publicly available to the SDK. The old method has been renamed 7048 // to initializeFadingEdgeInternal and hidden for framework use only; 7049 // this one initializes using defaults to make it safe to call for apps. 7050 7051 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 7052 7053 initializeFadingEdgeInternal(arr); 7054 7055 arr.recycle(); 7056 } 7057 7058 /** 7059 * <p> 7060 * Initializes the fading edges from a given set of styled attributes. This 7061 * method should be called by subclasses that need fading edges and when an 7062 * instance of these subclasses is created programmatically rather than 7063 * being inflated from XML. This method is automatically called when the XML 7064 * is inflated. 7065 * </p> 7066 * 7067 * @param a the styled attributes set to initialize the fading edges from 7068 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 7069 */ 7070 protected void initializeFadingEdgeInternal(TypedArray a) { 7071 initScrollCache(); 7072 7073 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 7074 R.styleable.View_fadingEdgeLength, 7075 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 7076 } 7077 7078 /** 7079 * Returns the size of the vertical faded edges used to indicate that more 7080 * content in this view is visible. 7081 * 7082 * @return The size in pixels of the vertical faded edge or 0 if vertical 7083 * faded edges are not enabled for this view. 7084 * @attr ref android.R.styleable#View_fadingEdgeLength 7085 */ 7086 public int getVerticalFadingEdgeLength() { 7087 if (isVerticalFadingEdgeEnabled()) { 7088 ScrollabilityCache cache = mScrollCache; 7089 if (cache != null) { 7090 return cache.fadingEdgeLength; 7091 } 7092 } 7093 return 0; 7094 } 7095 7096 /** 7097 * Set the size of the faded edge used to indicate that more content in this 7098 * view is available. Will not change whether the fading edge is enabled; use 7099 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 7100 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 7101 * for the vertical or horizontal fading edges. 7102 * 7103 * @param length The size in pixels of the faded edge used to indicate that more 7104 * content in this view is visible. 7105 */ 7106 public void setFadingEdgeLength(int length) { 7107 initScrollCache(); 7108 mScrollCache.fadingEdgeLength = length; 7109 } 7110 7111 /** 7112 * Clears the request and callback previously set 7113 * through {@link View#setPendingCredentialRequest}. 7114 * Once this API is invoked, there will be no request fired to {@link CredentialManager} 7115 * on future view focus events. 7116 * 7117 * @see #setPendingCredentialRequest 7118 */ 7119 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 7120 public void clearPendingCredentialRequest() { 7121 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 7122 Log.v(AUTOFILL_LOG_TAG, "clearPendingCredentialRequest called"); 7123 } 7124 mViewCredentialHandler = null; 7125 } 7126 7127 /** 7128 * Sets a {@link CredentialManager} request to retrieve credentials, when the user focuses 7129 * on this given view. 7130 * 7131 * When this view is focused, the given {@code request} will be fired to 7132 * {@link CredentialManager}, which will fetch content from all 7133 * {@link android.service.credentials.CredentialProviderService} services on the 7134 * device, and then display credential options to the user on a relevant UI 7135 * (dropdown, keyboard suggestions etc.). 7136 * 7137 * When the user selects a credential, the final {@link GetCredentialResponse} will be 7138 * propagated to the given {@code callback}. Developers are expected to handle the response 7139 * programmatically and perform a relevant action, e.g. signing in the user. 7140 * 7141 * <p> For details on how to build a Credential Manager request, please see 7142 * {@link GetCredentialRequest}. 7143 * 7144 * <p> This API should be called at any point before the user focuses on the view, e.g. during 7145 * {@code onCreate} of an Activity. 7146 * 7147 * @param request the request to be fired when this view is entered 7148 * @param callback to be invoked when either a response or an exception needs to be 7149 * propagated for the given view 7150 */ 7151 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 7152 public void setPendingCredentialRequest(@NonNull GetCredentialRequest request, 7153 @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { 7154 Preconditions.checkNotNull(request, "request must not be null"); 7155 Preconditions.checkNotNull(callback, "callback must not be null"); 7156 7157 for (CredentialOption option : request.getCredentialOptions()) { 7158 ArrayList<AutofillId> ids = option.getCandidateQueryData() 7159 .getParcelableArrayList( 7160 CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); 7161 ids = ids != null ? ids : new ArrayList<>(); 7162 if (!ids.contains(getAutofillId())) { 7163 ids.add(getAutofillId()); 7164 } 7165 option.getCandidateQueryData() 7166 .putParcelableArrayList(CredentialProviderService.EXTRA_AUTOFILL_ID, ids); 7167 } 7168 mViewCredentialHandler = new ViewCredentialHandler(request, callback); 7169 } 7170 7171 /** 7172 * 7173 * @hide 7174 */ 7175 @Nullable 7176 public ViewCredentialHandler getViewCredentialHandler() { 7177 return mViewCredentialHandler; 7178 } 7179 7180 /** 7181 * Returns the size of the horizontal faded edges used to indicate that more 7182 * content in this view is visible. 7183 * 7184 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 7185 * faded edges are not enabled for this view. 7186 * @attr ref android.R.styleable#View_fadingEdgeLength 7187 */ 7188 public int getHorizontalFadingEdgeLength() { 7189 if (isHorizontalFadingEdgeEnabled()) { 7190 ScrollabilityCache cache = mScrollCache; 7191 if (cache != null) { 7192 return cache.fadingEdgeLength; 7193 } 7194 } 7195 return 0; 7196 } 7197 7198 /** 7199 * Returns the width of the vertical scrollbar. 7200 * 7201 * @return The width in pixels of the vertical scrollbar or 0 if there 7202 * is no vertical scrollbar. 7203 */ 7204 public int getVerticalScrollbarWidth() { 7205 ScrollabilityCache cache = mScrollCache; 7206 if (cache != null) { 7207 ScrollBarDrawable scrollBar = cache.scrollBar; 7208 if (scrollBar != null) { 7209 int size = scrollBar.getSize(true); 7210 if (size <= 0) { 7211 size = cache.scrollBarSize; 7212 } 7213 return size; 7214 } 7215 return 0; 7216 } 7217 return 0; 7218 } 7219 7220 /** 7221 * Returns the height of the horizontal scrollbar. 7222 * 7223 * @return The height in pixels of the horizontal scrollbar or 0 if 7224 * there is no horizontal scrollbar. 7225 */ 7226 protected int getHorizontalScrollbarHeight() { 7227 ScrollabilityCache cache = mScrollCache; 7228 if (cache != null) { 7229 ScrollBarDrawable scrollBar = cache.scrollBar; 7230 if (scrollBar != null) { 7231 int size = scrollBar.getSize(false); 7232 if (size <= 0) { 7233 size = cache.scrollBarSize; 7234 } 7235 return size; 7236 } 7237 return 0; 7238 } 7239 return 0; 7240 } 7241 7242 /** 7243 * <p> 7244 * Initializes the scrollbars from a given set of styled attributes. This 7245 * method should be called by subclasses that need scrollbars and when an 7246 * instance of these subclasses is created programmatically rather than 7247 * being inflated from XML. This method is automatically called when the XML 7248 * is inflated. 7249 * </p> 7250 * 7251 * @param a the styled attributes set to initialize the scrollbars from 7252 * 7253 * @removed 7254 */ 7255 protected void initializeScrollbars(TypedArray a) { 7256 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 7257 // using the View filter array which is not available to the SDK. As such, internal 7258 // framework usage now uses initializeScrollbarsInternal and we grab a default 7259 // TypedArray with the right filter instead here. 7260 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 7261 7262 initializeScrollbarsInternal(arr); 7263 7264 // We ignored the method parameter. Recycle the one we actually did use. 7265 arr.recycle(); 7266 } 7267 7268 private void initializeScrollBarDrawable() { 7269 initScrollCache(); 7270 7271 if (mScrollCache.scrollBar == null) { 7272 mScrollCache.scrollBar = new ScrollBarDrawable(); 7273 mScrollCache.scrollBar.setState(getDrawableState()); 7274 mScrollCache.scrollBar.setCallback(this); 7275 } 7276 } 7277 7278 /** 7279 * <p> 7280 * Initializes the scrollbars from a given set of styled attributes. This 7281 * method should be called by subclasses that need scrollbars and when an 7282 * instance of these subclasses is created programmatically rather than 7283 * being inflated from XML. This method is automatically called when the XML 7284 * is inflated. 7285 * </p> 7286 * 7287 * @param a the styled attributes set to initialize the scrollbars from 7288 * @hide 7289 */ 7290 @UnsupportedAppUsage 7291 protected void initializeScrollbarsInternal(TypedArray a) { 7292 initScrollCache(); 7293 7294 final ScrollabilityCache scrollabilityCache = mScrollCache; 7295 7296 if (scrollabilityCache.scrollBar == null) { 7297 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 7298 scrollabilityCache.scrollBar.setState(getDrawableState()); 7299 scrollabilityCache.scrollBar.setCallback(this); 7300 } 7301 7302 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 7303 7304 if (!fadeScrollbars) { 7305 scrollabilityCache.state = ScrollabilityCache.ON; 7306 } 7307 scrollabilityCache.fadeScrollBars = fadeScrollbars; 7308 7309 7310 scrollabilityCache.scrollBarFadeDuration = a.getInt( 7311 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 7312 .getScrollBarFadeDuration()); 7313 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 7314 R.styleable.View_scrollbarDefaultDelayBeforeFade, 7315 ViewConfiguration.getScrollDefaultDelay()); 7316 7317 7318 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 7319 com.android.internal.R.styleable.View_scrollbarSize, 7320 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 7321 7322 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 7323 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 7324 7325 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 7326 if (thumb != null) { 7327 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 7328 } 7329 7330 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 7331 false); 7332 if (alwaysDraw) { 7333 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 7334 } 7335 7336 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 7337 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 7338 7339 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 7340 if (thumb != null) { 7341 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 7342 } 7343 7344 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 7345 false); 7346 if (alwaysDraw) { 7347 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 7348 } 7349 7350 // Apply layout direction to the new Drawables if needed 7351 final int layoutDirection = getLayoutDirection(); 7352 if (track != null) { 7353 track.setLayoutDirection(layoutDirection); 7354 } 7355 if (thumb != null) { 7356 thumb.setLayoutDirection(layoutDirection); 7357 } 7358 7359 // Re-apply user/background padding so that scrollbar(s) get added 7360 resolvePadding(); 7361 } 7362 7363 /** 7364 * Defines the vertical scrollbar thumb drawable 7365 * @attr ref android.R.styleable#View_scrollbarThumbVertical 7366 * 7367 * @see #awakenScrollBars(int) 7368 * @see #isVerticalScrollBarEnabled() 7369 * @see #setVerticalScrollBarEnabled(boolean) 7370 */ 7371 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 7372 initializeScrollBarDrawable(); 7373 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 7374 } 7375 7376 /** 7377 * Defines the vertical scrollbar track drawable 7378 * @attr ref android.R.styleable#View_scrollbarTrackVertical 7379 * 7380 * @see #awakenScrollBars(int) 7381 * @see #isVerticalScrollBarEnabled() 7382 * @see #setVerticalScrollBarEnabled(boolean) 7383 */ 7384 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 7385 initializeScrollBarDrawable(); 7386 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 7387 } 7388 7389 /** 7390 * Defines the horizontal thumb drawable 7391 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 7392 * 7393 * @see #awakenScrollBars(int) 7394 * @see #isHorizontalScrollBarEnabled() 7395 * @see #setHorizontalScrollBarEnabled(boolean) 7396 */ 7397 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 7398 initializeScrollBarDrawable(); 7399 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 7400 } 7401 7402 /** 7403 * Defines the horizontal track drawable 7404 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 7405 * 7406 * @see #awakenScrollBars(int) 7407 * @see #isHorizontalScrollBarEnabled() 7408 * @see #setHorizontalScrollBarEnabled(boolean) 7409 */ 7410 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 7411 initializeScrollBarDrawable(); 7412 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 7413 } 7414 7415 /** 7416 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 7417 * exists, null otherwise. 7418 * 7419 * @see #awakenScrollBars(int) 7420 * @see #isVerticalScrollBarEnabled() 7421 * @see #setVerticalScrollBarEnabled(boolean) 7422 */ 7423 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 7424 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 7425 } 7426 7427 /** 7428 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 7429 * exists, null otherwise. 7430 * 7431 * @see #awakenScrollBars(int) 7432 * @see #isVerticalScrollBarEnabled() 7433 * @see #setVerticalScrollBarEnabled(boolean) 7434 */ 7435 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 7436 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 7437 } 7438 7439 /** 7440 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 7441 * exists, null otherwise. 7442 * 7443 * @see #awakenScrollBars(int) 7444 * @see #isHorizontalScrollBarEnabled() 7445 * @see #setHorizontalScrollBarEnabled(boolean) 7446 */ 7447 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 7448 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 7449 } 7450 7451 /** 7452 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 7453 * exists, null otherwise. 7454 * 7455 * @see #awakenScrollBars(int) 7456 * @see #isHorizontalScrollBarEnabled() 7457 * @see #setHorizontalScrollBarEnabled(boolean) 7458 */ 7459 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 7460 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 7461 } 7462 7463 private void initializeScrollIndicatorsInternal() { 7464 // Some day maybe we'll break this into top/left/start/etc. and let the 7465 // client control it. Until then, you can have any scroll indicator you 7466 // want as long as it's a 1dp foreground-colored rectangle. 7467 if (mScrollIndicatorDrawable == null) { 7468 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 7469 } 7470 } 7471 7472 /** 7473 * <p> 7474 * Initalizes the scrollability cache if necessary. 7475 * </p> 7476 */ 7477 private void initScrollCache() { 7478 if (mScrollCache == null) { 7479 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 7480 } 7481 } 7482 7483 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 7484 private ScrollabilityCache getScrollCache() { 7485 initScrollCache(); 7486 return mScrollCache; 7487 } 7488 7489 /** 7490 * Set the position of the vertical scroll bar. Should be one of 7491 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 7492 * {@link #SCROLLBAR_POSITION_RIGHT}. 7493 * 7494 * @param position Where the vertical scroll bar should be positioned. 7495 */ 7496 public void setVerticalScrollbarPosition(int position) { 7497 if (mVerticalScrollbarPosition != position) { 7498 mVerticalScrollbarPosition = position; 7499 computeOpaqueFlags(); 7500 resolvePadding(); 7501 } 7502 } 7503 7504 /** 7505 * @return The position where the vertical scroll bar will show, if applicable. 7506 * @see #setVerticalScrollbarPosition(int) 7507 */ 7508 public int getVerticalScrollbarPosition() { 7509 return mVerticalScrollbarPosition; 7510 } 7511 7512 boolean isOnScrollbar(float x, float y) { 7513 if (mScrollCache == null) { 7514 return false; 7515 } 7516 x += getScrollX(); 7517 y += getScrollY(); 7518 final boolean canScrollVertically = 7519 computeVerticalScrollRange() > computeVerticalScrollExtent(); 7520 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 7521 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7522 getVerticalScrollBarBounds(null, touchBounds); 7523 if (touchBounds.contains((int) x, (int) y)) { 7524 return true; 7525 } 7526 } 7527 final boolean canScrollHorizontally = 7528 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 7529 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 7530 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7531 getHorizontalScrollBarBounds(null, touchBounds); 7532 if (touchBounds.contains((int) x, (int) y)) { 7533 return true; 7534 } 7535 } 7536 return false; 7537 } 7538 7539 @UnsupportedAppUsage 7540 boolean isOnScrollbarThumb(float x, float y) { 7541 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 7542 } 7543 7544 private boolean isOnVerticalScrollbarThumb(float x, float y) { 7545 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 7546 return false; 7547 } 7548 final int range = computeVerticalScrollRange(); 7549 final int extent = computeVerticalScrollExtent(); 7550 if (range > extent) { 7551 x += getScrollX(); 7552 y += getScrollY(); 7553 final Rect bounds = mScrollCache.mScrollBarBounds; 7554 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7555 getVerticalScrollBarBounds(bounds, touchBounds); 7556 final int offset = computeVerticalScrollOffset(); 7557 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 7558 extent, range); 7559 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 7560 extent, range, offset); 7561 final int thumbTop = bounds.top + thumbOffset; 7562 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7563 if (x >= touchBounds.left && x <= touchBounds.right 7564 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 7565 return true; 7566 } 7567 } 7568 return false; 7569 } 7570 7571 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 7572 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 7573 return false; 7574 } 7575 final int range = computeHorizontalScrollRange(); 7576 final int extent = computeHorizontalScrollExtent(); 7577 if (range > extent) { 7578 x += getScrollX(); 7579 y += getScrollY(); 7580 final Rect bounds = mScrollCache.mScrollBarBounds; 7581 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7582 getHorizontalScrollBarBounds(bounds, touchBounds); 7583 final int offset = computeHorizontalScrollOffset(); 7584 7585 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 7586 extent, range); 7587 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7588 extent, range, offset); 7589 final int thumbLeft = bounds.left + thumbOffset; 7590 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7591 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7592 && y >= touchBounds.top && y <= touchBounds.bottom) { 7593 return true; 7594 } 7595 } 7596 return false; 7597 } 7598 7599 @UnsupportedAppUsage 7600 boolean isDraggingScrollBar() { 7601 return mScrollCache != null 7602 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7603 } 7604 7605 /** 7606 * Sets the state of all scroll indicators. 7607 * <p> 7608 * See {@link #setScrollIndicators(int, int)} for usage information. 7609 * 7610 * @param indicators a bitmask of indicators that should be enabled, or 7611 * {@code 0} to disable all indicators 7612 * @see #setScrollIndicators(int, int) 7613 * @see #getScrollIndicators() 7614 * @attr ref android.R.styleable#View_scrollIndicators 7615 */ 7616 @RemotableViewMethod 7617 public void setScrollIndicators(@ScrollIndicators int indicators) { 7618 setScrollIndicators(indicators, 7619 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7620 } 7621 7622 /** 7623 * Sets the state of the scroll indicators specified by the mask. To change 7624 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7625 * <p> 7626 * When a scroll indicator is enabled, it will be displayed if the view 7627 * can scroll in the direction of the indicator. 7628 * <p> 7629 * Multiple indicator types may be enabled or disabled by passing the 7630 * logical OR of the desired types. If multiple types are specified, they 7631 * will all be set to the same enabled state. 7632 * <p> 7633 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7634 * 7635 * @param indicators the indicator direction, or the logical OR of multiple 7636 * indicator directions. One or more of: 7637 * <ul> 7638 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7639 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7640 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7641 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7642 * <li>{@link #SCROLL_INDICATOR_START}</li> 7643 * <li>{@link #SCROLL_INDICATOR_END}</li> 7644 * </ul> 7645 * @see #setScrollIndicators(int) 7646 * @see #getScrollIndicators() 7647 * @attr ref android.R.styleable#View_scrollIndicators 7648 */ 7649 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7650 // Shift and sanitize mask. 7651 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7652 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7653 7654 // Shift and mask indicators. 7655 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7656 indicators &= mask; 7657 7658 // Merge with non-masked flags. 7659 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7660 7661 if (mPrivateFlags3 != updatedFlags) { 7662 mPrivateFlags3 = updatedFlags; 7663 7664 if (indicators != 0) { 7665 initializeScrollIndicatorsInternal(); 7666 } 7667 invalidate(); 7668 } 7669 } 7670 7671 /** 7672 * Returns a bitmask representing the enabled scroll indicators. 7673 * <p> 7674 * For example, if the top and left scroll indicators are enabled and all 7675 * other indicators are disabled, the return value will be 7676 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7677 * <p> 7678 * To check whether the bottom scroll indicator is enabled, use the value 7679 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7680 * 7681 * @return a bitmask representing the enabled scroll indicators 7682 */ 7683 @InspectableProperty(flagMapping = { 7684 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7685 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7686 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7687 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7688 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7689 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7690 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7691 }) 7692 @ScrollIndicators 7693 public int getScrollIndicators() { 7694 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7695 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7696 } 7697 7698 @UnsupportedAppUsage 7699 ListenerInfo getListenerInfo() { 7700 if (mListenerInfo != null) { 7701 return mListenerInfo; 7702 } 7703 mListenerInfo = new ListenerInfo(); 7704 return mListenerInfo; 7705 } 7706 7707 /** 7708 * Register a callback to be invoked when the scroll X or Y positions of 7709 * this view change. 7710 * <p> 7711 * <b>Note:</b> Some views handle scrolling independently from View and may 7712 * have their own separate listeners for scroll-type events. For example, 7713 * {@link android.widget.ListView ListView} allows clients to register an 7714 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7715 * to listen for changes in list scroll position. 7716 * 7717 * @param l The listener to notify when the scroll X or Y position changes. 7718 * @see android.view.View#getScrollX() 7719 * @see android.view.View#getScrollY() 7720 */ 7721 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7722 getListenerInfo().mOnScrollChangeListener = l; 7723 } 7724 7725 /** 7726 * Register a callback to be invoked when focus of this view changed. 7727 * 7728 * @param l The callback that will run. 7729 */ 7730 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7731 getListenerInfo().mOnFocusChangeListener = l; 7732 } 7733 7734 /** 7735 * Add a listener that will be called when the bounds of the view change due to 7736 * layout processing. 7737 * 7738 * @param listener The listener that will be called when layout bounds change. 7739 */ 7740 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7741 ListenerInfo li = getListenerInfo(); 7742 if (li.mOnLayoutChangeListeners == null) { 7743 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7744 } 7745 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7746 li.mOnLayoutChangeListeners.add(listener); 7747 } 7748 } 7749 7750 /** 7751 * Remove a listener for layout changes. 7752 * 7753 * @param listener The listener for layout bounds change. 7754 */ 7755 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7756 ListenerInfo li = mListenerInfo; 7757 if (li == null || li.mOnLayoutChangeListeners == null) { 7758 return; 7759 } 7760 li.mOnLayoutChangeListeners.remove(listener); 7761 } 7762 7763 /** 7764 * Add a listener for attach state changes. 7765 * 7766 * This listener will be called whenever this view is attached or detached 7767 * from a window. Remove the listener using 7768 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7769 * 7770 * @param listener Listener to attach 7771 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7772 */ 7773 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7774 ListenerInfo li = getListenerInfo(); 7775 if (li.mOnAttachStateChangeListeners == null) { 7776 li.mOnAttachStateChangeListeners 7777 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7778 } 7779 li.mOnAttachStateChangeListeners.add(listener); 7780 } 7781 7782 /** 7783 * Remove a listener for attach state changes. The listener will receive no further 7784 * notification of window attach/detach events. 7785 * 7786 * @param listener Listener to remove 7787 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7788 */ 7789 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7790 ListenerInfo li = mListenerInfo; 7791 if (li == null || li.mOnAttachStateChangeListeners == null) { 7792 return; 7793 } 7794 li.mOnAttachStateChangeListeners.remove(listener); 7795 } 7796 7797 /** 7798 * Returns the focus-change callback registered for this view. 7799 * 7800 * @return The callback, or null if one is not registered. 7801 */ 7802 public OnFocusChangeListener getOnFocusChangeListener() { 7803 ListenerInfo li = mListenerInfo; 7804 return li != null ? li.mOnFocusChangeListener : null; 7805 } 7806 7807 /** 7808 * Register a callback to be invoked when this view is clicked. If this view is not 7809 * clickable, it becomes clickable. 7810 * 7811 * @param l The callback that will run 7812 * 7813 * @see #setClickable(boolean) 7814 */ 7815 public void setOnClickListener(@Nullable OnClickListener l) { 7816 if (!isClickable()) { 7817 setClickable(true); 7818 } 7819 getListenerInfo().mOnClickListener = l; 7820 } 7821 7822 /** 7823 * Return whether this view has an attached OnClickListener. Returns 7824 * true if there is a listener, false if there is none. 7825 */ 7826 public boolean hasOnClickListeners() { 7827 ListenerInfo li = mListenerInfo; 7828 return (li != null && li.mOnClickListener != null); 7829 } 7830 7831 /** 7832 * Register a callback to be invoked when this view is clicked and held. If this view is not 7833 * long clickable, it becomes long clickable. 7834 * 7835 * @param l The callback that will run 7836 * 7837 * @see #setLongClickable(boolean) 7838 */ 7839 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7840 if (!isLongClickable()) { 7841 setLongClickable(true); 7842 } 7843 getListenerInfo().mOnLongClickListener = l; 7844 } 7845 7846 /** 7847 * Return whether this view has an attached OnLongClickListener. Returns 7848 * true if there is a listener, false if there is none. 7849 */ 7850 public boolean hasOnLongClickListeners() { 7851 ListenerInfo li = mListenerInfo; 7852 return (li != null && li.mOnLongClickListener != null); 7853 } 7854 7855 /** 7856 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7857 * @hide 7858 */ 7859 @Nullable 7860 public OnLongClickListener getOnLongClickListener() { 7861 ListenerInfo li = mListenerInfo; 7862 return (li != null) ? li.mOnLongClickListener : null; 7863 } 7864 7865 /** 7866 * Register a callback to be invoked when this view is context clicked. If the view is not 7867 * context clickable, it becomes context clickable. 7868 * 7869 * @param l The callback that will run 7870 * @see #setContextClickable(boolean) 7871 */ 7872 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7873 if (!isContextClickable()) { 7874 setContextClickable(true); 7875 } 7876 getListenerInfo().mOnContextClickListener = l; 7877 } 7878 7879 /** 7880 * Register a callback to be invoked when the context menu for this view is 7881 * being built. If this view is not long clickable, it becomes long clickable. 7882 * 7883 * @param l The callback that will run 7884 * 7885 */ 7886 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7887 if (!isLongClickable()) { 7888 setLongClickable(true); 7889 } 7890 getListenerInfo().mOnCreateContextMenuListener = l; 7891 } 7892 7893 /** 7894 * Set an observer to collect stats for each frame rendered for this view. 7895 * 7896 * @hide 7897 */ 7898 public void addFrameMetricsListener(Window window, 7899 Window.OnFrameMetricsAvailableListener listener, 7900 Handler handler) { 7901 if (mAttachInfo != null) { 7902 if (mAttachInfo.mThreadedRenderer != null) { 7903 if (mFrameMetricsObservers == null) { 7904 mFrameMetricsObservers = new ArrayList<>(); 7905 } 7906 7907 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7908 mFrameMetricsObservers.add(fmo); 7909 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7910 } else { 7911 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7912 } 7913 } else { 7914 if (mFrameMetricsObservers == null) { 7915 mFrameMetricsObservers = new ArrayList<>(); 7916 } 7917 7918 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7919 mFrameMetricsObservers.add(fmo); 7920 } 7921 } 7922 7923 /** 7924 * Remove observer configured to collect frame stats for this view. 7925 * 7926 * @hide 7927 */ 7928 public void removeFrameMetricsListener( 7929 Window.OnFrameMetricsAvailableListener listener) { 7930 ThreadedRenderer renderer = getThreadedRenderer(); 7931 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7932 if (fmo == null) { 7933 throw new IllegalArgumentException( 7934 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7935 } 7936 7937 if (mFrameMetricsObservers != null) { 7938 mFrameMetricsObservers.remove(fmo); 7939 if (renderer != null) { 7940 renderer.removeObserver(fmo.getRendererObserver()); 7941 } 7942 } 7943 } 7944 7945 private void registerPendingFrameMetricsObservers() { 7946 if (mFrameMetricsObservers != null) { 7947 ThreadedRenderer renderer = getThreadedRenderer(); 7948 if (renderer != null) { 7949 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7950 renderer.addObserver(fmo.getRendererObserver()); 7951 } 7952 } else { 7953 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7954 } 7955 } 7956 } 7957 7958 private FrameMetricsObserver findFrameMetricsObserver( 7959 Window.OnFrameMetricsAvailableListener listener) { 7960 if (mFrameMetricsObservers != null) { 7961 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7962 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7963 if (observer.mListener == listener) { 7964 return observer; 7965 } 7966 } 7967 } 7968 7969 return null; 7970 } 7971 7972 /** @hide */ 7973 public void setNotifyAutofillManagerOnClick(boolean notify) { 7974 if (notify) { 7975 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7976 } else { 7977 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7978 } 7979 } 7980 7981 private void notifyAutofillManagerOnClick() { 7982 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7983 try { 7984 getAutofillManager().notifyViewClicked(this); 7985 } finally { 7986 // Set it to already called so it's not called twice when called by 7987 // performClickInternal() 7988 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7989 } 7990 } 7991 } 7992 7993 /** 7994 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7995 * {@code performClick()} directly to make sure the autofill manager is notified when 7996 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7997 * method). 7998 */ 7999 private boolean performClickInternal() { 8000 // Must notify autofill manager before performing the click actions to avoid scenarios where 8001 // the app has a click listener that changes the state of views the autofill service might 8002 // be interested on. 8003 notifyAutofillManagerOnClick(); 8004 8005 return performClick(); 8006 } 8007 8008 /** 8009 * Call this view's OnClickListener, if it is defined. Performs all normal 8010 * actions associated with clicking: reporting accessibility event, playing 8011 * a sound, etc. 8012 * 8013 * @return True there was an assigned OnClickListener that was called, false 8014 * otherwise is returned. 8015 */ 8016 // NOTE: other methods on View should not call this method directly, but performClickInternal() 8017 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 8018 // could extend this method without calling super.performClick()). 8019 public boolean performClick() { 8020 // We still need to call this method to handle the cases where performClick() was called 8021 // externally, instead of through performClickInternal() 8022 notifyAutofillManagerOnClick(); 8023 8024 final boolean result; 8025 final ListenerInfo li = mListenerInfo; 8026 if (li != null && li.mOnClickListener != null) { 8027 playSoundEffect(SoundEffectConstants.CLICK); 8028 li.mOnClickListener.onClick(this); 8029 result = true; 8030 } else { 8031 result = false; 8032 } 8033 8034 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 8035 8036 notifyEnterOrExitForAutoFillIfNeeded(true); 8037 8038 return result; 8039 } 8040 8041 /** 8042 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 8043 * this only calls the listener, and does not do any associated clicking 8044 * actions like reporting an accessibility event. 8045 * 8046 * @return True there was an assigned OnClickListener that was called, false 8047 * otherwise is returned. 8048 */ 8049 public boolean callOnClick() { 8050 ListenerInfo li = mListenerInfo; 8051 if (li != null && li.mOnClickListener != null) { 8052 li.mOnClickListener.onClick(this); 8053 return true; 8054 } 8055 return false; 8056 } 8057 8058 /** 8059 * Calls this view's OnLongClickListener, if it is defined. Invokes the 8060 * context menu if the OnLongClickListener did not consume the event. 8061 * 8062 * @return {@code true} if one of the above receivers consumed the event, 8063 * {@code false} otherwise 8064 */ 8065 public boolean performLongClick() { 8066 return performLongClickInternal(mLongClickX, mLongClickY); 8067 } 8068 8069 /** 8070 * Calls this view's OnLongClickListener, if it is defined. Invokes the 8071 * context menu if the OnLongClickListener did not consume the event, 8072 * anchoring it to an (x,y) coordinate. 8073 * 8074 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 8075 * to disable anchoring 8076 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 8077 * to disable anchoring 8078 * @return {@code true} if one of the above receivers consumed the event, 8079 * {@code false} otherwise 8080 */ 8081 public boolean performLongClick(float x, float y) { 8082 mLongClickX = x; 8083 mLongClickY = y; 8084 final boolean handled = performLongClick(); 8085 mLongClickX = Float.NaN; 8086 mLongClickY = Float.NaN; 8087 return handled; 8088 } 8089 8090 /** 8091 * Calls this view's OnLongClickListener, if it is defined. Invokes the 8092 * context menu if the OnLongClickListener did not consume the event, 8093 * optionally anchoring it to an (x,y) coordinate. 8094 * 8095 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 8096 * to disable anchoring 8097 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 8098 * to disable anchoring 8099 * @return {@code true} if one of the above receivers consumed the event, 8100 * {@code false} otherwise 8101 */ 8102 private boolean performLongClickInternal(float x, float y) { 8103 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 8104 8105 boolean handled = false; 8106 final OnLongClickListener listener = 8107 mListenerInfo == null ? null : mListenerInfo.mOnLongClickListener; 8108 boolean shouldPerformHapticFeedback = true; 8109 if (listener != null) { 8110 handled = listener.onLongClick(View.this); 8111 if (handled) { 8112 shouldPerformHapticFeedback = listener.onLongClickUseDefaultHapticFeedback( 8113 View.this); 8114 } 8115 } 8116 if (!handled) { 8117 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 8118 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 8119 } 8120 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 8121 if (!handled) { 8122 handled = showLongClickTooltip((int) x, (int) y); 8123 } 8124 } 8125 if (handled && shouldPerformHapticFeedback) { 8126 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 8127 } 8128 return handled; 8129 } 8130 8131 /** 8132 * Call this view's OnContextClickListener, if it is defined. 8133 * 8134 * @param x the x coordinate of the context click 8135 * @param y the y coordinate of the context click 8136 * @return True if there was an assigned OnContextClickListener that consumed the event, false 8137 * otherwise. 8138 */ 8139 public boolean performContextClick(float x, float y) { 8140 return performContextClick(); 8141 } 8142 8143 /** 8144 * Call this view's OnContextClickListener, if it is defined. 8145 * 8146 * @return True if there was an assigned OnContextClickListener that consumed the event, false 8147 * otherwise. 8148 */ 8149 public boolean performContextClick() { 8150 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 8151 8152 boolean handled = false; 8153 ListenerInfo li = mListenerInfo; 8154 if (li != null && li.mOnContextClickListener != null) { 8155 handled = li.mOnContextClickListener.onContextClick(View.this); 8156 } 8157 if (handled) { 8158 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 8159 } 8160 return handled; 8161 } 8162 8163 /** 8164 * Performs button-related actions during a touch down event. 8165 * 8166 * @param event The event. 8167 * @return True if the down was consumed. 8168 * 8169 * @hide 8170 */ 8171 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 8172 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 8173 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 8174 showContextMenu(event.getX(), event.getY()); 8175 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 8176 return true; 8177 } 8178 return false; 8179 } 8180 8181 /** 8182 * Shows the context menu for this view. 8183 * 8184 * @return {@code true} if the context menu was shown, {@code false} 8185 * otherwise 8186 * @see #showContextMenu(float, float) 8187 */ 8188 public boolean showContextMenu() { 8189 return getParent().showContextMenuForChild(this); 8190 } 8191 8192 /** 8193 * Shows the context menu for this view anchored to the specified 8194 * view-relative coordinate. 8195 * 8196 * @param x the X coordinate in pixels relative to the view to which the 8197 * menu should be anchored, or {@link Float#NaN} to disable anchoring 8198 * @param y the Y coordinate in pixels relative to the view to which the 8199 * menu should be anchored, or {@link Float#NaN} to disable anchoring 8200 * @return {@code true} if the context menu was shown, {@code false} 8201 * otherwise 8202 */ 8203 public boolean showContextMenu(float x, float y) { 8204 return getParent().showContextMenuForChild(this, x, y); 8205 } 8206 8207 /** 8208 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 8209 * 8210 * @param callback Callback that will control the lifecycle of the action mode 8211 * @return The new action mode if it is started, null otherwise 8212 * 8213 * @see ActionMode 8214 * @see #startActionMode(android.view.ActionMode.Callback, int) 8215 */ 8216 public ActionMode startActionMode(ActionMode.Callback callback) { 8217 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 8218 } 8219 8220 /** 8221 * Start an action mode with the given type. 8222 * 8223 * @param callback Callback that will control the lifecycle of the action mode 8224 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 8225 * @return The new action mode if it is started, null otherwise 8226 * 8227 * @see ActionMode 8228 */ 8229 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 8230 ViewParent parent = getParent(); 8231 if (parent == null) return null; 8232 try { 8233 return parent.startActionModeForChild(this, callback, type); 8234 } catch (AbstractMethodError ame) { 8235 // Older implementations of custom views might not implement this. 8236 return parent.startActionModeForChild(this, callback); 8237 } 8238 } 8239 8240 /** 8241 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 8242 * Context, creating a unique View identifier to retrieve the result. 8243 * 8244 * @param intent The Intent to be started. 8245 * @param requestCode The request code to use. 8246 * @hide 8247 */ 8248 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 8249 public void startActivityForResult(Intent intent, int requestCode) { 8250 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 8251 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 8252 } 8253 8254 /** 8255 * If this View corresponds to the calling who, dispatches the activity result. 8256 * @param who The identifier for the targeted View to receive the result. 8257 * @param requestCode The integer request code originally supplied to 8258 * startActivityForResult(), allowing you to identify who this 8259 * result came from. 8260 * @param resultCode The integer result code returned by the child activity 8261 * through its setResult(). 8262 * @param data An Intent, which can return result data to the caller 8263 * (various data can be attached to Intent "extras"). 8264 * @return {@code true} if the activity result was dispatched. 8265 * @hide 8266 */ 8267 public boolean dispatchActivityResult( 8268 String who, int requestCode, int resultCode, Intent data) { 8269 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 8270 onActivityResult(requestCode, resultCode, data); 8271 mStartActivityRequestWho = null; 8272 return true; 8273 } 8274 return false; 8275 } 8276 8277 /** 8278 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 8279 * 8280 * @param requestCode The integer request code originally supplied to 8281 * startActivityForResult(), allowing you to identify who this 8282 * result came from. 8283 * @param resultCode The integer result code returned by the child activity 8284 * through its setResult(). 8285 * @param data An Intent, which can return result data to the caller 8286 * (various data can be attached to Intent "extras"). 8287 * @hide 8288 */ 8289 public void onActivityResult(int requestCode, int resultCode, Intent data) { 8290 // Do nothing. 8291 } 8292 8293 /** 8294 * Register a callback to be invoked when a hardware key is pressed in this view. 8295 * Key presses in software input methods will generally not trigger the methods of 8296 * this listener. 8297 * @param l the key listener to attach to this view 8298 */ 8299 public void setOnKeyListener(OnKeyListener l) { 8300 getListenerInfo().mOnKeyListener = l; 8301 } 8302 8303 /** 8304 * Register a callback to be invoked when a touch event is sent to this view. 8305 * @param l the touch listener to attach to this view 8306 */ 8307 public void setOnTouchListener(OnTouchListener l) { 8308 getListenerInfo().mOnTouchListener = l; 8309 } 8310 8311 /** 8312 * Register a callback to be invoked when a generic motion event is sent to this view. 8313 * @param l the generic motion listener to attach to this view 8314 */ 8315 public void setOnGenericMotionListener(OnGenericMotionListener l) { 8316 getListenerInfo().mOnGenericMotionListener = l; 8317 } 8318 8319 /** 8320 * Register a callback to be invoked when a hover event is sent to this view. 8321 * @param l the hover listener to attach to this view 8322 */ 8323 public void setOnHoverListener(OnHoverListener l) { 8324 getListenerInfo().mOnHoverListener = l; 8325 } 8326 8327 /** 8328 * Register a drag event listener callback object for this View. The parameter is 8329 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 8330 * View, the system calls the 8331 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 8332 * @param l An implementation of {@link android.view.View.OnDragListener}. 8333 */ 8334 public void setOnDragListener(OnDragListener l) { 8335 getListenerInfo().mOnDragListener = l; 8336 } 8337 8338 /** 8339 * Give this view focus. This will cause 8340 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 8341 * 8342 * Note: this does not check whether this {@link View} should get focus, it just 8343 * gives it focus no matter what. It should only be called internally by framework 8344 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 8345 * 8346 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 8347 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 8348 * focus moved when requestFocus() is called. It may not always 8349 * apply, in which case use the default View.FOCUS_DOWN. 8350 * @param previouslyFocusedRect The rectangle of the view that had focus 8351 * prior in this View's coordinate system. 8352 */ 8353 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 8354 if (DBG) { 8355 System.out.println(this + " requestFocus()"); 8356 } 8357 8358 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 8359 mPrivateFlags |= PFLAG_FOCUSED; 8360 8361 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 8362 8363 if (mParent != null) { 8364 mParent.requestChildFocus(this, this); 8365 updateFocusedInCluster(oldFocus, direction); 8366 } 8367 8368 if (mAttachInfo != null) { 8369 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 8370 } 8371 8372 onFocusChanged(true, direction, previouslyFocusedRect); 8373 refreshDrawableState(); 8374 } 8375 } 8376 8377 /** 8378 * Sets this view's preference for reveal behavior when it gains focus. 8379 * 8380 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 8381 * this view would prefer to be brought fully into view when it gains focus. 8382 * For example, a text field that a user is meant to type into. Other views such 8383 * as scrolling containers may prefer to opt-out of this behavior.</p> 8384 * 8385 * <p>The default value for views is true, though subclasses may change this 8386 * based on their preferred behavior.</p> 8387 * 8388 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 8389 * 8390 * @see #getRevealOnFocusHint() 8391 */ 8392 public final void setRevealOnFocusHint(boolean revealOnFocus) { 8393 if (revealOnFocus) { 8394 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 8395 } else { 8396 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 8397 } 8398 } 8399 8400 /** 8401 * Returns this view's preference for reveal behavior when it gains focus. 8402 * 8403 * <p>When this method returns true for a child view requesting focus, ancestor 8404 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 8405 * should make a best effort to make the newly focused child fully visible to the user. 8406 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 8407 * other properties affecting visibility to the user as part of the focus change.</p> 8408 * 8409 * @return true if this view would prefer to become fully visible when it gains focus, 8410 * false if it would prefer not to disrupt scroll positioning 8411 * 8412 * @see #setRevealOnFocusHint(boolean) 8413 */ 8414 public final boolean getRevealOnFocusHint() { 8415 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 8416 } 8417 8418 /** 8419 * Populates <code>outRect</code> with the hotspot bounds. By default, 8420 * the hotspot bounds are identical to the screen bounds. 8421 * 8422 * @param outRect rect to populate with hotspot bounds 8423 * @hide Only for internal use by views and widgets. 8424 */ 8425 public void getHotspotBounds(Rect outRect) { 8426 final Drawable background = getBackground(); 8427 if (background != null) { 8428 background.getHotspotBounds(outRect); 8429 } else { 8430 getBoundsOnScreen(outRect); 8431 } 8432 } 8433 8434 /** 8435 * Request that a rectangle of this view be visible on the screen, 8436 * scrolling if necessary just enough. 8437 * 8438 * <p>A View should call this if it maintains some notion of which part 8439 * of its content is interesting. For example, a text editing view 8440 * should call this when its cursor moves. 8441 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 8442 * It should not be affected by which part of the View is currently visible or its scroll 8443 * position. 8444 * 8445 * @param rectangle The rectangle in the View's content coordinate space 8446 * @return Whether any parent scrolled. 8447 * @see AccessibilityAction#ACTION_SHOW_ON_SCREEN 8448 */ 8449 public boolean requestRectangleOnScreen(Rect rectangle) { 8450 return requestRectangleOnScreen(rectangle, false); 8451 } 8452 8453 /** 8454 * Request that a rectangle of this view be visible on the screen, 8455 * scrolling if necessary just enough. 8456 * 8457 * <p>A View should call this if it maintains some notion of which part 8458 * of its content is interesting. For example, a text editing view 8459 * should call this when its cursor moves. 8460 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 8461 * It should not be affected by which part of the View is currently visible or its scroll 8462 * position. 8463 * <p>When <code>immediate</code> is set to true, scrolling will not be 8464 * animated. 8465 * 8466 * @param rectangle The rectangle in the View's content coordinate space 8467 * @param immediate True to forbid animated scrolling, false otherwise 8468 * @return Whether any parent scrolled. 8469 */ 8470 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 8471 if (mParent == null) { 8472 return false; 8473 } 8474 8475 View child = this; 8476 8477 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 8478 position.set(rectangle); 8479 8480 ViewParent parent = mParent; 8481 boolean scrolled = false; 8482 while (parent != null) { 8483 rectangle.set((int) position.left, (int) position.top, 8484 (int) position.right, (int) position.bottom); 8485 8486 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 8487 8488 if (!(parent instanceof View)) { 8489 break; 8490 } 8491 8492 // move it from child's content coordinate space to parent's content coordinate space 8493 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 8494 8495 child = (View) parent; 8496 parent = child.getParent(); 8497 } 8498 8499 return scrolled; 8500 } 8501 8502 /** 8503 * Called when this view wants to give up focus. If focus is cleared 8504 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 8505 * <p> 8506 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 8507 * to the first focusable View from the top after focus is cleared. Hence, if this 8508 * View is the first from the top that can take focus, then all callbacks 8509 * related to clearing focus will be invoked after which the framework will 8510 * give focus to this view. 8511 * </p> 8512 */ 8513 public void clearFocus() { 8514 if (DBG) { 8515 System.out.println(this + " clearFocus()"); 8516 } 8517 8518 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 8519 clearFocusInternal(null, true, refocus); 8520 } 8521 8522 /** 8523 * Clears focus from the view, optionally propagating the change up through 8524 * the parent hierarchy and requesting that the root view place new focus. 8525 * 8526 * @param propagate whether to propagate the change up through the parent 8527 * hierarchy 8528 * @param refocus when propagate is true, specifies whether to request the 8529 * root view place new focus 8530 * @hide 8531 */ 8532 public void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 8533 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 8534 mPrivateFlags &= ~PFLAG_FOCUSED; 8535 clearParentsWantFocus(); 8536 8537 if (propagate && mParent != null) { 8538 mParent.clearChildFocus(this); 8539 } 8540 8541 onFocusChanged(false, 0, null); 8542 refreshDrawableState(); 8543 8544 if (propagate && (!refocus || !rootViewRequestFocus())) { 8545 notifyGlobalFocusCleared(this); 8546 } 8547 } 8548 } 8549 8550 void notifyGlobalFocusCleared(View oldFocus) { 8551 if (oldFocus != null && mAttachInfo != null) { 8552 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 8553 } 8554 } 8555 8556 boolean rootViewRequestFocus() { 8557 final View root = getRootView(); 8558 return root != null && root.requestFocus(); 8559 } 8560 8561 /** 8562 * Called internally by the view system when a new view is getting focus. 8563 * This is what clears the old focus. 8564 * <p> 8565 * <b>NOTE:</b> The parent view's focused child must be updated manually 8566 * after calling this method. Otherwise, the view hierarchy may be left in 8567 * an inconstent state. 8568 */ 8569 void unFocus(View focused) { 8570 if (DBG) { 8571 System.out.println(this + " unFocus()"); 8572 } 8573 8574 clearFocusInternal(focused, false, false); 8575 } 8576 8577 /** 8578 * Returns true if this view has focus itself, or is the ancestor of the 8579 * view that has focus. 8580 * 8581 * @return True if this view has or contains focus, false otherwise. 8582 */ 8583 @ViewDebug.ExportedProperty(category = "focus") 8584 public boolean hasFocus() { 8585 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8586 } 8587 8588 /** 8589 * Returns true if this view is focusable or if it contains a reachable View 8590 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 8591 * is a view whose parents do not block descendants focus. 8592 * Only {@link #VISIBLE} views are considered focusable. 8593 * 8594 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8595 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8596 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8597 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8598 * {@code false} for views not explicitly marked as focusable. 8599 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8600 * behavior.</p> 8601 * 8602 * @return {@code true} if the view is focusable or if the view contains a focusable 8603 * view, {@code false} otherwise 8604 * 8605 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8606 * @see ViewGroup#getTouchscreenBlocksFocus() 8607 * @see #hasExplicitFocusable() 8608 */ 8609 public boolean hasFocusable() { 8610 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8611 } 8612 8613 /** 8614 * Returns true if this view is focusable or if it contains a reachable View 8615 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8616 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8617 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8618 * {@link #FOCUSABLE} are considered focusable. 8619 * 8620 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8621 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8622 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8623 * to focusable will not.</p> 8624 * 8625 * @return {@code true} if the view is focusable or if the view contains a focusable 8626 * view, {@code false} otherwise 8627 * 8628 * @see #hasFocusable() 8629 */ 8630 public boolean hasExplicitFocusable() { 8631 return hasFocusable(false, true); 8632 } 8633 8634 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8635 if (!isFocusableInTouchMode()) { 8636 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8637 final ViewGroup g = (ViewGroup) p; 8638 if (g.shouldBlockFocusForTouchscreen()) { 8639 return false; 8640 } 8641 } 8642 } 8643 8644 // Invisible, gone, or disabled views are never focusable. 8645 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8646 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8647 return false; 8648 } 8649 8650 // Only use effective focusable value when allowed. 8651 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8652 return true; 8653 } 8654 8655 return false; 8656 } 8657 8658 /** 8659 * Called by the view system when the focus state of this view changes. 8660 * When the focus change event is caused by directional navigation, direction 8661 * and previouslyFocusedRect provide insight into where the focus is coming from. 8662 * When overriding, be sure to call up through to the super class so that 8663 * the standard focus handling will occur. 8664 * 8665 * @param gainFocus True if the View has focus; false otherwise. 8666 * @param direction The direction focus has moved when requestFocus() 8667 * is called to give this view focus. Values are 8668 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8669 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8670 * It may not always apply, in which case use the default. 8671 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8672 * system, of the previously focused view. If applicable, this will be 8673 * passed in as finer grained information about where the focus is coming 8674 * from (in addition to direction). Will be <code>null</code> otherwise. 8675 */ 8676 @CallSuper 8677 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8678 @Nullable Rect previouslyFocusedRect) { 8679 if (DBG) { 8680 Log.d(VIEW_LOG_TAG, "onFocusChanged() entered. gainFocus: " 8681 + gainFocus); 8682 } 8683 if (gainFocus) { 8684 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8685 } else { 8686 notifyViewAccessibilityStateChangedIfNeeded( 8687 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8688 } 8689 8690 // Here we check whether we still need the default focus highlight, and switch it on/off. 8691 switchDefaultFocusHighlight(); 8692 8693 if (!gainFocus) { 8694 if (isPressed()) { 8695 setPressed(false); 8696 } 8697 if (hasWindowFocus()) { 8698 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8699 } 8700 onFocusLost(); 8701 } else if (hasWindowFocus()) { 8702 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8703 ViewRootImpl viewRoot = getViewRootImpl(); 8704 if (viewRoot != null) { 8705 if (mIsHandwritingDelegate) { 8706 viewRoot.getHandwritingInitiator().onDelegateViewFocused(this); 8707 } else if (initiationWithoutInputConnection() && onCheckIsTextEditor()) { 8708 viewRoot.getHandwritingInitiator().onEditorFocused(this); 8709 } 8710 } 8711 } 8712 8713 invalidate(true); 8714 ListenerInfo li = mListenerInfo; 8715 if (li != null && li.mOnFocusChangeListener != null) { 8716 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8717 } 8718 8719 if (mAttachInfo != null) { 8720 mAttachInfo.mKeyDispatchState.reset(this); 8721 } 8722 8723 if (mParent != null) { 8724 mParent.onDescendantUnbufferedRequested(); 8725 } 8726 8727 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8728 updatePreferKeepClearForFocus(); 8729 } 8730 8731 /** 8732 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8733 * 8734 * @param hasFocus {@code true} when the {@link View} is being focused. 8735 */ 8736 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8737 if (mAttachInfo == null) { 8738 return; 8739 } 8740 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8741 } 8742 8743 /** @hide */ 8744 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8745 if (canNotifyAutofillEnterExitEvent()) { 8746 AutofillManager afm = getAutofillManager(); 8747 if (afm != null) { 8748 if (DBG) { 8749 Log.d(VIEW_LOG_TAG, this + " afm is not null"); 8750 } 8751 if (enter) { 8752 // We have not been laid out yet, hence cannot evaluate 8753 // whether this view is visible to the user, we will do 8754 // the evaluation once layout is complete. 8755 // Sometimes, views are already laid out, but it's still 8756 // not visible to the user, we also do the evaluation once 8757 // the view is visible. ex: There is a fade-in animation 8758 // for the activity, the view will be laid out when the 8759 // animation beginning. On the time, the view is not visible 8760 // to the user. And then as the animation progresses, the view 8761 // becomes visible to the user. 8762 if (DBG) { 8763 Log.d(VIEW_LOG_TAG, 8764 "notifyEnterOrExitForAutoFillIfNeeded:" 8765 + " isLaidOut(): " + isLaidOut() 8766 + " isVisibleToUser(): " + isVisibleToUser() 8767 + " isFocused(): " + isFocused()); 8768 } 8769 if (!isLaidOut() || !isVisibleToUser()) { 8770 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8771 } else if (isVisibleToUser()) { 8772 if (isFocused()) { 8773 // TODO This is a potential problem that View gets focus before it's 8774 // visible to User. Ideally View should handle the event when 8775 // isVisibleToUser() becomes true where it should issue 8776 // notifyViewEntered(). 8777 afm.notifyViewEntered(this); 8778 } else { 8779 afm.notifyViewEnteredForFillDialog(this); 8780 } 8781 } 8782 } else if (!isFocused()) { 8783 afm.notifyViewExited(this); 8784 } 8785 } 8786 } 8787 } 8788 8789 /** 8790 * Visually distinct portion of a window with window-like semantics are considered panes for 8791 * accessibility purposes. One example is the content view of a large fragment that is replaced. 8792 * In order for accessibility services to understand a pane's window-like behavior, panes 8793 * should have descriptive titles. Views with pane titles produce 8794 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}s when they appear, disappear, or change 8795 * title. 8796 * 8797 * <p> 8798 * When transitioning from one Activity to another, instead of using 8799 * {@code setAccessibilityPaneTitle()}, set a descriptive title for its window by using 8800 * {@code android:label} 8801 * for the matching Activity entry in your application's manifest or updating the title at 8802 * runtime with {@link android.app.Activity#setTitle(CharSequence)}. 8803 * 8804 * <p> 8805 * <aside> 8806 * <b>Note:</b> Use 8807 * {@link androidx.core.view.ViewCompat#setAccessibilityPaneTitle(View, CharSequence)} 8808 * for backwards-compatibility. 8809 * </aside> 8810 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8811 * View is not a pane. 8812 * 8813 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8814 * 8815 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8816 */ 8817 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8818 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8819 boolean currentPaneTitleEmpty = mAccessibilityPaneTitle == null; 8820 boolean newPaneTitleEmpty = accessibilityPaneTitle == null; 8821 mAccessibilityPaneTitle = accessibilityPaneTitle; 8822 // Make explicitly important as nulled titles need to be important for DISAPPEARED 8823 // events. 8824 if (mAccessibilityPaneTitle != null 8825 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8826 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8827 } 8828 if (currentPaneTitleEmpty) { 8829 notifyViewAccessibilityStateChangedIfNeeded( 8830 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED); 8831 } else if (newPaneTitleEmpty) { 8832 notifyViewAccessibilityStateChangedIfNeeded( 8833 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 8834 } else { 8835 notifyViewAccessibilityStateChangedIfNeeded( 8836 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8837 } 8838 } 8839 } 8840 8841 /** 8842 * Get the title of the pane for purposes of accessibility. 8843 * 8844 * @return The current pane title. 8845 * 8846 * {@see #setAccessibilityPaneTitle}. 8847 * 8848 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8849 */ 8850 @InspectableProperty 8851 @Nullable 8852 public CharSequence getAccessibilityPaneTitle() { 8853 return mAccessibilityPaneTitle; 8854 } 8855 8856 private boolean isAccessibilityPane() { 8857 return mAccessibilityPaneTitle != null; 8858 } 8859 8860 /** 8861 * Sends an accessibility event of the given type. If accessibility is 8862 * not enabled this method has no effect. The default implementation calls 8863 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8864 * to populate information about the event source (this View), then calls 8865 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8866 * populate the text content of the event source including its descendants, 8867 * then for events type {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} 8868 * and {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} with 8869 * subtype {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}, 8870 * throttle the events, and last calls 8871 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8872 * on its parent to request sending of the event to interested parties. 8873 * <p> 8874 * If an {@link AccessibilityDelegate} has been specified via calling 8875 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8876 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8877 * responsible for handling this call. 8878 * </p> 8879 * <p> 8880 * If this view uses {@link AccessibilityNodeProvider} to provide virtual view hierarchy rooted 8881 * at this view, this method should not be called to send events from virtual children because 8882 * it will populate the events with wrong information and the events should be throttled per 8883 * child instead at the virtual root level. To send events from virtual children, call 8884 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} on the view's 8885 * parent to request sending of the event to interested parties. 8886 * </p> 8887 * 8888 * @param eventType The type of the event to send, as defined by several types from 8889 * {@link AccessibilityEvent}, such as 8890 * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} or 8891 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8892 * 8893 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8894 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8895 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8896 * @see AccessibilityDelegate 8897 */ 8898 public void sendAccessibilityEvent(int eventType) { 8899 if (mAccessibilityDelegate != null) { 8900 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8901 } else { 8902 sendAccessibilityEventInternal(eventType); 8903 } 8904 } 8905 8906 /** 8907 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8908 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8909 * specified text to its users. 8910 * <p> 8911 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8912 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8913 * accurately supplying the semantics of their UI. 8914 * They should not need to specify what exactly is announced to users. 8915 * 8916 * <p> 8917 * In general, only announce transitions and don't generate a confirmation message for simple 8918 * actions like a button press. Label your controls concisely and precisely instead, and for 8919 * significant UI changes like window changes, use 8920 * {@link android.app.Activity#setTitle(CharSequence)} and 8921 * {@link #setAccessibilityPaneTitle(CharSequence)}. 8922 * 8923 * <p> 8924 * Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical 8925 * views within the user interface. These should still be used sparingly as they may generate 8926 * announcements every time a View is updated. 8927 * 8928 * <p> 8929 * For notifying users about errors, such as in a login screen with text that displays an 8930 * "incorrect password" notification, that view should send an AccessibilityEvent of type 8931 * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set 8932 * {@link AccessibilityNodeInfo#setError(CharSequence)} instead. Custom widgets should expose 8933 * error-setting methods that support accessibility automatically. For example, instead of 8934 * explicitly sending this event when using a TextView, use 8935 * {@link android.widget.TextView#setError(CharSequence)}. 8936 * 8937 * <p> 8938 * Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the 8939 * user interface. While a live region may send different types of events generated by the view, 8940 * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of 8941 * type {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}. 8942 * 8943 * @param text The announcement text. 8944 */ 8945 public void announceForAccessibility(CharSequence text) { 8946 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8947 AccessibilityEvent event = AccessibilityEvent.obtain( 8948 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8949 onInitializeAccessibilityEvent(event); 8950 event.getText().add(text); 8951 event.setContentDescription(null); 8952 mParent.requestSendAccessibilityEvent(this, event); 8953 } 8954 } 8955 8956 /** 8957 * @see #sendAccessibilityEvent(int) 8958 * 8959 * Note: Called from the default {@link AccessibilityDelegate}. 8960 * 8961 * @hide 8962 */ 8963 public void sendAccessibilityEventInternal(int eventType) { 8964 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8965 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8966 } 8967 } 8968 8969 /** 8970 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8971 * takes as an argument an empty {@link AccessibilityEvent} and does not 8972 * perform a check whether accessibility is enabled. 8973 * <p> 8974 * If an {@link AccessibilityDelegate} has been specified via calling 8975 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8976 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8977 * is responsible for handling this call. 8978 * </p> 8979 * 8980 * @param event The event to send. 8981 * 8982 * @see #sendAccessibilityEvent(int) 8983 */ 8984 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8985 if (mAccessibilityDelegate != null) { 8986 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8987 } else { 8988 sendAccessibilityEventUncheckedInternal(event); 8989 } 8990 } 8991 8992 /** 8993 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8994 * 8995 * Note: Called from the default {@link AccessibilityDelegate}. 8996 * 8997 * @hide 8998 */ 8999 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 9000 // Panes disappearing are relevant even if though the view is no longer visible. 9001 boolean isWindowStateChanged = 9002 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 9003 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 9004 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 9005 boolean detached = detached(); 9006 if (!isShown() && !isWindowDisappearedEvent && !detached) { 9007 return; 9008 } 9009 onInitializeAccessibilityEvent(event); 9010 // Only a subset of accessibility events populates text content. 9011 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 9012 dispatchPopulateAccessibilityEvent(event); 9013 } 9014 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 9015 if (throttle != null) { 9016 throttle.post(event); 9017 } else if (!isWindowDisappearedEvent && detached) { 9018 // Views could be attached soon later. Accessibility events during this temporarily 9019 // detached period should be sent too. 9020 postDelayed(() -> { 9021 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 9022 requestParentSendAccessibilityEvent(event); 9023 } 9024 }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 9025 } else { 9026 requestParentSendAccessibilityEvent(event); 9027 } 9028 } 9029 9030 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 9031 ViewParent parent = getParent(); 9032 if (parent != null) { 9033 getParent().requestSendAccessibilityEvent(this, event); 9034 } 9035 } 9036 9037 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 9038 AccessibilityEvent event) { 9039 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 9040 if (mSendViewScrolledAccessibilityEvent == null) { 9041 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 9042 } 9043 return mSendViewScrolledAccessibilityEvent; 9044 } 9045 boolean isStateContentChanged = (event.getContentChangeTypes() 9046 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 9047 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 9048 && isStateContentChanged) { 9049 if (mSendStateChangedAccessibilityEvent == null) { 9050 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 9051 } 9052 return mSendStateChangedAccessibilityEvent; 9053 } 9054 return null; 9055 } 9056 9057 private void clearAccessibilityThrottles() { 9058 cancel(mSendViewScrolledAccessibilityEvent); 9059 cancel(mSendStateChangedAccessibilityEvent); 9060 } 9061 9062 /** 9063 * Dispatches an {@link AccessibilityEvent} to the {@link View} to add the text content of the 9064 * view and its children. 9065 * <p> 9066 * <b>Note:</b> This method should only be used with event.setText(). 9067 * Avoid mutating other event state in this method. In general, put UI metadata in the node for 9068 * services to easily query. 9069 * <ul> 9070 * <li> If you are modifying other event properties, you may be eliminating semantics 9071 * accessibility services may want. Instead, send a separate event using 9072 * {@link #sendAccessibilityEvent(int)} and override 9073 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 9074 * </li> 9075 * <li>If you are checking for type {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED} 9076 * to generate window/title announcements, you may be causing disruptive announcements 9077 * (or making no announcements at all). Instead, follow the practices described in 9078 * {@link View#announceForAccessibility(CharSequence)}. <b>Note:</b> this does not suggest 9079 * calling announceForAccessibility(), but using the suggestions listed in its 9080 * documentation. 9081 * </li> 9082 * <li>If you are making changes based on the state of accessibility, such as checking for 9083 * an event type to trigger a UI update, while well-intentioned, you are creating brittle, 9084 * less well-maintained code that works for some users but not others. Instead, leverage 9085 * existing code for equitable experiences and less technical debt. See 9086 * {@link AccessibilityManager#isEnabled()} for an example. 9087 * </li> 9088 * </ul> 9089 * <p> 9090 * Note that the event text is populated in a separate dispatch path 9091 * ({@link #onPopulateAccessibilityEvent(AccessibilityEvent)}) since we add to the 9092 * event not only the text of the source but also the text of all its descendants. 9093 * <p> 9094 * A typical implementation will call 9095 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on this view 9096 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 9097 * on each child or the first child that is visible. Override this method if custom population 9098 * of the event text content is required. 9099 * 9100 * <p> 9101 * If an {@link AccessibilityDelegate} has been specified via calling 9102 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9103 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 9104 * is responsible for handling this call. 9105 * </p> 9106 * <p> 9107 * If this view sets {@link #isAccessibilityDataSensitive()} then this view should only append 9108 * sensitive information to an event that also sets 9109 * {@link AccessibilityEvent#isAccessibilityDataSensitive()}. 9110 * </p> 9111 * <p> 9112 * <em>Note:</em> Accessibility events of certain types are not dispatched for 9113 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 9114 * </p> 9115 * 9116 * @param event The event. 9117 * 9118 * @return True if the event population was completed. 9119 */ 9120 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 9121 if (mAccessibilityDelegate != null) { 9122 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 9123 } else { 9124 return dispatchPopulateAccessibilityEventInternal(event); 9125 } 9126 } 9127 9128 /** 9129 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 9130 * 9131 * Note: Called from the default {@link AccessibilityDelegate}. 9132 * 9133 * @hide 9134 */ 9135 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 9136 onPopulateAccessibilityEvent(event); 9137 return false; 9138 } 9139 9140 /** 9141 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 9142 * giving a chance to this View to populate the accessibility event with its 9143 * text content. 9144 * <p> 9145 * <b>Note:</b> This method should only be used with event.setText(). 9146 * Avoid mutating other event state in this method. Instead, follow the practices described in 9147 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}. In general, put UI 9148 * metadata in the node for services to easily query, than in transient events. 9149 * <p> 9150 * Example: Adding formatted date string to an accessibility event in addition 9151 * to the text added by the super implementation: 9152 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 9153 * super.onPopulateAccessibilityEvent(event); 9154 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 9155 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 9156 * mCurrentDate.getTimeInMillis(), flags); 9157 * event.getText().add(selectedDateUtterance); 9158 * }</pre> 9159 * <p> 9160 * If an {@link AccessibilityDelegate} has been specified via calling 9161 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9162 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 9163 * is responsible for handling this call. 9164 * </p> 9165 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 9166 * information to the event, in case the default implementation has basic information to add. 9167 * </p> 9168 * 9169 * @param event The accessibility event which to populate. 9170 * 9171 * @see #sendAccessibilityEvent(int) 9172 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 9173 */ 9174 @CallSuper 9175 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 9176 if (mAccessibilityDelegate != null) { 9177 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 9178 } else { 9179 onPopulateAccessibilityEventInternal(event); 9180 } 9181 } 9182 9183 /** 9184 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 9185 * 9186 * Note: Called from the default {@link AccessibilityDelegate}. 9187 * 9188 * @hide 9189 */ 9190 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 9191 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 9192 && isAccessibilityPane()) { 9193 event.getText().add(getAccessibilityPaneTitle()); 9194 } 9195 } 9196 9197 /** 9198 * Initializes an {@link AccessibilityEvent} with information about 9199 * this View which is the event source. In other words, the source of 9200 * an accessibility event is the view whose state change triggered firing 9201 * the event. 9202 * <p> 9203 * Example: Setting the password property of an event in addition 9204 * to properties set by the super implementation: 9205 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 9206 * super.onInitializeAccessibilityEvent(event); 9207 * event.setPassword(true); 9208 * }</pre> 9209 * <p> 9210 * If an {@link AccessibilityDelegate} has been specified via calling 9211 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9212 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 9213 * is responsible for handling this call. 9214 * </p> 9215 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 9216 * information to the event, in case the default implementation has basic information to add. 9217 * </p> 9218 * @param event The event to initialize. 9219 * 9220 * @see #sendAccessibilityEvent(int) 9221 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 9222 */ 9223 @CallSuper 9224 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 9225 if (mAccessibilityDelegate != null) { 9226 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 9227 } else { 9228 onInitializeAccessibilityEventInternal(event); 9229 } 9230 } 9231 9232 /** 9233 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 9234 * 9235 * Note: Called from the default {@link AccessibilityDelegate}. 9236 * 9237 * @hide 9238 */ 9239 @UnsupportedAppUsage 9240 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 9241 event.setSource(this); 9242 event.setClassName(getAccessibilityClassName()); 9243 event.setPackageName(getContext().getPackageName()); 9244 event.setEnabled(isEnabled()); 9245 event.setContentDescription(mContentDescription); 9246 event.setScrollX(getScrollX()); 9247 event.setScrollY(getScrollY()); 9248 9249 switch (event.getEventType()) { 9250 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 9251 ArrayList<View> focusablesTempList = (mAttachInfo != null) 9252 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 9253 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 9254 event.setItemCount(focusablesTempList.size()); 9255 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 9256 if (mAttachInfo != null) { 9257 focusablesTempList.clear(); 9258 } 9259 } break; 9260 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 9261 CharSequence text = getIterableTextForAccessibility(); 9262 if (text != null && text.length() > 0) { 9263 event.setFromIndex(getAccessibilitySelectionStart()); 9264 event.setToIndex(getAccessibilitySelectionEnd()); 9265 event.setItemCount(text.length()); 9266 } 9267 } break; 9268 } 9269 } 9270 9271 /** 9272 * Returns an {@link AccessibilityNodeInfo} representing this view from the 9273 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 9274 * This method is responsible for obtaining an accessibility node info from a 9275 * pool of reusable instances and calling 9276 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 9277 * initialize the former. 9278 * <p> 9279 * Note: The client is responsible for recycling the obtained instance by calling 9280 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 9281 * </p> 9282 * 9283 * @return A populated {@link AccessibilityNodeInfo}. 9284 * 9285 * @see AccessibilityNodeInfo 9286 */ 9287 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 9288 if (mAccessibilityDelegate != null) { 9289 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 9290 } else { 9291 return createAccessibilityNodeInfoInternal(); 9292 } 9293 } 9294 9295 /** 9296 * @see #createAccessibilityNodeInfo() 9297 * 9298 * @hide 9299 */ 9300 public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 9301 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9302 if (provider != null) { 9303 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 9304 } else { 9305 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 9306 onInitializeAccessibilityNodeInfo(info); 9307 return info; 9308 } 9309 } 9310 9311 /** 9312 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 9313 * The base implementation sets: 9314 * <ul> 9315 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 9316 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 9317 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 9318 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 9319 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 9320 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 9321 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 9322 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 9323 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 9324 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 9325 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 9326 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 9327 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 9328 * </ul> 9329 * <p> 9330 * Subclasses should override this method, call the super implementation, 9331 * and set additional attributes. 9332 * </p> 9333 * <p> 9334 * If an {@link AccessibilityDelegate} has been specified via calling 9335 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9336 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 9337 * is responsible for handling this call. 9338 * </p> 9339 * 9340 * @param info The instance to initialize. 9341 */ 9342 @CallSuper 9343 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 9344 if (mAccessibilityDelegate != null) { 9345 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 9346 } else { 9347 onInitializeAccessibilityNodeInfoInternal(info); 9348 } 9349 } 9350 9351 /** 9352 * Gets the location of this view in screen coordinates. 9353 * 9354 * @param outRect The output location 9355 * @hide 9356 */ 9357 @UnsupportedAppUsage 9358 public void getBoundsOnScreen(Rect outRect) { 9359 getBoundsOnScreen(outRect, false); 9360 } 9361 9362 /** 9363 * Gets the location of this view in screen coordinates. 9364 * 9365 * @param outRect The output location 9366 * @param clipToParent Whether to clip child bounds to the parent ones. 9367 * @hide 9368 */ 9369 @UnsupportedAppUsage 9370 @TestApi 9371 public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { 9372 if (mAttachInfo == null) { 9373 return; 9374 } 9375 RectF position = mAttachInfo.mTmpTransformRect; 9376 getBoundsToScreenInternal(position, clipToParent); 9377 outRect.set(Math.round(position.left), Math.round(position.top), 9378 Math.round(position.right), Math.round(position.bottom)); 9379 // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded 9380 // will sandbox outRect within window bounds. 9381 mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); 9382 } 9383 9384 /** 9385 * Gets the location of this view in screen coordinates. 9386 * 9387 * @param outRect The output location 9388 * @param clipToParent Whether to clip child bounds to the parent ones. 9389 * @hide 9390 */ 9391 public void getBoundsOnScreen(RectF outRect, boolean clipToParent) { 9392 if (mAttachInfo == null) { 9393 return; 9394 } 9395 RectF position = mAttachInfo.mTmpTransformRect; 9396 getBoundsToScreenInternal(position, clipToParent); 9397 outRect.set(position.left, position.top, position.right, position.bottom); 9398 } 9399 9400 /** 9401 * Gets the location of this view in window coordinates. 9402 * 9403 * @param outRect The output location 9404 * @param clipToParent Whether to clip child bounds to the parent ones. 9405 * @hide 9406 */ 9407 public void getBoundsInWindow(Rect outRect, boolean clipToParent) { 9408 if (mAttachInfo == null) { 9409 return; 9410 } 9411 RectF position = mAttachInfo.mTmpTransformRect; 9412 getBoundsToWindowInternal(position, clipToParent); 9413 outRect.set(Math.round(position.left), Math.round(position.top), 9414 Math.round(position.right), Math.round(position.bottom)); 9415 } 9416 9417 private void getBoundsToScreenInternal(RectF position, boolean clipToParent) { 9418 position.set(0, 0, mRight - mLeft, mBottom - mTop); 9419 mapRectFromViewToScreenCoords(position, clipToParent); 9420 } 9421 9422 private void getBoundsToWindowInternal(RectF position, boolean clipToParent) { 9423 position.set(0, 0, mRight - mLeft, mBottom - mTop); 9424 mapRectFromViewToWindowCoords(position, clipToParent); 9425 } 9426 9427 /** 9428 * Map a rectangle from view-relative coordinates to screen-relative coordinates 9429 * 9430 * @param rect The rectangle to be mapped 9431 * @param clipToParent Whether to clip child bounds to the parent ones. 9432 * @hide 9433 */ 9434 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 9435 mapRectFromViewToWindowCoords(rect, clipToParent); 9436 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 9437 } 9438 9439 /** 9440 * Map a rectangle from view-relative coordinates to window-relative coordinates 9441 * 9442 * @param rect The rectangle to be mapped 9443 * @param clipToParent Whether to clip child bounds to the parent ones. 9444 * @hide 9445 */ 9446 public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) { 9447 if (!hasIdentityMatrix()) { 9448 getMatrix().mapRect(rect); 9449 } 9450 9451 rect.offset(mLeft, mTop); 9452 9453 ViewParent parent = mParent; 9454 while (parent instanceof View) { 9455 View parentView = (View) parent; 9456 9457 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 9458 9459 if (clipToParent) { 9460 rect.left = Math.max(rect.left, 0); 9461 rect.top = Math.max(rect.top, 0); 9462 rect.right = Math.min(rect.right, parentView.getWidth()); 9463 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 9464 } 9465 9466 if (!parentView.hasIdentityMatrix()) { 9467 parentView.getMatrix().mapRect(rect); 9468 } 9469 9470 rect.offset(parentView.mLeft, parentView.mTop); 9471 9472 parent = parentView.mParent; 9473 } 9474 9475 if (parent instanceof ViewRootImpl) { 9476 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 9477 rect.offset(0, -viewRootImpl.mCurScrollY); 9478 } 9479 } 9480 9481 /** 9482 * Return the class name of this object to be used for accessibility purposes. 9483 * Subclasses should only override this if they are implementing something that 9484 * should be seen as a completely new class of view when used by accessibility, 9485 * unrelated to the class it is deriving from. This is used to fill in 9486 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 9487 */ 9488 public CharSequence getAccessibilityClassName() { 9489 return View.class.getName(); 9490 } 9491 9492 /** 9493 * Called when assist structure is being retrieved from a view as part of 9494 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 9495 * @param structure Fill in with structured view data. The default implementation 9496 * fills in all data that can be inferred from the view itself. 9497 */ 9498 public void onProvideStructure(ViewStructure structure) { 9499 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 9500 } 9501 9502 /** 9503 * Populates a {@link ViewStructure} to fullfil an autofill request. 9504 * 9505 * <p>The structure should contain at least the following properties: 9506 * <ul> 9507 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 9508 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 9509 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 9510 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 9511 * </ul> 9512 * 9513 * <p>It's also recommended to set the following properties - the more properties the structure 9514 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 9515 * using the structure: 9516 * 9517 * <ul> 9518 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 9519 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 9520 * view can only be filled with predefined values (typically used when the autofill type 9521 * is {@link #AUTOFILL_TYPE_LIST}). 9522 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 9523 * <li>Class name ({@link ViewStructure#setClassName(String)}). 9524 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 9525 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 9526 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 9527 * opacity ({@link ViewStructure#setOpaque(boolean)}). 9528 * <li>For views representing text fields, text properties such as the text itself 9529 * ({@link ViewStructure#setText(CharSequence)}), text hints 9530 * ({@link ViewStructure#setHint(CharSequence)}, input type 9531 * ({@link ViewStructure#setInputType(int)}), 9532 * <li>For views representing HTML nodes, its web domain 9533 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 9534 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 9535 * </ul> 9536 * 9537 * <p>The default implementation of this method already sets most of these properties based on 9538 * related {@link View} methods (for example, the autofill id is set using 9539 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 9540 * and views in the standard Android widgets library also override it to set their 9541 * relevant properties (for example, {@link android.widget.TextView} already sets the text 9542 * properties), so it's recommended to only override this method 9543 * (and call {@code super.onProvideAutofillStructure()}) when: 9544 * 9545 * <ul> 9546 * <li>The view contents does not include PII (Personally Identifiable Information), so it 9547 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 9548 * <li>The view can only be autofilled with predefined options, so it can call 9549 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 9550 * </ul> 9551 * 9552 * <p><b>Note:</b> The {@code left} and {@code top} values set in 9553 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 9554 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 9555 * 9556 * <p>Views support the Autofill Framework mainly by: 9557 * <ul> 9558 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9559 * <li>Notifying the Android System when the view value changed by calling 9560 * {@link AutofillManager#notifyValueChanged(View)}. 9561 * <li>Implementing the methods that autofill the view. 9562 * </ul> 9563 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 9564 * for the latter. 9565 * 9566 * @param structure fill in with structured view data for autofill purposes. 9567 * @param flags optional flags. 9568 * 9569 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9570 */ 9571 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 9572 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 9573 } 9574 9575 /** 9576 * Populates a {@link ViewStructure} for content capture. 9577 * 9578 * <p>This method is called after a view that is eligible for content capture 9579 * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is 9580 * enabled for the user, and the activity rendering the view is enabled for content capture) 9581 * is laid out and is visible. The populated structure is then passed to the service through 9582 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 9583 * 9584 * <p>The default implementation of this method sets the most relevant properties based on 9585 * related {@link View} methods, and views in the standard Android widgets library also 9586 * override it to set their relevant properties. Therefore, if overriding this method, it 9587 * is recommended to call {@code super.onProvideContentCaptureStructure()}. 9588 * 9589 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 9590 * the node representing this view and return right away, then asynchronously report (not 9591 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 9592 * changed by calling 9593 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 9594 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 9595 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 9596 * respectively. The structure for a child must be created using 9597 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 9598 * {@code autofillId} for a child can be obtained either through 9599 * {@code childStructure.getAutofillId()} or 9600 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 9601 * 9602 * <p>When the virtual view hierarchy represents a web page, you should also: 9603 * 9604 * <ul> 9605 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 9606 * capture events should be generate for that URL. 9607 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 9608 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 9609 * that subtree. 9610 * </ul> 9611 * 9612 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 9613 * <ul> 9614 * <li>{@link ViewStructure#setChildCount(int)} 9615 * <li>{@link ViewStructure#addChildCount(int)} 9616 * <li>{@link ViewStructure#getChildCount()} 9617 * <li>{@link ViewStructure#newChild(int)} 9618 * <li>{@link ViewStructure#asyncNewChild(int)} 9619 * <li>{@link ViewStructure#asyncCommit()} 9620 * <li>{@link ViewStructure#setWebDomain(String)} 9621 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 9622 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 9623 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 9624 * <li>{@link ViewStructure#setAlpha(float)} 9625 * <li>{@link ViewStructure#setElevation(float)} 9626 * <li>{@link ViewStructure#setTransformation(Matrix)} 9627 * 9628 * </ul> 9629 */ 9630 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 9631 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 9632 } 9633 9634 /** @hide */ 9635 protected void onProvideStructure(@NonNull ViewStructure structure, 9636 @ViewStructureType int viewFor, int flags) { 9637 final int id = mID; 9638 if (id != NO_ID && !isViewIdGenerated(id)) { 9639 String pkg, type, entry; 9640 try { 9641 final Resources res = getResources(); 9642 entry = res.getResourceEntryName(id); 9643 type = res.getResourceTypeName(id); 9644 pkg = res.getResourcePackageName(id); 9645 } catch (Resources.NotFoundException e) { 9646 entry = type = pkg = null; 9647 } 9648 structure.setId(id, pkg, type, entry); 9649 } else { 9650 structure.setId(id, null, null, null); 9651 } 9652 9653 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9654 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 9655 final @AutofillType int autofillType = getAutofillType(); 9656 // Don't need to fill autofill info if view does not support it. 9657 // For example, only TextViews that are editable support autofill 9658 if (autofillType != AUTOFILL_TYPE_NONE) { 9659 structure.setAutofillType(autofillType); 9660 structure.setAutofillHints(getAutofillHints()); 9661 structure.setAutofillValue(getAutofillValue()); 9662 structure.setIsCredential(isCredential()); 9663 } 9664 if (getViewCredentialHandler() != null) { 9665 structure.setPendingCredentialRequest( 9666 getViewCredentialHandler().getRequest(), 9667 getViewCredentialHandler().getCallback()); 9668 } 9669 structure.setImportantForAutofill(getImportantForAutofill()); 9670 structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); 9671 } 9672 9673 int ignoredParentLeft = 0; 9674 int ignoredParentTop = 0; 9675 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9676 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 9677 View parentGroup = null; 9678 9679 ViewParent viewParent = getParent(); 9680 if (viewParent instanceof View) { 9681 parentGroup = (View) viewParent; 9682 } 9683 9684 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 9685 ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX; 9686 ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY; 9687 9688 viewParent = parentGroup.getParent(); 9689 if (viewParent instanceof View) { 9690 parentGroup = (View) viewParent; 9691 } else { 9692 break; 9693 } 9694 } 9695 } 9696 9697 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 9698 mRight - mLeft, mBottom - mTop); 9699 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 9700 if (!hasIdentityMatrix()) { 9701 structure.setTransformation(getMatrix()); 9702 } 9703 structure.setElevation(getZ()); 9704 } 9705 structure.setVisibility(getVisibility()); 9706 structure.setEnabled(isEnabled()); 9707 if (isClickable()) { 9708 structure.setClickable(true); 9709 } 9710 if (isFocusable()) { 9711 structure.setFocusable(true); 9712 } 9713 if (isFocused()) { 9714 structure.setFocused(true); 9715 } 9716 if (isAccessibilityFocused()) { 9717 structure.setAccessibilityFocused(true); 9718 } 9719 if (isSelected()) { 9720 structure.setSelected(true); 9721 } 9722 if (isActivated()) { 9723 structure.setActivated(true); 9724 } 9725 if (isLongClickable()) { 9726 structure.setLongClickable(true); 9727 } 9728 if (this instanceof Checkable) { 9729 structure.setCheckable(true); 9730 if (((Checkable)this).isChecked()) { 9731 structure.setChecked(true); 9732 } 9733 } 9734 if (isOpaque()) { 9735 structure.setOpaque(true); 9736 } 9737 if (isContextClickable()) { 9738 structure.setContextClickable(true); 9739 } 9740 structure.setClassName(getAccessibilityClassName().toString()); 9741 structure.setContentDescription(getContentDescription()); 9742 } 9743 9744 /** 9745 * Called when assist structure is being retrieved from a view as part of 9746 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 9747 * generate additional virtual structure under this view. The default implementation 9748 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 9749 * view's virtual accessibility nodes, if any. You can override this for a more 9750 * optimal implementation providing this data. 9751 */ 9752 public void onProvideVirtualStructure(ViewStructure structure) { 9753 onProvideVirtualStructureCompat(structure, false); 9754 } 9755 9756 /** 9757 * Fallback implementation to populate a ViewStructure from accessibility state. 9758 * 9759 * @param structure The structure to populate. 9760 * @param forAutofill Whether the structure is needed for autofill. 9761 */ 9762 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 9763 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9764 if (provider != null) { 9765 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9766 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 9767 } 9768 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 9769 structure.setChildCount(1); 9770 final ViewStructure root = structure.newChild(0); 9771 if (info != null) { 9772 populateVirtualStructure(root, provider, info, forAutofill); 9773 info.recycle(); 9774 } else { 9775 Log.w(AUTOFILL_LOG_TAG, "AccessibilityNodeInfo is null."); 9776 } 9777 } 9778 } 9779 9780 /** 9781 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 9782 * request. 9783 * 9784 * <p>This method should be used when the view manages a virtual structure under this view. For 9785 * example, a view that draws input fields using {@link #draw(Canvas)}. 9786 * 9787 * <p>When implementing this method, subclasses must follow the rules below: 9788 * 9789 * <ul> 9790 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 9791 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 9792 * identifying the children in the virtual structure. 9793 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 9794 * exclude intermediate levels that are irrelevant for autofill; that would improve the 9795 * autofill performance. 9796 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 9797 * children. 9798 * <li>Set the autofill properties of the child structure as defined by 9799 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 9800 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 9801 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 9802 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 9803 * when the focused virtual child changed. 9804 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9805 * whether a given virtual view is visible to the user in order to support triggering 9806 * save when all views of interest go away. 9807 * <li>Call 9808 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9809 * when the value of a virtual child changed. 9810 * <li>Call {@link 9811 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9812 * when the visibility of a virtual child changed. 9813 * <li>Call 9814 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9815 * child is clicked. 9816 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9817 * changed and the current context should be committed (for example, when the user tapped 9818 * a {@code SUBMIT} button in an HTML page). 9819 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9820 * changed and the current context should be canceled (for example, when the user tapped 9821 * a {@code CANCEL} button in an HTML page). 9822 * <li>Provide ways for users to manually request autofill by calling 9823 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9824 * <li>The {@code left} and {@code top} values set in 9825 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9826 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9827 * structure. 9828 * </ul> 9829 * 9830 * <p>Views with virtual children support the Autofill Framework mainly by: 9831 * <ul> 9832 * <li>Providing the metadata defining what the virtual children mean and how they can be 9833 * autofilled. 9834 * <li>Implementing the methods that autofill the virtual children. 9835 * </ul> 9836 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9837 * for the latter. 9838 * 9839 * @param structure fill in with virtual children data for autofill purposes. 9840 * @param flags optional flags. 9841 * 9842 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9843 */ 9844 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9845 if (mContext.isAutofillCompatibilityEnabled()) { 9846 onProvideVirtualStructureCompat(structure, true); 9847 } 9848 } 9849 9850 /** 9851 * Sets the listener to be {@link #performReceiveContent used} to handle insertion of 9852 * content into this view. 9853 * 9854 * <p>Depending on the type of view, this listener may be invoked for different scenarios. For 9855 * example, for an editable {@link android.widget.TextView}, this listener will be invoked for 9856 * the following scenarios: 9857 * <ol> 9858 * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the 9859 * insertion/selection menu) 9860 * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent}) 9861 * <li>Drag and drop (drop events from {@link #onDragEvent}) 9862 * <li>Autofill 9863 * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT} 9864 * </ol> 9865 * 9866 * <p>When setting a listener, clients must also declare the accepted MIME types. 9867 * The listener will still be invoked even if the MIME type of the content is not one of the 9868 * declared MIME types (e.g. if the user pastes content whose type is not one of the declared 9869 * MIME types). 9870 * In that case, the listener may reject the content (defer to the default platform behavior) 9871 * or execute some other fallback logic (e.g. show an appropriate message to the user). 9872 * The declared MIME types serve as a hint to allow different features to optionally alter 9873 * their behavior. For example, a soft keyboard may optionally choose to hide its UI for 9874 * inserting GIFs for a particular input field if the MIME types set here for that field 9875 * don't include "image/gif" or "image/*". 9876 * 9877 * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC 9878 * MIME types. As a result, you should always write your MIME types with lowercase letters, 9879 * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9880 * lowercase. 9881 * 9882 * @param mimeTypes The MIME types accepted by the given listener. These may use patterns 9883 * such as "image/*", but may not start with a wildcard. This argument must 9884 * not be null or empty if a non-null listener is passed in. 9885 * @param listener The listener to use. This can be null to reset to the default behavior. 9886 */ 9887 public void setOnReceiveContentListener( 9888 @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, 9889 @Nullable OnReceiveContentListener listener) { 9890 if (listener != null) { 9891 Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, 9892 "When the listener is set, MIME types must also be set"); 9893 } 9894 if (mimeTypes != null) { 9895 Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")), 9896 "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes)); 9897 } 9898 mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; 9899 getListenerInfo().mOnReceiveContentListener = listener; 9900 } 9901 9902 /** 9903 * Receives the given content. If no listener is set, invokes {@link #onReceiveContent}. If a 9904 * listener is {@link #setOnReceiveContentListener set}, invokes the listener instead; if the 9905 * listener returns a non-null result, invokes {@link #onReceiveContent} to handle it. 9906 * 9907 * @param payload The content to insert and related metadata. 9908 * 9909 * @return The portion of the passed-in content that was not accepted (may be all, some, or none 9910 * of the passed-in content). 9911 */ 9912 @Nullable 9913 public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { 9914 final OnReceiveContentListener listener = (mListenerInfo == null) ? null 9915 : getListenerInfo().mOnReceiveContentListener; 9916 if (listener != null) { 9917 final ContentInfo remaining = listener.onReceiveContent(this, payload); 9918 return (remaining == null) ? null : onReceiveContent(remaining); 9919 } 9920 return onReceiveContent(payload); 9921 } 9922 9923 /** 9924 * Implements the default behavior for receiving content for this type of view. The default 9925 * view implementation is a no-op (returns the passed-in content without acting on it). 9926 * 9927 * <p>Widgets should override this method to define their default behavior for receiving 9928 * content. Apps should {@link #setOnReceiveContentListener set a listener} to provide 9929 * app-specific handling for receiving content. 9930 * 9931 * <p>See {@link #setOnReceiveContentListener} and {@link #performReceiveContent} for more info. 9932 * 9933 * @param payload The content to insert and related metadata. 9934 * 9935 * @return The portion of the passed-in content that was not handled (may be all, some, or none 9936 * of the passed-in content). 9937 */ 9938 @Nullable 9939 public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { 9940 return payload; 9941 } 9942 9943 /** 9944 * Returns the MIME types accepted by {@link #performReceiveContent} for this view, as 9945 * configured via {@link #setOnReceiveContentListener}. By default returns null. 9946 * 9947 * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft 9948 * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For 9949 * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular 9950 * input field if the MIME types returned here for that field don't include "image/gif" or 9951 * "image/*". 9952 * 9953 * <p>Note: Comparisons of MIME types should be performed using utilities such as 9954 * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to 9955 * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching 9956 * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result, 9957 * you should always write your MIME types with lowercase letters, or use 9958 * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9959 * lowercase. 9960 * 9961 * @return The MIME types accepted by {@link #performReceiveContent} for this view (may 9962 * include patterns such as "image/*"). 9963 */ 9964 @SuppressLint("NullableCollection") 9965 @Nullable 9966 public String[] getReceiveContentMimeTypes() { 9967 return mReceiveContentMimeTypes; 9968 } 9969 9970 /** 9971 * Automatically fills the content of this view with the {@code value}. 9972 * 9973 * <p>Views support the Autofill Framework mainly by: 9974 * <ul> 9975 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9976 * <li>Implementing the methods that autofill the view. 9977 * </ul> 9978 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 9979 * this method is responsible for latter. 9980 * 9981 * <p>This method does nothing by default, but when overridden it typically: 9982 * <ol> 9983 * <li>Checks if the provided value matches the expected type (which is defined by 9984 * {@link #getAutofillType()}). 9985 * <li>Checks if the view is editable - if it isn't, it should return right away. 9986 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 9987 * <li>Pass the actual value to the equivalent setter in the view. 9988 * </ol> 9989 * 9990 * <p>For example, a text-field view could implement the method this way: 9991 * 9992 * <pre class="prettyprint"> 9993 * @Override 9994 * public void autofill(AutofillValue value) { 9995 * if (!value.isText() || !this.isEditable()) { 9996 * return; 9997 * } 9998 * CharSequence text = value.getTextValue(); 9999 * if (text != null) { 10000 * this.setText(text); 10001 * } 10002 * } 10003 * </pre> 10004 * 10005 * <p>If the value is updated asynchronously, the next call to 10006 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 10007 * changed to the autofilled value. If not, the view will not be considered autofilled. 10008 * 10009 * <p><b>Note:</b> After this method is called, the value returned by 10010 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 10011 * view will not be highlighted as autofilled. 10012 * 10013 * @param value value to be autofilled. 10014 */ 10015 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 10016 } 10017 10018 /** 10019 * Automatically fills the content of the virtual children within this view. 10020 * 10021 * <p>Views with virtual children support the Autofill Framework mainly by: 10022 * <ul> 10023 * <li>Providing the metadata defining what the virtual children mean and how they can be 10024 * autofilled. 10025 * <li>Implementing the methods that autofill the virtual children. 10026 * </ul> 10027 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 10028 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 10029 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 10030 * 10031 * <p>If a child value is updated asynchronously, the next call to 10032 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 10033 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 10034 * considered autofilled. 10035 * 10036 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 10037 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 10038 * changes. 10039 * 10040 * @param values map of values to be autofilled, keyed by virtual child id. 10041 * 10042 * @attr ref android.R.styleable#Theme_autofilledHighlight 10043 */ 10044 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 10045 if (!mContext.isAutofillCompatibilityEnabled()) { 10046 return; 10047 } 10048 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10049 if (provider == null) { 10050 return; 10051 } 10052 final int valueCount = values.size(); 10053 for (int i = 0; i < valueCount; i++) { 10054 final AutofillValue value = values.valueAt(i); 10055 if (value.isText()) { 10056 final int virtualId = values.keyAt(i); 10057 final CharSequence text = value.getTextValue(); 10058 final Bundle arguments = new Bundle(); 10059 arguments.putCharSequence( 10060 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 10061 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 10062 } 10063 } 10064 } 10065 10066 /** 10067 * @hide 10068 */ 10069 public void onGetCredentialResponse(GetCredentialResponse response) { 10070 if (getPendingCredentialCallback() == null) { 10071 Log.w(AUTOFILL_LOG_TAG, "onGetCredentialResponse called but no callback found"); 10072 return; 10073 } 10074 getPendingCredentialCallback().onResult(response); 10075 } 10076 10077 /** 10078 * @hide 10079 */ 10080 public void onGetCredentialException(String errorType, String errorMsg) { 10081 if (getPendingCredentialCallback() == null) { 10082 Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found"); 10083 return; 10084 } 10085 getPendingCredentialCallback().onError(new GetCredentialException(errorType, errorMsg)); 10086 } 10087 10088 /** 10089 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 10090 * 10091 * <p>The autofill id is created on demand, unless it is explicitly set by 10092 * {@link #setAutofillId(AutofillId)}. 10093 * 10094 * <p>See {@link #setAutofillId(AutofillId)} for more info. 10095 * 10096 * @return The View's autofill id. 10097 */ 10098 public final AutofillId getAutofillId() { 10099 if (mAutofillId == null) { 10100 // The autofill id needs to be unique, but its value doesn't matter, 10101 // so it's better to reuse the accessibility id to save space. 10102 mAutofillId = new AutofillId(getAutofillViewId()); 10103 } 10104 return mAutofillId; 10105 } 10106 10107 /** 10108 * Returns the {@link GetCredentialRequest} associated with the view. 10109 * If the return value is null, that means no request has been set 10110 * on the view and no {@link CredentialManager} flow will be invoked 10111 * when this view is focused. Traditioanl autofill flows will still 10112 * work, autofilling content if applicable, from 10113 * the active {@link android.service.autofill.AutofillService} on 10114 * the device. 10115 * 10116 * <p>See {@link #setPendingCredentialRequest} for more info. 10117 * 10118 * @return The credential request associated with this View. 10119 */ 10120 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 10121 @Nullable 10122 public final GetCredentialRequest getPendingCredentialRequest() { 10123 if (mViewCredentialHandler == null) { 10124 return null; 10125 } 10126 return mViewCredentialHandler.getRequest(); 10127 } 10128 10129 10130 /** 10131 * Returns the callback that has previously been set up on this view through 10132 * the {@link #setPendingCredentialRequest} API. 10133 * If the return value is null, that means no callback, or request, has been set 10134 * on the view and no {@link CredentialManager} flow will be invoked 10135 * when this view is focused. Traditioanl autofill flows will still 10136 * work, and autofillable content will still be returned through the 10137 * {@link #autofill(AutofillValue)} )} API. 10138 * 10139 * <p>See {@link #setPendingCredentialRequest} for more info. 10140 * 10141 * @return The callback associated with this view that will be invoked on a response from 10142 * {@link CredentialManager} . 10143 */ 10144 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 10145 @Nullable 10146 public final OutcomeReceiver<GetCredentialResponse, 10147 GetCredentialException> getPendingCredentialCallback() { 10148 if (mViewCredentialHandler == null) { 10149 return null; 10150 } 10151 return mViewCredentialHandler.getCallback(); 10152 } 10153 10154 /** 10155 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 10156 * 10157 * <p>The autofill id is created on demand, and this method should only be called when a view is 10158 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 10159 * that method creates a snapshot of the view that is passed along to the autofill service. 10160 * 10161 * <p>This method is typically used when view subtrees are recycled to represent different 10162 * content* —in this case, the autofill id can be saved before the view content is swapped 10163 * out, and restored later when it's swapped back in. For example: 10164 * 10165 * <pre> 10166 * EditText reusableView = ...; 10167 * ViewGroup parentView = ...; 10168 * AutofillManager afm = ...; 10169 * 10170 * // Swap out the view and change its contents 10171 * AutofillId oldId = reusableView.getAutofillId(); 10172 * CharSequence oldText = reusableView.getText(); 10173 * parentView.removeView(reusableView); 10174 * AutofillId newId = afm.getNextAutofillId(); 10175 * reusableView.setText("New I am"); 10176 * reusableView.setAutofillId(newId); 10177 * parentView.addView(reusableView); 10178 * 10179 * // Later, swap the old content back in 10180 * parentView.removeView(reusableView); 10181 * reusableView.setAutofillId(oldId); 10182 * reusableView.setText(oldText); 10183 * parentView.addView(reusableView); 10184 * </pre> 10185 * 10186 * <p>NOTE: If this view is a descendant of an {@link android.widget.AdapterView}, the system 10187 * may reset its autofill id when this view is recycled. If the autofill ids need to be stable, 10188 * they should be set again in 10189 * {@link android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)}. 10190 * 10191 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 10192 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 10193 * obtained through {@link #getAutofillId()}), or a new value obtained through 10194 * {@link AutofillManager#getNextAutofillId()}. 10195 * 10196 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 10197 * a window}. 10198 * 10199 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 10200 */ 10201 public void setAutofillId(@Nullable AutofillId id) { 10202 // TODO(b/37566627): add unit / CTS test for all possible combinations below 10203 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10204 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 10205 } 10206 if (isAttachedToWindow()) { 10207 throw new IllegalStateException("Cannot set autofill id when view is attached"); 10208 } 10209 if (id != null && !id.isNonVirtual()) { 10210 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 10211 } 10212 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 10213 // Ignore reset because it was never explicitly set before. 10214 return; 10215 } 10216 mAutofillId = id; 10217 if (id != null) { 10218 mAutofillViewId = id.getViewId(); 10219 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 10220 } else { 10221 mAutofillViewId = NO_ID; 10222 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 10223 } 10224 } 10225 10226 /** 10227 * Forces a reset of the autofill ids of the subtree rooted at this view. Like calling 10228 * {@link #setAutofillId(AutofillId) setAutofillId(null)} for each view, but works even if the 10229 * views are attached to a window. 10230 * 10231 * <p>This is useful if the views are being recycled, since an autofill id should uniquely 10232 * identify a particular piece of content. 10233 * 10234 * @hide 10235 */ 10236 public void resetSubtreeAutofillIds() { 10237 if (mAutofillViewId == NO_ID) { 10238 return; 10239 } 10240 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10241 Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 10242 } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10243 Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 10244 } 10245 mAutofillId = null; 10246 mAutofillViewId = NO_ID; 10247 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 10248 } 10249 10250 /** 10251 * Describes the autofill type of this view, so an 10252 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 10253 * when autofilling the view. 10254 * 10255 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 10256 * support the Autofill Framework. 10257 * 10258 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 10259 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 10260 * 10261 * @see #onProvideAutofillStructure(ViewStructure, int) 10262 * @see #autofill(AutofillValue) 10263 */ 10264 public @AutofillType int getAutofillType() { 10265 return AUTOFILL_TYPE_NONE; 10266 } 10267 10268 /** 10269 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 10270 * to autofill the view with the user's data. 10271 * 10272 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 10273 * 10274 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 10275 * {@code null} if no hints were set. 10276 * 10277 * @attr ref android.R.styleable#View_autofillHints 10278 */ 10279 @ViewDebug.ExportedProperty() 10280 @InspectableProperty 10281 @Nullable public String[] getAutofillHints() { 10282 return mAutofillHints; 10283 } 10284 10285 /** 10286 * @hide 10287 */ 10288 @TestApi 10289 public boolean isAutofilled() { 10290 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 10291 } 10292 10293 /** 10294 * @hide 10295 */ 10296 public boolean hideAutofillHighlight() { 10297 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 10298 } 10299 10300 /** 10301 * Gets the {@link View}'s current autofill value. 10302 * 10303 * <p>By default returns {@code null}, but subclasses should override it and return an 10304 * appropriate value to properly support the Autofill Framework. 10305 * 10306 * @see #onProvideAutofillStructure(ViewStructure, int) 10307 * @see #autofill(AutofillValue) 10308 */ 10309 @Nullable 10310 public AutofillValue getAutofillValue() { 10311 return null; 10312 } 10313 10314 /** 10315 * Gets the mode for determining whether this view is important for autofill. 10316 * 10317 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 10318 * info about this mode. 10319 * 10320 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 10321 * {@link #setImportantForAutofill(int)}. 10322 * 10323 * @attr ref android.R.styleable#View_importantForAutofill 10324 */ 10325 @ViewDebug.ExportedProperty(mapping = { 10326 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 10327 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 10328 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 10329 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 10330 to = "yesExcludeDescendants"), 10331 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 10332 to = "noExcludeDescendants")}) 10333 @InspectableProperty(enumMapping = { 10334 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 10335 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 10336 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 10337 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 10338 name = "yesExcludeDescendants"), 10339 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 10340 name = "noExcludeDescendants"), 10341 }) 10342 public @AutofillImportance int getImportantForAutofill() { 10343 return (mPrivateFlags3 10344 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 10345 } 10346 10347 /** 10348 * Sets the mode for determining whether this view is considered important for autofill. 10349 * 10350 * <p>The platform determines the importance for autofill automatically but you 10351 * can use this method to customize the behavior. For example: 10352 * 10353 * <ol> 10354 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 10355 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 10356 * <li>When both the view and its children are irrelevant for autofill (for example, the root 10357 * view of an activity containing a spreadhseet editor), it should be 10358 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 10359 * <li>When the view content is relevant for autofill but its children aren't (for example, 10360 * a credit card expiration date represented by a custom view that overrides the proper 10361 * autofill methods and has 2 children representing the month and year), it should 10362 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 10363 * </ol> 10364 * 10365 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 10366 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 10367 * children) will not be used for autofill purpose; for example, when the user explicitly 10368 * makes an autofill request, all views are included in the ViewStructure, and starting in 10369 * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} the system uses other factors along 10370 * with importance to determine the autofill behavior. See {@link #isImportantForAutofill()} 10371 * for more details about how the View's importance for autofill is used. 10372 * 10373 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 10374 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 10375 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 10376 * 10377 * @attr ref android.R.styleable#View_importantForAutofill 10378 */ 10379 public void setImportantForAutofill(@AutofillImportance int mode) { 10380 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 10381 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 10382 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 10383 } 10384 10385 /** 10386 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 10387 * associated with this view is considered important for autofill purposes. 10388 * 10389 * <p>Generally speaking, a view is important for autofill if: 10390 * <ol> 10391 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 10392 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 10393 * determine how other views can be autofilled. 10394 * <ol> 10395 * 10396 * <p>For example, view containers should typically return {@code false} for performance reasons 10397 * (since the important info is provided by their children), but if its properties have relevant 10398 * information (for example, a resource id called {@code credentials}, it should return 10399 * {@code true}. On the other hand, views representing labels or editable fields should 10400 * typically return {@code true}, but in some cases they could return {@code false} 10401 * (for example, if they're part of a "Captcha" mechanism). 10402 * 10403 * <p>The value returned by this method depends on the value returned by 10404 * {@link #getImportantForAutofill()}: 10405 * 10406 * <ol> 10407 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 10408 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 10409 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 10410 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 10411 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 10412 * that can return {@code true} in some cases (like a container with a resource id), 10413 * but {@code false} in most. 10414 * <li>otherwise, it returns {@code false}. 10415 * </ol> 10416 * 10417 * <p> The behavior of importances depends on Android version: 10418 * <ol> 10419 * <li>For {@link android.os.Build.VERSION_CODES#TIRAMISU} and below: 10420 * <ol> 10421 * <li>When a view is considered important for autofill: 10422 * <ol> 10423 * <li>The view might automatically trigger an autofill request when focused on. 10424 * <li>The contents of the view are included in the {@link ViewStructure} used in an 10425 * autofill request. 10426 * </ol> 10427 * <li>On the other hand, when a view is considered not important for autofill: 10428 * <ol> 10429 * <li>The view never automatically triggers autofill requests, but it can trigger a 10430 * manual request through {@link AutofillManager#requestAutofill(View)}. 10431 * <li>The contents of the view are not included in the {@link ViewStructure} used in 10432 * an autofill request, unless the request has the 10433 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 10434 * </ol> 10435 * </ol> 10436 * <li>For {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above: 10437 * <ol> 10438 * <li>The system uses importance, along with other view properties and other optimization 10439 * factors, to determine if a view should trigger autofill on focus. 10440 * <li>The contents of {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, 10441 * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@link #IMPORTANT_FOR_AUTOFILL_NO}, 10442 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, and 10443 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} views will be included in the 10444 * {@link ViewStructure} used in an autofill request. 10445 * </ol> 10446 * </ol> 10447 * 10448 * @return whether the view is considered important for autofill. 10449 * 10450 * @see #setImportantForAutofill(int) 10451 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 10452 * @see #IMPORTANT_FOR_AUTOFILL_YES 10453 * @see #IMPORTANT_FOR_AUTOFILL_NO 10454 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 10455 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 10456 * @see AutofillManager#requestAutofill(View) 10457 */ 10458 public final boolean isImportantForAutofill() { 10459 // Check parent mode to ensure we're not hidden. 10460 ViewParent parent = mParent; 10461 while (parent instanceof View) { 10462 final int parentImportance = ((View) parent).getImportantForAutofill(); 10463 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 10464 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 10465 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10466 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 10467 + "because parent " + parent + "'s importance is " + parentImportance); 10468 } 10469 return false; 10470 } 10471 parent = parent.getParent(); 10472 } 10473 10474 final int importance = getImportantForAutofill(); 10475 10476 // First, check the explicit states. 10477 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 10478 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 10479 return true; 10480 } 10481 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 10482 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 10483 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10484 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 10485 + "because its importance is " + importance); 10486 } 10487 return false; 10488 } 10489 10490 // Then use some heuristics to handle AUTO. 10491 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 10492 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 10493 + this); 10494 return false; 10495 } 10496 10497 // Always include views that have an explicit resource id. 10498 final int id = mID; 10499 if (id != NO_ID && !isViewIdGenerated(id)) { 10500 final Resources res = getResources(); 10501 String entry = null; 10502 String pkg = null; 10503 try { 10504 entry = res.getResourceEntryName(id); 10505 pkg = res.getResourcePackageName(id); 10506 } catch (Resources.NotFoundException e) { 10507 // ignore 10508 } 10509 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 10510 return true; 10511 } 10512 } 10513 10514 // If the app developer explicitly set hints for it, it's important. 10515 if (getAutofillHints() != null) { 10516 return true; 10517 } 10518 10519 // Otherwise, assume it's not important... 10520 return false; 10521 } 10522 10523 /** 10524 * Sets content sensitivity mode to determine whether this view displays sensitive content 10525 * (e.g. username, password etc.). The system will improve user privacy i.e. hide content 10526 * drawn by a sensitive view from screen sharing and recording. 10527 * 10528 * <p> The window hosting a sensitive view will be marked as secure during an active media 10529 * projection session. This would be equivalent to applying 10530 * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. 10531 * 10532 * @param mode {@link #CONTENT_SENSITIVITY_AUTO}, {@link #CONTENT_SENSITIVITY_NOT_SENSITIVE} 10533 * or {@link #CONTENT_SENSITIVITY_SENSITIVE} 10534 */ 10535 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 10536 public final void setContentSensitivity(@ContentSensitivity int mode) { 10537 mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK; 10538 mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT) 10539 & PFLAG4_CONTENT_SENSITIVITY_MASK); 10540 if (sensitiveContentAppProtection()) { 10541 updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); 10542 } 10543 } 10544 10545 /** 10546 * Gets content sensitivity mode to determine whether this view displays sensitive content. 10547 * 10548 * <p>See {@link #setContentSensitivity(int)} and 10549 * {@link #isContentSensitive()} for more info about this mode. 10550 * 10551 * @return {@link #CONTENT_SENSITIVITY_AUTO} by default, or value passed to 10552 * {@link #setContentSensitivity(int)}. 10553 */ 10554 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 10555 public @ContentSensitivity final int getContentSensitivity() { 10556 return (mPrivateFlags4 & PFLAG4_CONTENT_SENSITIVITY_MASK) 10557 >> PFLAG4_CONTENT_SENSITIVITY_SHIFT; 10558 } 10559 10560 /** 10561 * Returns whether this view displays sensitive content, based 10562 * on the value explicitly set by {@link #setContentSensitivity(int)}. 10563 * 10564 * @return whether the view displays sensitive content. 10565 * 10566 * @see #setContentSensitivity(int) 10567 * @see #CONTENT_SENSITIVITY_AUTO 10568 * @see #CONTENT_SENSITIVITY_SENSITIVE 10569 * @see #CONTENT_SENSITIVITY_NOT_SENSITIVE 10570 */ 10571 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 10572 public final boolean isContentSensitive() { 10573 final int contentSensitivity = getContentSensitivity(); 10574 if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) { 10575 return true; 10576 } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) { 10577 return false; 10578 } else if (sensitiveContentAppProtection()) { 10579 return SensitiveAutofillHintsHelper 10580 .containsSensitiveAutofillHint(getAutofillHints()); 10581 } 10582 return false; 10583 } 10584 10585 /** 10586 * Helper used to track sensitive views when they are added or removed from the window 10587 * based on whether it's laid out and visible. 10588 * 10589 * <p>This method is called from many places (visibility changed, view laid out, view attached 10590 * or detached to/from window, etc...) 10591 */ 10592 private void updateSensitiveViewsCountIfNeeded(boolean appeared) { 10593 if (!sensitiveContentAppProtection() || mAttachInfo == null) { 10594 return; 10595 } 10596 10597 if (appeared && isContentSensitive()) { 10598 if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) { 10599 mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE; 10600 mAttachInfo.increaseSensitiveViewsCount(); 10601 } 10602 } else { 10603 if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) { 10604 mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE; 10605 mAttachInfo.decreaseSensitiveViewsCount(); 10606 } 10607 } 10608 } 10609 10610 /** 10611 * Gets the mode for determining whether this view is important for content capture. 10612 * 10613 * <p>See {@link #setImportantForContentCapture(int)} and 10614 * {@link #isImportantForContentCapture()} for more info about this mode. 10615 * 10616 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 10617 * {@link #setImportantForContentCapture(int)}. 10618 * 10619 * @attr ref android.R.styleable#View_importantForContentCapture 10620 */ 10621 @ViewDebug.ExportedProperty(mapping = { 10622 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 10623 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 10624 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 10625 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 10626 to = "yesExcludeDescendants"), 10627 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 10628 to = "noExcludeDescendants")}) 10629 @InspectableProperty(enumMapping = { 10630 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 10631 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 10632 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 10633 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 10634 name = "yesExcludeDescendants"), 10635 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 10636 name = "noExcludeDescendants"), 10637 }) 10638 public @ContentCaptureImportance int getImportantForContentCapture() { 10639 // NOTE: the important for content capture values were the first flags added and are set in 10640 // the rightmost position, so we don't need to shift them 10641 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 10642 } 10643 10644 /** 10645 * Sets the mode for determining whether this view is considered important for content capture. 10646 * 10647 * <p>The platform determines the importance for autofill automatically but you 10648 * can use this method to customize the behavior. Typically, a view that provides text should 10649 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 10650 * 10651 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 10652 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 10653 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 10654 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 10655 * 10656 * @attr ref android.R.styleable#View_importantForContentCapture 10657 */ 10658 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 10659 // Reset first 10660 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 10661 // Then set again 10662 // NOTE: the important for content capture values were the first flags added and are set in 10663 // the rightmost position, so we don't need to shift them 10664 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 10665 } 10666 10667 /** 10668 * Hints the Android System whether this view is considered important for content capture, based 10669 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 10670 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 10671 * 10672 * <p>See {@link ContentCaptureManager} for more info about content capture. 10673 * 10674 * @return whether the view is considered important for content capture. 10675 * 10676 * @see #setImportantForContentCapture(int) 10677 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 10678 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 10679 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 10680 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 10681 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10682 */ 10683 public final boolean isImportantForContentCapture() { 10684 boolean isImportant; 10685 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 10686 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 10687 return isImportant; 10688 } 10689 10690 isImportant = calculateIsImportantForContentCapture(); 10691 10692 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 10693 if (isImportant) { 10694 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 10695 } 10696 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 10697 return isImportant; 10698 } 10699 10700 /** 10701 * Calculates whether the flag is important for content capture so it can be used by 10702 * {@link #isImportantForContentCapture()} while the tree is traversed. 10703 */ 10704 private boolean calculateIsImportantForContentCapture() { 10705 // Check parent mode to ensure we're important 10706 ViewParent parent = mParent; 10707 while (parent instanceof View) { 10708 final int parentImportance = ((View) parent).getImportantForContentCapture(); 10709 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10710 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 10711 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10712 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 10713 + "content capture because parent " + parent + "'s importance is " 10714 + parentImportance); 10715 } 10716 return false; 10717 } 10718 parent = parent.getParent(); 10719 } 10720 10721 final int importance = getImportantForContentCapture(); 10722 10723 // First, check the explicit states. 10724 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 10725 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 10726 return true; 10727 } 10728 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10729 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 10730 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10731 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 10732 + "capture because its importance is " + importance); 10733 } 10734 return false; 10735 } 10736 10737 // Then use some heuristics to handle AUTO. 10738 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 10739 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 10740 + " on view " + this); 10741 return false; 10742 } 10743 10744 // View group is important if at least one children also is 10745 if (this instanceof ViewGroup) { 10746 final ViewGroup group = (ViewGroup) this; 10747 for (int i = 0; i < group.getChildCount(); i++) { 10748 final View child = group.getChildAt(i); 10749 if (child.isImportantForContentCapture()) { 10750 return true; 10751 } 10752 } 10753 } 10754 10755 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 10756 if (getAutofillHints() != null) { 10757 return true; 10758 } 10759 10760 // Otherwise, assume it's not important... 10761 return false; 10762 } 10763 10764 /** 10765 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 10766 * added, based on whether it's laid out and visible, and without knowing if the parent removed 10767 * it from the view hierarchy. 10768 * 10769 * <p>This method is called from many places (visibility changed, view laid out, view attached 10770 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 10771 * described below: 10772 * 10773 * <ol> 10774 * <li>It should only be called when content capture is enabled for the view. 10775 * <li>It must call viewAppeared() before viewDisappeared() 10776 * <li>viewAppeared() can only be called when the view is visible and laid out 10777 * <li>It should not call the same event twice. 10778 * </ol> 10779 */ 10780 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 10781 AttachInfo ai = mAttachInfo; 10782 // Skip it while the view is being laid out for the first time 10783 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 10784 10785 // First check if context has client, so it saves a service lookup when it doesn't 10786 if (mContext.getContentCaptureOptions() == null) return; 10787 10788 if (appeared) { 10789 // The appeared event stops sending to AiAi. 10790 // 1. The view is hidden. 10791 // 2. The same event was sent. 10792 // 3. The view is not laid out, and it will be laid out in the future. 10793 // Some recycled views cached its layout and a relayout is unnecessary. In this case, 10794 // system still needs to notify content capture the view appeared. When a view is 10795 // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED. 10796 final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() 10797 && getVisibility() == VISIBLE 10798 && !isLayoutRequested(); 10799 if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() 10800 || !(isLaidOut() || isRecycledWithoutRelayout)) { 10801 if (DEBUG_CONTENT_CAPTURE) { 10802 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 10803 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10804 + ", visible=" + (getVisibility() == VISIBLE) 10805 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10806 + ", alreadyNotifiedDisappeared=" 10807 + getNotifiedContentCaptureDisappeared()); 10808 } 10809 return; 10810 } 10811 } else { 10812 if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { 10813 if (DEBUG_CONTENT_CAPTURE) { 10814 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 10815 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10816 + ", visible=" + (getVisibility() == VISIBLE) 10817 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10818 + ", alreadyNotifiedDisappeared=" 10819 + getNotifiedContentCaptureDisappeared()); 10820 } 10821 return; 10822 } 10823 } 10824 10825 ContentCaptureSession session = getContentCaptureSession(); 10826 if (session == null) return; 10827 10828 // ... and finally at the view level 10829 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 10830 if (!isImportantForContentCapture()) return; 10831 10832 if (appeared) { 10833 setNotifiedContentCaptureAppeared(); 10834 10835 if (ai != null) { 10836 makeParentImportantAndNotifyAppearedEventIfNeed(); 10837 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10838 } else { 10839 if (DEBUG_CONTENT_CAPTURE) { 10840 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 10841 } 10842 } 10843 } else { 10844 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10845 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10846 10847 if (ai != null) { 10848 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10849 } else { 10850 if (DEBUG_CONTENT_CAPTURE) { 10851 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 10852 } 10853 } 10854 10855 // We reset any translation state as views may be re-used (e.g., as in ListView and 10856 // RecyclerView). We only need to do this for views important for content capture since 10857 // views unimportant for content capture won't be translated anyway. 10858 if (!isTemporarilyDetached()) { 10859 clearTranslationState(); 10860 } 10861 } 10862 } 10863 10864 private void makeParentImportantAndNotifyAppearedEventIfNeed() { 10865 // If view sent the appeared event to Content Capture, Content Capture also 10866 // would like to receive its parents' appeared events. So checks its parents 10867 // whether the appeared event is sent or not. If not, send the appeared event. 10868 final ViewParent parent = getParent(); 10869 if (parent instanceof View) { 10870 View p = ((View) parent); 10871 if (p.getNotifiedContentCaptureAppeared()) { 10872 return; 10873 } 10874 // Set important for content capture in the cache. 10875 p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 10876 p.notifyAppearedOrDisappearedForContentCaptureIfNeeded(/* appeared */ true); 10877 } 10878 } 10879 10880 private void setNotifiedContentCaptureAppeared() { 10881 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10882 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10883 } 10884 10885 /** @hide */ 10886 protected boolean getNotifiedContentCaptureAppeared() { 10887 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 10888 } 10889 10890 10891 private boolean getNotifiedContentCaptureDisappeared() { 10892 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; 10893 } 10894 10895 /** 10896 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 10897 * 10898 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 10899 * the content capture events associated with this view or its view hierarchy (if it's a 10900 * {@link ViewGroup}). 10901 * 10902 * <p>For example, if your activity is associated with a web domain, first you would need to 10903 * set the context for the main DOM: 10904 * 10905 * <pre> 10906 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 10907 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 10908 * </pre> 10909 * 10910 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 10911 * 10912 * <pre> 10913 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 10914 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 10915 * iframeView.setContentCaptureSession(iframeSession); 10916 * </pre> 10917 * 10918 * @param contentCaptureSession a session created by 10919 * {@link ContentCaptureSession#createContentCaptureSession( 10920 * android.view.contentcapture.ContentCaptureContext)}. 10921 */ 10922 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 10923 mContentCaptureSession = contentCaptureSession; 10924 } 10925 10926 /** 10927 * Gets the session used to notify content capture events. 10928 * 10929 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 10930 * inherited by ancestors, default session or {@code null} if content capture is disabled for 10931 * this view. 10932 */ 10933 @Nullable 10934 public final ContentCaptureSession getContentCaptureSession() { 10935 if (mContentCaptureSessionCached) { 10936 return mContentCaptureSession; 10937 } 10938 10939 mContentCaptureSession = getAndCacheContentCaptureSession(); 10940 mContentCaptureSessionCached = true; 10941 return mContentCaptureSession; 10942 } 10943 10944 @Nullable 10945 private ContentCaptureSession getAndCacheContentCaptureSession() { 10946 // First try the session explicitly set by setContentCaptureSession() 10947 if (mContentCaptureSession != null) { 10948 return mContentCaptureSession; 10949 } 10950 10951 // Then the session explicitly set in an ancestor 10952 ContentCaptureSession session = null; 10953 if (mParent instanceof View) { 10954 session = ((View) mParent).getContentCaptureSession(); 10955 } 10956 10957 // Finally, if no session was explicitly set, use the context's default session. 10958 if (session == null) { 10959 final ContentCaptureManager ccm = mContext 10960 .getSystemService(ContentCaptureManager.class); 10961 return ccm == null ? null : ccm.getMainContentCaptureSession(); 10962 } 10963 return session; 10964 } 10965 10966 @Nullable 10967 private AutofillManager getAutofillManager() { 10968 return mContext.getSystemService(AutofillManager.class); 10969 } 10970 10971 /** 10972 * Check whether current activity / package is in autofill denylist. 10973 * 10974 * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in 10975 * assist structure 10976 */ 10977 final boolean isActivityDeniedForAutofillForUnimportantView() { 10978 final AutofillManager afm = getAutofillManager(); 10979 if (afm == null) return false; 10980 return afm.isActivityDeniedForAutofill(); 10981 } 10982 10983 /** 10984 * Check whether current view matches autofillable heuristics 10985 * 10986 * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in 10987 * assist structure 10988 */ 10989 final boolean isMatchingAutofillableHeuristics() { 10990 final AutofillManager afm = getAutofillManager(); 10991 if (afm == null) return false; 10992 // check the flag to see if trigger fill request on not important views is enabled 10993 return afm.isTriggerFillRequestOnUnimportantViewEnabled() 10994 ? afm.isAutofillable(this) : false; 10995 } 10996 10997 private boolean isAutofillable() { 10998 if (DBG) { 10999 Log.d(VIEW_LOG_TAG, "isAutofillable() entered."); 11000 } 11001 if (getAutofillType() == AUTOFILL_TYPE_NONE) { 11002 if (DBG) { 11003 Log.d(VIEW_LOG_TAG, "getAutofillType() returns AUTOFILL_TYPE_NONE"); 11004 } 11005 return false; 11006 } 11007 11008 final AutofillManager afm = getAutofillManager(); 11009 if (afm == null) { 11010 if (DBG) { 11011 Log.d(VIEW_LOG_TAG, "AutofillManager is null"); 11012 } 11013 return false; 11014 } 11015 11016 // Check whether view is not part of an activity. If it's not, return false. 11017 if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) { 11018 if (DBG) { 11019 Log.d(VIEW_LOG_TAG, "getAutofillViewId()<=LAST_APP_AUTOFILL_ID"); 11020 } 11021 return false; 11022 } 11023 11024 // If view is important and filter important view flag is turned on, or view is not 11025 // important and trigger fill request on not important view flag is turned on, then use 11026 // AutofillManager.isAutofillable() to decide whether view is autofillable instead. 11027 if ((isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled()) 11028 || (!isImportantForAutofill() 11029 && afm.isTriggerFillRequestOnUnimportantViewEnabled())) { 11030 if (DBG) { 11031 Log.d(VIEW_LOG_TAG, "isImportantForAutofill(): " + isImportantForAutofill() 11032 + "afm.isAutofillable(): " + afm.isAutofillable(this)); 11033 } 11034 return afm.isAutofillable(this) ? true : notifyAugmentedAutofillIfNeeded(afm); 11035 } 11036 11037 // If the previous condition is not met, fall back to the previous way to trigger fill 11038 // request based on autofill importance instead. 11039 if (DBG) { 11040 Log.d(VIEW_LOG_TAG, "isImportantForAutofill(): " + isImportantForAutofill()); 11041 } 11042 return isImportantForAutofill() ? true : notifyAugmentedAutofillIfNeeded(afm); 11043 } 11044 11045 private boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) { 11046 final AutofillOptions options = mContext.getAutofillOptions(); 11047 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 11048 return false; 11049 } 11050 afm.notifyViewEnteredForAugmentedAutofill(this); 11051 return true; 11052 } 11053 11054 /** @hide */ 11055 public boolean canNotifyAutofillEnterExitEvent() { 11056 if (DBG) { 11057 Log.d(VIEW_LOG_TAG, "canNotifyAutofillEnterExitEvent() entered. " 11058 + " isAutofillable(): " + isAutofillable() 11059 + " isAttachedToWindow(): " + isAttachedToWindow()); 11060 } 11061 return isAutofillable() && isAttachedToWindow(); 11062 } 11063 11064 private void populateVirtualStructure(ViewStructure structure, 11065 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 11066 boolean forAutofill) { 11067 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 11068 null, null, info.getViewIdResourceName()); 11069 Rect rect = structure.getTempRect(); 11070 info.getBoundsInParent(rect); 11071 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 11072 structure.setVisibility(VISIBLE); 11073 structure.setEnabled(info.isEnabled()); 11074 if (info.isClickable()) { 11075 structure.setClickable(true); 11076 } 11077 if (info.isFocusable()) { 11078 structure.setFocusable(true); 11079 } 11080 if (info.isFocused()) { 11081 structure.setFocused(true); 11082 } 11083 if (info.isAccessibilityFocused()) { 11084 structure.setAccessibilityFocused(true); 11085 } 11086 if (info.isSelected()) { 11087 structure.setSelected(true); 11088 } 11089 if (info.isLongClickable()) { 11090 structure.setLongClickable(true); 11091 } 11092 if (info.isCheckable()) { 11093 structure.setCheckable(true); 11094 if (info.isChecked()) { 11095 structure.setChecked(true); 11096 } 11097 } 11098 if (info.isContextClickable()) { 11099 structure.setContextClickable(true); 11100 } 11101 if (forAutofill) { 11102 structure.setAutofillId(new AutofillId(getAutofillId(), 11103 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 11104 } 11105 if (getViewCredentialHandler() != null) { 11106 structure.setPendingCredentialRequest( 11107 getViewCredentialHandler().getRequest(), 11108 getViewCredentialHandler().getCallback()); 11109 } 11110 CharSequence cname = info.getClassName(); 11111 structure.setClassName(cname != null ? cname.toString() : null); 11112 structure.setContentDescription(info.getContentDescription()); 11113 if (forAutofill) { 11114 final int maxTextLength = info.getMaxTextLength(); 11115 if (maxTextLength != -1) { 11116 structure.setMaxTextLength(maxTextLength); 11117 } 11118 structure.setHint(info.getHintText()); 11119 } 11120 CharSequence text = info.getText(); 11121 boolean hasText = text != null || info.getError() != null; 11122 if (hasText) { 11123 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 11124 } 11125 if (forAutofill) { 11126 if (info.isEditable()) { 11127 structure.setDataIsSensitive(true); 11128 if (hasText) { 11129 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 11130 structure.setAutofillValue(AutofillValue.forText(text)); 11131 } 11132 int inputType = info.getInputType(); 11133 if (inputType == 0 && info.isPassword()) { 11134 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 11135 } 11136 structure.setInputType(inputType); 11137 } else { 11138 structure.setDataIsSensitive(false); 11139 } 11140 } 11141 final int NCHILDREN = info.getChildCount(); 11142 if (NCHILDREN > 0) { 11143 structure.setChildCount(NCHILDREN); 11144 for (int i=0; i<NCHILDREN; i++) { 11145 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 11146 == AccessibilityNodeProvider.HOST_VIEW_ID) { 11147 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 11148 continue; 11149 } 11150 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 11151 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 11152 if (cinfo != null) { 11153 ViewStructure child = structure.newChild(i); 11154 populateVirtualStructure(child, provider, cinfo, forAutofill); 11155 cinfo.recycle(); 11156 } 11157 } 11158 } 11159 } 11160 11161 /** 11162 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 11163 * implementation calls {@link #onProvideStructure} and 11164 * {@link #onProvideVirtualStructure}. 11165 */ 11166 public void dispatchProvideStructure(ViewStructure structure) { 11167 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 11168 } 11169 11170 /** 11171 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 11172 * when an Assist structure is being created as part of an autofill request. 11173 * 11174 * <p>The default implementation does the following: 11175 * <ul> 11176 * <li>Sets the {@link AutofillId} in the structure. 11177 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 11178 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 11179 * </ul> 11180 * 11181 * <p>Typically, this method should only be overridden by subclasses that provide a view 11182 * hierarchy (such as {@link ViewGroup}) - other classes should override 11183 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 11184 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 11185 * 11186 * <p>When overridden, it must: 11187 * 11188 * <ul> 11189 * <li>Either call 11190 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 11191 * set the {@link AutofillId} in the structure (for example, by calling 11192 * {@code structure.setAutofillId(getAutofillId())}). 11193 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 11194 * set, all views in the structure should be considered important for autofill, 11195 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 11196 * respect this flag to provide a better user experience - this flag is typically used 11197 * when an user explicitly requested autofill. If the flag is not set, 11198 * then only views marked as important for autofill should be included in the 11199 * structure - skipping non-important views optimizes the overall autofill performance. 11200 * </ul> 11201 * 11202 * @param structure fill in with structured view data for autofill purposes. 11203 * @param flags optional flags. 11204 * 11205 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 11206 */ 11207 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 11208 @AutofillFlags int flags) { 11209 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 11210 } 11211 11212 private void dispatchProvideStructure(@NonNull ViewStructure structure, 11213 @ViewStructureType int viewFor, @AutofillFlags int flags) { 11214 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 11215 structure.setAutofillId(getAutofillId()); 11216 onProvideAutofillStructure(structure, flags); 11217 onProvideAutofillVirtualStructure(structure, flags); 11218 } else if (!isAssistBlocked()) { 11219 onProvideStructure(structure); 11220 onProvideVirtualStructure(structure); 11221 } else { 11222 structure.setClassName(getAccessibilityClassName().toString()); 11223 structure.setAssistBlocked(true); 11224 } 11225 } 11226 11227 /** 11228 * Dispatches the initial content capture events for a view structure. 11229 * 11230 * @hide 11231 */ 11232 public void dispatchInitialProvideContentCaptureStructure() { 11233 AttachInfo ai = mAttachInfo; 11234 if (ai == null) { 11235 Log.w(CONTENT_CAPTURE_LOG_TAG, 11236 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 11237 return; 11238 } 11239 ContentCaptureManager ccm = ai.mContentCaptureManager; 11240 if (ccm == null) { 11241 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 11242 + "no ContentCaptureManager for " + this); 11243 return; 11244 } 11245 11246 // We must set it before checkign if the view itself is important, because it might 11247 // initially not be (for example, if it's empty), although that might change later (for 11248 // example, if important views are added) 11249 ai.mReadyForContentCaptureUpdates = true; 11250 11251 if (!isImportantForContentCapture()) { 11252 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 11253 Log.d(CONTENT_CAPTURE_LOG_TAG, 11254 "dispatchProvideContentCaptureStructure(): decorView is not important"); 11255 } 11256 return; 11257 } 11258 11259 ai.mContentCaptureManager = ccm; 11260 11261 ContentCaptureSession session = getContentCaptureSession(); 11262 if (session == null) { 11263 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 11264 Log.d(CONTENT_CAPTURE_LOG_TAG, 11265 "dispatchProvideContentCaptureStructure(): no session for " + this); 11266 } 11267 return; 11268 } 11269 11270 session.notifyViewTreeEvent(/* started= */ true); 11271 try { 11272 dispatchProvideContentCaptureStructure(); 11273 } finally { 11274 session.notifyViewTreeEvent(/* started= */ false); 11275 } 11276 } 11277 11278 /** @hide */ 11279 void dispatchProvideContentCaptureStructure() { 11280 ContentCaptureSession session = getContentCaptureSession(); 11281 if (session != null) { 11282 ViewStructure structure = session.newViewStructure(this); 11283 onProvideContentCaptureStructure(structure, /* flags= */ 0); 11284 setNotifiedContentCaptureAppeared(); 11285 session.notifyViewAppeared(structure); 11286 } 11287 } 11288 11289 /** 11290 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 11291 * 11292 * Note: Called from the default {@link AccessibilityDelegate}. 11293 * 11294 * @hide 11295 */ 11296 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 11297 if (mAttachInfo == null) { 11298 return; 11299 } 11300 11301 Rect bounds = mAttachInfo.mTmpInvalRect; 11302 11303 getDrawingRect(bounds); 11304 info.setBoundsInParent(bounds); 11305 11306 getBoundsOnScreen(bounds, true); 11307 info.setBoundsInScreen(bounds); 11308 getBoundsInWindow(bounds, true); 11309 info.setBoundsInWindow(bounds); 11310 11311 ViewParent parent = getParentForAccessibility(); 11312 if (parent instanceof View) { 11313 info.setParent((View) parent); 11314 } 11315 11316 if (mID != View.NO_ID) { 11317 View rootView = getRootView(); 11318 if (rootView == null) { 11319 rootView = this; 11320 } 11321 11322 View label = rootView.findLabelForView(this, mID); 11323 if (label != null) { 11324 info.setLabeledBy(label); 11325 } 11326 11327 if ((mAttachInfo.mAccessibilityFetchFlags 11328 & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS) != 0 11329 && Resources.resourceHasPackage(mID)) { 11330 try { 11331 String viewId = getResources().getResourceName(mID); 11332 info.setViewIdResourceName(viewId); 11333 } catch (Resources.NotFoundException nfe) { 11334 /* ignore */ 11335 } 11336 } 11337 } 11338 11339 if (mLabelForId != View.NO_ID) { 11340 View rootView = getRootView(); 11341 if (rootView == null) { 11342 rootView = this; 11343 } 11344 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 11345 if (labeled != null) { 11346 info.setLabelFor(labeled); 11347 } 11348 } 11349 11350 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 11351 View rootView = getRootView(); 11352 if (rootView == null) { 11353 rootView = this; 11354 } 11355 View next = rootView.findViewInsideOutShouldExist(this, 11356 mAccessibilityTraversalBeforeId); 11357 if (next != null && next.includeForAccessibility()) { 11358 info.setTraversalBefore(next); 11359 } 11360 } 11361 11362 if (mAccessibilityTraversalAfterId != View.NO_ID) { 11363 View rootView = getRootView(); 11364 if (rootView == null) { 11365 rootView = this; 11366 } 11367 View next = rootView.findViewInsideOutShouldExist(this, 11368 mAccessibilityTraversalAfterId); 11369 if (next != null && next.includeForAccessibility()) { 11370 info.setTraversalAfter(next); 11371 } 11372 } 11373 11374 info.setVisibleToUser(isVisibleToUser()); 11375 11376 info.setImportantForAccessibility(isImportantForAccessibility()); 11377 info.setAccessibilityDataSensitive(isAccessibilityDataSensitive()); 11378 info.setPackageName(mContext.getPackageName()); 11379 info.setClassName(getAccessibilityClassName()); 11380 info.setStateDescription(getStateDescription()); 11381 info.setContentDescription(getContentDescription()); 11382 11383 info.setEnabled(isEnabled()); 11384 info.setClickable(isClickable()); 11385 info.setFocusable(isFocusable()); 11386 info.setScreenReaderFocusable(isScreenReaderFocusable()); 11387 info.setFocused(isFocused()); 11388 info.setAccessibilityFocused(isAccessibilityFocused()); 11389 info.setSelected(isSelected()); 11390 info.setLongClickable(isLongClickable()); 11391 info.setContextClickable(isContextClickable()); 11392 info.setLiveRegion(getAccessibilityLiveRegion()); 11393 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 11394 info.setTooltipText(mTooltipInfo.mTooltipText); 11395 info.addAction((mTooltipInfo.mTooltipPopup == null) 11396 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 11397 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 11398 } 11399 11400 // TODO: These make sense only if we are in an AdapterView but all 11401 // views can be selected. Maybe from accessibility perspective 11402 // we should report as selectable view in an AdapterView. 11403 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 11404 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 11405 11406 if (isFocusable()) { 11407 if (isFocused()) { 11408 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 11409 } else { 11410 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 11411 } 11412 } 11413 11414 if (!isAccessibilityFocused()) { 11415 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 11416 } else { 11417 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 11418 } 11419 11420 if (isClickable() && isEnabled()) { 11421 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 11422 } 11423 11424 if (isLongClickable() && isEnabled()) { 11425 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 11426 } 11427 11428 if (isContextClickable() && isEnabled()) { 11429 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 11430 } 11431 11432 CharSequence text = getIterableTextForAccessibility(); 11433 if (text != null && text.length() > 0) { 11434 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 11435 11436 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 11437 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 11438 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 11439 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 11440 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 11441 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 11442 } 11443 11444 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 11445 populateAccessibilityNodeInfoDrawingOrderInParent(info); 11446 info.setPaneTitle(mAccessibilityPaneTitle); 11447 info.setHeading(isAccessibilityHeading()); 11448 11449 if (mTouchDelegate != null) { 11450 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 11451 } 11452 11453 if (startedSystemDragForAccessibility()) { 11454 info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); 11455 } 11456 11457 if (canAcceptAccessibilityDrop()) { 11458 info.addAction(AccessibilityAction.ACTION_DRAG_DROP); 11459 } 11460 } 11461 11462 11463 /** 11464 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 11465 * additional data. 11466 * <p> 11467 * This method only needs overloading if the node is marked as having extra data available. 11468 * </p> 11469 * 11470 * @param info The info to which to add the extra data. Never {@code null}. 11471 * @param extraDataKey A key specifying the type of extra data to add to the info. The 11472 * extra data should be added to the {@link Bundle} returned by 11473 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 11474 * {@code null}. 11475 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 11476 * {@code null} if the service provided no arguments. 11477 * 11478 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 11479 */ 11480 public void addExtraDataToAccessibilityNodeInfo( 11481 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 11482 @Nullable Bundle arguments) { 11483 } 11484 11485 /** 11486 * Determine the order in which this view will be drawn relative to its siblings for a11y 11487 * 11488 * @param info The info whose drawing order should be populated 11489 */ 11490 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 11491 /* 11492 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 11493 * drawing order may not be well-defined, and some Views with custom drawing order may 11494 * not be initialized sufficiently to respond properly getChildDrawingOrder. 11495 */ 11496 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 11497 info.setDrawingOrder(0); 11498 return; 11499 } 11500 int drawingOrderInParent = 1; 11501 // Iterate up the hierarchy if parents are not important for a11y 11502 View viewAtDrawingLevel = this; 11503 final ViewParent parent = getParentForAccessibility(); 11504 while (viewAtDrawingLevel != parent) { 11505 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 11506 if (!(currentParent instanceof ViewGroup)) { 11507 // Should only happen for the Decor 11508 drawingOrderInParent = 0; 11509 break; 11510 } else { 11511 final ViewGroup parentGroup = (ViewGroup) currentParent; 11512 final int childCount = parentGroup.getChildCount(); 11513 if (childCount > 1) { 11514 List<View> preorderedList = parentGroup.buildOrderedChildList(); 11515 if (preorderedList != null) { 11516 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 11517 for (int i = 0; i < childDrawIndex; i++) { 11518 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 11519 } 11520 preorderedList.clear(); 11521 } else { 11522 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 11523 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 11524 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 11525 .getChildDrawingOrder(childCount, childIndex) : childIndex; 11526 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 11527 if (childDrawIndex != 0) { 11528 for (int i = 0; i < numChildrenToIterate; i++) { 11529 final int otherDrawIndex = (customOrder ? 11530 parentGroup.getChildDrawingOrder(childCount, i) : i); 11531 if (otherDrawIndex < childDrawIndex) { 11532 drawingOrderInParent += 11533 numViewsForAccessibility(parentGroup.getChildAt(i)); 11534 } 11535 } 11536 } 11537 } 11538 } 11539 } 11540 viewAtDrawingLevel = (View) currentParent; 11541 } 11542 info.setDrawingOrder(drawingOrderInParent); 11543 } 11544 11545 private static int numViewsForAccessibility(View view) { 11546 if (view != null) { 11547 if (view.includeForAccessibility()) { 11548 return 1; 11549 } else if (view instanceof ViewGroup) { 11550 return ((ViewGroup) view).getNumChildrenForAccessibility(); 11551 } 11552 } 11553 return 0; 11554 } 11555 11556 private View findLabelForView(View view, int labeledId) { 11557 if (mMatchLabelForPredicate == null) { 11558 mMatchLabelForPredicate = new MatchLabelForPredicate(); 11559 } 11560 mMatchLabelForPredicate.mLabeledId = labeledId; 11561 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 11562 } 11563 11564 /** 11565 * Computes whether this virtual autofill view is visible to the user. 11566 * 11567 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 11568 * view must override it. 11569 * 11570 * @return Whether the view is visible on the screen. 11571 */ 11572 public boolean isVisibleToUserForAutofill(int virtualId) { 11573 if (mContext.isAutofillCompatibilityEnabled()) { 11574 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 11575 if (provider != null) { 11576 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 11577 if (node != null) { 11578 return node.isVisibleToUser(); 11579 } 11580 // if node is null, assume it's not visible anymore 11581 } else { 11582 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 11583 } 11584 return false; 11585 } 11586 return true; 11587 } 11588 11589 /** 11590 * Computes whether this view is visible to the user. Such a view is 11591 * attached, visible, all its predecessors are visible, it is not clipped 11592 * entirely by its predecessors, and has an alpha greater than zero. 11593 * 11594 * @return Whether the view is visible on the screen. 11595 * 11596 * @hide 11597 */ 11598 @UnsupportedAppUsage 11599 public boolean isVisibleToUser() { 11600 return isVisibleToUser(null); 11601 } 11602 11603 /** 11604 * Computes whether the given portion of this view is visible to the user. 11605 * Such a view is attached, visible, all its predecessors are visible, 11606 * has an alpha greater than zero, and the specified portion is not 11607 * clipped entirely by its predecessors. 11608 * 11609 * @param boundInView the portion of the view to test; coordinates should be relative; may be 11610 * <code>null</code>, and the entire view will be tested in this case. 11611 * When <code>true</code> is returned by the function, the actual visible 11612 * region will be stored in this parameter; that is, if boundInView is fully 11613 * contained within the view, no modification will be made, otherwise regions 11614 * outside of the visible area of the view will be clipped. 11615 * 11616 * @return Whether the specified portion of the view is visible on the screen. 11617 * 11618 * @hide 11619 */ 11620 @UnsupportedAppUsage(trackingBug = 171933273) 11621 protected boolean isVisibleToUser(Rect boundInView) { 11622 if (mAttachInfo != null) { 11623 // Attached to invisible window means this view is not visible. 11624 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 11625 return false; 11626 } 11627 // An invisible predecessor or one with alpha zero means 11628 // that this view is not visible to the user. 11629 Object current = this; 11630 while (current instanceof View) { 11631 View view = (View) current; 11632 // We have attach info so this view is attached and there is no 11633 // need to check whether we reach to ViewRootImpl on the way up. 11634 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 11635 view.getVisibility() != VISIBLE) { 11636 return false; 11637 } 11638 current = view.mParent; 11639 } 11640 // Check if the view is entirely covered by its predecessors. 11641 Rect visibleRect = mAttachInfo.mTmpInvalRect; 11642 Point offset = mAttachInfo.mPoint; 11643 if (!getGlobalVisibleRect(visibleRect, offset)) { 11644 return false; 11645 } 11646 // Check if the visible portion intersects the rectangle of interest. 11647 if (boundInView != null) { 11648 visibleRect.offset(-offset.x, -offset.y); 11649 return boundInView.intersect(visibleRect); 11650 } 11651 return true; 11652 } 11653 return false; 11654 } 11655 11656 /** 11657 * Returns the delegate for implementing accessibility support via 11658 * composition. For more details see {@link AccessibilityDelegate}. 11659 * 11660 * @return The delegate, or null if none set. 11661 */ 11662 public AccessibilityDelegate getAccessibilityDelegate() { 11663 return mAccessibilityDelegate; 11664 } 11665 11666 /** 11667 * Sets a delegate for implementing accessibility support via composition 11668 * (as opposed to inheritance). For more details, see 11669 * {@link AccessibilityDelegate}. 11670 * <p> 11671 * <strong>Note:</strong> On platform versions prior to 11672 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 11673 * views in the {@code android.widget.*} package are called <i>before</i> 11674 * host methods. This prevents certain properties such as class name from 11675 * being modified by overriding 11676 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 11677 * as any changes will be overwritten by the host class. 11678 * <p> 11679 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 11680 * methods are called <i>after</i> host methods, which all properties to be 11681 * modified without being overwritten by the host class. 11682 * 11683 * @param delegate the object to which accessibility method calls should be 11684 * delegated 11685 * @see AccessibilityDelegate 11686 */ 11687 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 11688 mAccessibilityDelegate = delegate; 11689 } 11690 11691 /** 11692 * Gets the provider for managing a virtual view hierarchy rooted at this View 11693 * and reported to {@link android.accessibilityservice.AccessibilityService}s 11694 * that explore the window content. 11695 * <p> 11696 * If this method returns an instance, this instance is responsible for managing 11697 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 11698 * View including the one representing the View itself. Similarly the returned 11699 * instance is responsible for performing accessibility actions on any virtual 11700 * view or the root view itself. 11701 * </p> 11702 * <p> 11703 * If an {@link AccessibilityDelegate} has been specified via calling 11704 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11705 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 11706 * is responsible for handling this call. 11707 * </p> 11708 * 11709 * @return The provider. 11710 * 11711 * @see AccessibilityNodeProvider 11712 */ 11713 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 11714 if (mAccessibilityDelegate != null) { 11715 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 11716 } else { 11717 return null; 11718 } 11719 } 11720 11721 /** 11722 * Gets the unique identifier of this view on the screen for accessibility purposes. 11723 * 11724 * @return The view accessibility id. 11725 * 11726 * @hide 11727 */ 11728 @UnsupportedAppUsage 11729 public int getAccessibilityViewId() { 11730 if (mAccessibilityViewId == NO_ID) { 11731 mAccessibilityViewId = sNextAccessibilityViewId++; 11732 } 11733 return mAccessibilityViewId; 11734 } 11735 11736 /** 11737 * Gets the unique identifier of this view on the screen for autofill purposes. 11738 * 11739 * @return The view autofill id. 11740 * 11741 * @hide 11742 */ 11743 public int getAutofillViewId() { 11744 if (mAutofillViewId == NO_ID) { 11745 mAutofillViewId = mContext.getNextAutofillId(); 11746 } 11747 return mAutofillViewId; 11748 } 11749 11750 /** 11751 * Gets the unique identifier of the window in which this View resides. 11752 * 11753 * @return The window accessibility id. 11754 * 11755 * @hide 11756 */ 11757 public int getAccessibilityWindowId() { 11758 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 11759 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 11760 } 11761 11762 /** 11763 * Returns the {@link View}'s state description. 11764 * <p> 11765 * <strong>Note:</strong> Do not override this method, as it will have no 11766 * effect on the state description presented to accessibility services. 11767 * You must call {@link #setStateDescription(CharSequence)} to modify the 11768 * state description. 11769 * 11770 * @return the state description 11771 * @see #setStateDescription(CharSequence) 11772 */ 11773 @ViewDebug.ExportedProperty(category = "accessibility") 11774 public final @Nullable CharSequence getStateDescription() { 11775 return mStateDescription; 11776 } 11777 11778 /** 11779 * Returns the {@link View}'s content description. 11780 * <p> 11781 * <strong>Note:</strong> Do not override this method, as it will have no 11782 * effect on the content description presented to accessibility services. 11783 * You must call {@link #setContentDescription(CharSequence)} to modify the 11784 * content description. 11785 * 11786 * @return the content description 11787 * @see #setContentDescription(CharSequence) 11788 * @attr ref android.R.styleable#View_contentDescription 11789 */ 11790 @ViewDebug.ExportedProperty(category = "accessibility") 11791 @InspectableProperty 11792 public CharSequence getContentDescription() { 11793 return mContentDescription; 11794 } 11795 11796 /** 11797 * Sets the {@link View}'s state description. 11798 * <p> 11799 * A state description briefly describes the states of the view and is primarily used 11800 * for accessibility support to determine how the states of a view should be presented to 11801 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 11802 * it is used for customized state description (for example, "wifi, connected, three bars"). 11803 * State description changes frequently while content description should change less often. 11804 * State description should be localized. For android widgets which have default state 11805 * descriptions, app developers can call this method to override the state descriptions. 11806 * Setting state description to null restores the default behavior. 11807 * 11808 * @param stateDescription The state description. 11809 * @see #getStateDescription() 11810 * @see #setContentDescription(CharSequence) for the difference between content and 11811 * state descriptions. 11812 */ 11813 @RemotableViewMethod 11814 public void setStateDescription(@Nullable CharSequence stateDescription) { 11815 if (mStateDescription == null) { 11816 if (stateDescription == null) { 11817 return; 11818 } 11819 } else if (mStateDescription.equals(stateDescription)) { 11820 return; 11821 } 11822 mStateDescription = stateDescription; 11823 if (!TextUtils.isEmpty(stateDescription) 11824 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 11825 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 11826 } 11827 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 11828 AccessibilityEvent event = AccessibilityEvent.obtain(); 11829 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11830 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 11831 sendAccessibilityEventUnchecked(event); 11832 } 11833 } 11834 11835 /** 11836 * Sets the {@link View}'s content description. 11837 * <p> 11838 * A content description briefly describes the view and is primarily used 11839 * for accessibility support to determine how a view should be presented to 11840 * the user. In the case of a view with no textual representation, such as 11841 * {@link android.widget.ImageButton}, a useful content description 11842 * explains what the view does. For example, an image button with a phone 11843 * icon that is used to place a call may use "Call" as its content 11844 * description. An image of a floppy disk that is used to save a file may 11845 * use "Save". 11846 * 11847 * <p> 11848 * This should omit role or state. Role refers to the kind of user-interface element the View 11849 * is, such as a Button or Checkbox. State refers to a frequently changing property of the View, 11850 * such as an On/Off state of a button or the audio level of a volume slider. 11851 * 11852 * <p> 11853 * Content description updates are not frequent, and are used when the semantic content - not 11854 * the state - of the element changes. For example, a Play button might change to a Pause 11855 * button during music playback. 11856 * 11857 * @param contentDescription The content description. 11858 * @see #getContentDescription() 11859 * @see #setStateDescription(CharSequence)} for state changes. 11860 * @attr ref android.R.styleable#View_contentDescription 11861 */ 11862 @RemotableViewMethod 11863 public void setContentDescription(CharSequence contentDescription) { 11864 if (mContentDescription == null) { 11865 if (contentDescription == null) { 11866 return; 11867 } 11868 } else if (mContentDescription.equals(contentDescription)) { 11869 return; 11870 } 11871 mContentDescription = contentDescription; 11872 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 11873 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 11874 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 11875 notifySubtreeAccessibilityStateChangedIfNeeded(); 11876 } else { 11877 notifyViewAccessibilityStateChangedIfNeeded( 11878 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 11879 } 11880 } 11881 11882 /** 11883 * Sets the id of a view that screen readers are requested to visit after this view. 11884 * 11885 * <p> 11886 * 11887 * For example, if view B should be visited before view A, with 11888 * B.setAccessibilityTraversalBefore(A), this requests that screen readers visit and traverse 11889 * view B before visiting view A. 11890 * 11891 * <p> 11892 * <b>Note:</b> Views are visited in the order determined by the screen reader. Avoid 11893 * explicitly manipulating focus order, as this may result in inconsistent user 11894 * experiences between apps. Instead, use other semantics, such as restructuring the view 11895 * hierarchy layout, to communicate order. 11896 * 11897 * <p> 11898 * Setting this view to be after a view that is not important for accessibility, 11899 * or if this view is not important for accessibility, means this method will have no effect if 11900 * the service is not aware of unimportant views. 11901 * 11902 * <p> 11903 * To avoid a risk of loops, set clear relationships between views. For example, if focus order 11904 * should be B -> A, and B.setAccessibilityTraversalBefore(A), then also call 11905 * A.setAccessibilityTraversalAfter(B). 11906 * 11907 * @param beforeId The id of a view this one precedes in accessibility traversal. 11908 * 11909 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 11910 * 11911 * @see #setImportantForAccessibility(int) 11912 * @see #setAccessibilityTraversalAfter(int) 11913 */ 11914 @RemotableViewMethod 11915 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 11916 if (mAccessibilityTraversalBeforeId == beforeId) { 11917 return; 11918 } 11919 mAccessibilityTraversalBeforeId = beforeId; 11920 notifyViewAccessibilityStateChangedIfNeeded( 11921 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11922 } 11923 11924 /** 11925 * Gets the id of a view before which this one is visited in accessibility traversal. 11926 * 11927 * @return The id of a view this one precedes in accessibility traversal if 11928 * specified, otherwise {@link #NO_ID}. 11929 * 11930 * @see #setAccessibilityTraversalBefore(int) 11931 */ 11932 @IdRes 11933 @InspectableProperty 11934 public int getAccessibilityTraversalBefore() { 11935 return mAccessibilityTraversalBeforeId; 11936 } 11937 11938 /** 11939 * Sets the id of a view that screen readers are requested to visit before this view. 11940 * 11941 * <p> 11942 * For example, if view B should be visited after A, with B.setAccessibilityTraversalAfter(A), 11943 * then this requests that screen readers visit and traverse view A before visiting view B. 11944 * 11945 * <p> 11946 * <b>Note:</b> Views are visited in the order determined by the screen reader. Avoid 11947 * explicitly manipulating focus order, as this may result in inconsistent user 11948 * experiences between apps. Instead, use other semantics, such as restructuring the view 11949 * hierarchy layout, to communicate order. 11950 * 11951 * <p> 11952 * Setting this view to be after a view that is not important for accessibility, 11953 * or if this view is not important for accessibility, means this method will have no effect if 11954 * the service is not aware of unimportant views. 11955 * 11956 * <p> 11957 * To avoid a risk of loops, set clear relationships between views. For example, if focus order 11958 * should be B -> A, and B.setAccessibilityTraversalBefore(A), then also call 11959 * A.setAccessibilityTraversalAfter(B). 11960 * 11961 * @param afterId The id of a view this one succeeds in accessibility traversal. 11962 * 11963 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 11964 * 11965 * @see #setImportantForAccessibility(int) 11966 * @see #setAccessibilityTraversalBefore(int) 11967 */ 11968 @RemotableViewMethod 11969 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 11970 if (mAccessibilityTraversalAfterId == afterId) { 11971 return; 11972 } 11973 mAccessibilityTraversalAfterId = afterId; 11974 notifyViewAccessibilityStateChangedIfNeeded( 11975 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11976 } 11977 11978 /** 11979 * Gets the id of a view after which this one is visited in accessibility traversal. 11980 * 11981 * @return The id of a view this one succeedes in accessibility traversal if 11982 * specified, otherwise {@link #NO_ID}. 11983 * 11984 * @see #setAccessibilityTraversalAfter(int) 11985 */ 11986 @IdRes 11987 @InspectableProperty 11988 public int getAccessibilityTraversalAfter() { 11989 return mAccessibilityTraversalAfterId; 11990 } 11991 11992 /** 11993 * Gets the id of a view for which this view serves as a label for 11994 * accessibility purposes. 11995 * 11996 * @return The labeled view id. 11997 */ 11998 @IdRes 11999 @ViewDebug.ExportedProperty(category = "accessibility") 12000 @InspectableProperty 12001 public int getLabelFor() { 12002 return mLabelForId; 12003 } 12004 12005 /** 12006 * Sets the id of a view for which this view serves as a label for 12007 * accessibility purposes. 12008 * 12009 * @param id The labeled view id. 12010 */ 12011 @RemotableViewMethod 12012 public void setLabelFor(@IdRes int id) { 12013 if (mLabelForId == id) { 12014 return; 12015 } 12016 mLabelForId = id; 12017 if (mLabelForId != View.NO_ID 12018 && mID == View.NO_ID) { 12019 mID = generateViewId(); 12020 } 12021 notifyViewAccessibilityStateChangedIfNeeded( 12022 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12023 } 12024 12025 /** 12026 * Invoked whenever this view loses focus, either by losing window focus or by losing 12027 * focus within its window. This method can be used to clear any state tied to the 12028 * focus. For instance, if a button is held pressed with the trackball and the window 12029 * loses focus, this method can be used to cancel the press. 12030 * 12031 * Subclasses of View overriding this method should always call super.onFocusLost(). 12032 * 12033 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 12034 * @see #onWindowFocusChanged(boolean) 12035 * 12036 * @hide pending API council approval 12037 */ 12038 @CallSuper 12039 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 12040 protected void onFocusLost() { 12041 resetPressedState(); 12042 } 12043 12044 private void resetPressedState() { 12045 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12046 return; 12047 } 12048 12049 if (isPressed()) { 12050 setPressed(false); 12051 12052 if (!mHasPerformedLongPress) { 12053 removeLongPressCallback(); 12054 } 12055 } 12056 } 12057 12058 /** 12059 * Returns true if this view has focus 12060 * 12061 * @return True if this view has focus, false otherwise. 12062 */ 12063 @ViewDebug.ExportedProperty(category = "focus") 12064 @InspectableProperty(hasAttributeId = false) 12065 public boolean isFocused() { 12066 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 12067 } 12068 12069 /** 12070 * Find the view in the hierarchy rooted at this view that currently has 12071 * focus. 12072 * 12073 * @return The view that currently has focus, or null if no focused view can 12074 * be found. 12075 */ 12076 public View findFocus() { 12077 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 12078 } 12079 12080 /** 12081 * Indicates whether this view is one of the set of scrollable containers in 12082 * its window. 12083 * 12084 * @return whether this view is one of the set of scrollable containers in 12085 * its window 12086 * 12087 * @attr ref android.R.styleable#View_isScrollContainer 12088 */ 12089 @InspectableProperty(name = "isScrollContainer") 12090 public boolean isScrollContainer() { 12091 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 12092 } 12093 12094 /** 12095 * Change whether this view is one of the set of scrollable containers in 12096 * its window. This will be used to determine whether the window can 12097 * resize or must pan when a soft input area is open -- scrollable 12098 * containers allow the window to use resize mode since the container 12099 * will appropriately shrink. 12100 * 12101 * @attr ref android.R.styleable#View_isScrollContainer 12102 */ 12103 public void setScrollContainer(boolean isScrollContainer) { 12104 if (isScrollContainer) { 12105 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 12106 mAttachInfo.mScrollContainers.add(this); 12107 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 12108 } 12109 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 12110 } else { 12111 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 12112 mAttachInfo.mScrollContainers.remove(this); 12113 } 12114 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 12115 } 12116 } 12117 12118 /** 12119 * Returns the quality of the drawing cache. 12120 * 12121 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 12122 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 12123 * 12124 * @see #setDrawingCacheQuality(int) 12125 * @see #setDrawingCacheEnabled(boolean) 12126 * @see #isDrawingCacheEnabled() 12127 * 12128 * @attr ref android.R.styleable#View_drawingCacheQuality 12129 * 12130 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12131 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12132 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12133 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12134 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12135 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12136 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12137 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12138 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12139 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12140 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12141 * reports or unit testing the {@link PixelCopy} API is recommended. 12142 */ 12143 @Deprecated 12144 @DrawingCacheQuality 12145 @InspectableProperty(enumMapping = { 12146 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 12147 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 12148 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 12149 }) 12150 public int getDrawingCacheQuality() { 12151 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 12152 } 12153 12154 /** 12155 * Set the drawing cache quality of this view. This value is used only when the 12156 * drawing cache is enabled 12157 * 12158 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 12159 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 12160 * 12161 * @see #getDrawingCacheQuality() 12162 * @see #setDrawingCacheEnabled(boolean) 12163 * @see #isDrawingCacheEnabled() 12164 * 12165 * @attr ref android.R.styleable#View_drawingCacheQuality 12166 * 12167 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12168 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12169 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12170 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12171 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12172 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12173 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12174 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12175 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12176 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12177 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12178 * reports or unit testing the {@link PixelCopy} API is recommended. 12179 */ 12180 @Deprecated 12181 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 12182 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 12183 } 12184 12185 /** 12186 * Returns whether the screen should remain on, corresponding to the current 12187 * value of {@link #KEEP_SCREEN_ON}. 12188 * 12189 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 12190 * 12191 * @see #setKeepScreenOn(boolean) 12192 * 12193 * @attr ref android.R.styleable#View_keepScreenOn 12194 */ 12195 @InspectableProperty 12196 public boolean getKeepScreenOn() { 12197 return (mViewFlags & KEEP_SCREEN_ON) != 0; 12198 } 12199 12200 /** 12201 * Controls whether the screen should remain on, modifying the 12202 * value of {@link #KEEP_SCREEN_ON}. 12203 * 12204 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 12205 * 12206 * @see #getKeepScreenOn() 12207 * 12208 * @attr ref android.R.styleable#View_keepScreenOn 12209 */ 12210 public void setKeepScreenOn(boolean keepScreenOn) { 12211 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 12212 } 12213 12214 /** 12215 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 12216 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12217 * 12218 * @attr ref android.R.styleable#View_nextFocusLeft 12219 */ 12220 @IdRes 12221 @InspectableProperty(name = "nextFocusLeft") 12222 public int getNextFocusLeftId() { 12223 return mNextFocusLeftId; 12224 } 12225 12226 /** 12227 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 12228 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 12229 * decide automatically. 12230 * 12231 * @attr ref android.R.styleable#View_nextFocusLeft 12232 */ 12233 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 12234 mNextFocusLeftId = nextFocusLeftId; 12235 } 12236 12237 /** 12238 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 12239 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12240 * 12241 * @attr ref android.R.styleable#View_nextFocusRight 12242 */ 12243 @IdRes 12244 @InspectableProperty(name = "nextFocusRight") 12245 public int getNextFocusRightId() { 12246 return mNextFocusRightId; 12247 } 12248 12249 /** 12250 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 12251 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 12252 * decide automatically. 12253 * 12254 * @attr ref android.R.styleable#View_nextFocusRight 12255 */ 12256 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 12257 mNextFocusRightId = nextFocusRightId; 12258 } 12259 12260 /** 12261 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 12262 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12263 * 12264 * @attr ref android.R.styleable#View_nextFocusUp 12265 */ 12266 @IdRes 12267 @InspectableProperty(name = "nextFocusUp") 12268 public int getNextFocusUpId() { 12269 return mNextFocusUpId; 12270 } 12271 12272 /** 12273 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 12274 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 12275 * decide automatically. 12276 * 12277 * @attr ref android.R.styleable#View_nextFocusUp 12278 */ 12279 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 12280 mNextFocusUpId = nextFocusUpId; 12281 } 12282 12283 /** 12284 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 12285 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12286 * 12287 * @attr ref android.R.styleable#View_nextFocusDown 12288 */ 12289 @IdRes 12290 @InspectableProperty(name = "nextFocusDown") 12291 public int getNextFocusDownId() { 12292 return mNextFocusDownId; 12293 } 12294 12295 /** 12296 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 12297 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 12298 * decide automatically. 12299 * 12300 * @attr ref android.R.styleable#View_nextFocusDown 12301 */ 12302 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 12303 mNextFocusDownId = nextFocusDownId; 12304 } 12305 12306 /** 12307 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 12308 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12309 * 12310 * @attr ref android.R.styleable#View_nextFocusForward 12311 */ 12312 @IdRes 12313 @InspectableProperty(name = "nextFocusForward") 12314 public int getNextFocusForwardId() { 12315 return mNextFocusForwardId; 12316 } 12317 12318 /** 12319 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 12320 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 12321 * decide automatically. 12322 * 12323 * @attr ref android.R.styleable#View_nextFocusForward 12324 */ 12325 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 12326 mNextFocusForwardId = nextFocusForwardId; 12327 } 12328 12329 /** 12330 * Gets the id of the root of the next keyboard navigation cluster. 12331 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 12332 * decide automatically. 12333 * 12334 * @attr ref android.R.styleable#View_nextClusterForward 12335 */ 12336 @IdRes 12337 @InspectableProperty(name = "nextClusterForward") 12338 public int getNextClusterForwardId() { 12339 return mNextClusterForwardId; 12340 } 12341 12342 /** 12343 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 12344 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 12345 * decide automatically. 12346 * 12347 * @attr ref android.R.styleable#View_nextClusterForward 12348 */ 12349 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 12350 mNextClusterForwardId = nextClusterForwardId; 12351 } 12352 12353 /** 12354 * Returns the visibility of this view and all of its ancestors 12355 * 12356 * @return True if this view and all of its ancestors are {@link #VISIBLE} 12357 */ 12358 public boolean isShown() { 12359 View current = this; 12360 //noinspection ConstantConditions 12361 do { 12362 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 12363 return false; 12364 } 12365 ViewParent parent = current.mParent; 12366 if (parent == null) { 12367 return false; // We are not attached to the view root 12368 } 12369 if (!(parent instanceof View)) { 12370 return true; 12371 } 12372 current = (View) parent; 12373 } while (current != null); 12374 12375 return false; 12376 } 12377 12378 private boolean detached() { 12379 View current = this; 12380 //noinspection ConstantConditions 12381 do { 12382 if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { 12383 return true; 12384 } 12385 ViewParent parent = current.mParent; 12386 if (parent == null) { 12387 return false; 12388 } 12389 if (!(parent instanceof View)) { 12390 return false; 12391 } 12392 current = (View) parent; 12393 } while (current != null); 12394 12395 return false; 12396 } 12397 12398 /** 12399 * Called by the view hierarchy when the content insets for a window have 12400 * changed, to allow it to adjust its content to fit within those windows. 12401 * The content insets tell you the space that the status bar, input method, 12402 * and other system windows infringe on the application's window. 12403 * 12404 * <p>You do not normally need to deal with this function, since the default 12405 * window decoration given to applications takes care of applying it to the 12406 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 12407 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 12408 * and your content can be placed under those system elements. You can then 12409 * use this method within your view hierarchy if you have parts of your UI 12410 * which you would like to ensure are not being covered. 12411 * 12412 * <p>The default implementation of this method simply applies the content 12413 * insets to the view's padding, consuming that content (modifying the 12414 * insets to be 0), and returning true. This behavior is off by default, but can 12415 * be enabled through {@link #setFitsSystemWindows(boolean)}. 12416 * 12417 * <p>This function's traversal down the hierarchy is depth-first. The same content 12418 * insets object is propagated down the hierarchy, so any changes made to it will 12419 * be seen by all following views (including potentially ones above in 12420 * the hierarchy since this is a depth-first traversal). The first view 12421 * that returns true will abort the entire traversal. 12422 * 12423 * <p>The default implementation works well for a situation where it is 12424 * used with a container that covers the entire window, allowing it to 12425 * apply the appropriate insets to its content on all edges. If you need 12426 * a more complicated layout (such as two different views fitting system 12427 * windows, one on the top of the window, and one on the bottom), 12428 * you can override the method and handle the insets however you would like. 12429 * Note that the insets provided by the framework are always relative to the 12430 * far edges of the window, not accounting for the location of the called view 12431 * within that window. (In fact when this method is called you do not yet know 12432 * where the layout will place the view, as it is done before layout happens.) 12433 * 12434 * <p>Note: unlike many View methods, there is no dispatch phase to this 12435 * call. If you are overriding it in a ViewGroup and want to allow the 12436 * call to continue to your children, you must be sure to call the super 12437 * implementation. 12438 * 12439 * <p>Here is a sample layout that makes use of fitting system windows 12440 * to have controls for a video view placed inside of the window decorations 12441 * that it hides and shows. This can be used with code like the second 12442 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 12443 * 12444 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 12445 * 12446 * @param insets Current content insets of the window. Prior to 12447 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 12448 * the insets or else you and Android will be unhappy. 12449 * 12450 * @return {@code true} if this view applied the insets and it should not 12451 * continue propagating further down the hierarchy, {@code false} otherwise. 12452 * @see #getFitsSystemWindows() 12453 * @see #setFitsSystemWindows(boolean) 12454 * @see #setSystemUiVisibility(int) 12455 * 12456 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 12457 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 12458 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 12459 * to implement handling their own insets. 12460 */ 12461 @Deprecated 12462 protected boolean fitSystemWindows(Rect insets) { 12463 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 12464 if (insets == null) { 12465 // Null insets by definition have already been consumed. 12466 // This call cannot apply insets since there are none to apply, 12467 // so return false. 12468 return false; 12469 } 12470 // If we're not in the process of dispatching the newer apply insets call, 12471 // that means we're not in the compatibility path. Dispatch into the newer 12472 // apply insets path and take things from there. 12473 try { 12474 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 12475 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 12476 } finally { 12477 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 12478 } 12479 } else { 12480 // We're being called from the newer apply insets path. 12481 // Perform the standard fallback behavior. 12482 return fitSystemWindowsInt(insets); 12483 } 12484 } 12485 12486 private boolean fitSystemWindowsInt(Rect insets) { 12487 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 12488 Rect localInsets = sThreadLocal.get(); 12489 boolean res = computeFitSystemWindows(insets, localInsets); 12490 applyInsets(localInsets); 12491 return res; 12492 } 12493 return false; 12494 } 12495 12496 private void applyInsets(Rect insets) { 12497 mUserPaddingStart = UNDEFINED_PADDING; 12498 mUserPaddingEnd = UNDEFINED_PADDING; 12499 mUserPaddingLeftInitial = insets.left; 12500 mUserPaddingRightInitial = insets.right; 12501 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 12502 } 12503 12504 /** 12505 * Called when the view should apply {@link WindowInsets} according to its internal policy. 12506 * 12507 * <p>This method should be overridden by views that wish to apply a policy different from or 12508 * in addition to the default behavior. Clients that wish to force a view subtree 12509 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 12510 * 12511 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 12512 * it will be called during dispatch instead of this method. The listener may optionally 12513 * call this method from its own implementation if it wishes to apply the view's default 12514 * insets policy in addition to its own.</p> 12515 * 12516 * <p>Implementations of this method should either return the insets parameter unchanged 12517 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 12518 * that this view applied itself. This allows new inset types added in future platform 12519 * versions to pass through existing implementations unchanged without being erroneously 12520 * consumed.</p> 12521 * 12522 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 12523 * property is set then the view will consume the system window insets and apply them 12524 * as padding for the view.</p> 12525 * 12526 * @param insets Insets to apply 12527 * @return The supplied insets with any applied insets consumed 12528 */ 12529 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 12530 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 12531 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 12532 return onApplyFrameworkOptionalFitSystemWindows(insets); 12533 } 12534 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 12535 // We weren't called from within a direct call to fitSystemWindows, 12536 // call into it as a fallback in case we're in a class that overrides it 12537 // and has logic to perform. 12538 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 12539 return insets.consumeSystemWindowInsets(); 12540 } 12541 } else { 12542 // We were called from within a direct call to fitSystemWindows. 12543 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 12544 return insets.consumeSystemWindowInsets(); 12545 } 12546 } 12547 return insets; 12548 } 12549 12550 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 12551 Rect localInsets = sThreadLocal.get(); 12552 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 12553 applyInsets(localInsets); 12554 return result; 12555 } 12556 12557 /** 12558 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 12559 * window insets to this view. The listener's 12560 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 12561 * method will be called instead of the view's 12562 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 12563 * 12564 * @param listener Listener to set 12565 * 12566 * @see #onApplyWindowInsets(WindowInsets) 12567 */ 12568 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 12569 getListenerInfo().mOnApplyWindowInsetsListener = listener; 12570 } 12571 12572 /** 12573 * Request to apply the given window insets to this view or another view in its subtree. 12574 * 12575 * <p>This method should be called by clients wishing to apply insets corresponding to areas 12576 * obscured by window decorations or overlays. This can include the status and navigation bars, 12577 * action bars, input methods and more. New inset categories may be added in the future. 12578 * The method returns the insets provided minus any that were applied by this view or its 12579 * children.</p> 12580 * 12581 * <p>Clients wishing to provide custom behavior should override the 12582 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 12583 * {@link OnApplyWindowInsetsListener} via the 12584 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 12585 * method.</p> 12586 * 12587 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 12588 * </p> 12589 * 12590 * @param insets Insets to apply 12591 * @return The provided insets minus the insets that were consumed 12592 */ 12593 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 12594 try { 12595 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 12596 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 12597 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 12598 } else { 12599 return onApplyWindowInsets(insets); 12600 } 12601 } finally { 12602 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 12603 } 12604 } 12605 12606 /** 12607 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 12608 * cause insets. 12609 * <p> 12610 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 12611 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 12612 * this view. 12613 * </p> 12614 * @param callback The callback to set. 12615 */ 12616 public void setWindowInsetsAnimationCallback( 12617 @Nullable WindowInsetsAnimation.Callback callback) { 12618 getListenerInfo().mWindowInsetsAnimationCallback = callback; 12619 } 12620 12621 /** 12622 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 12623 * or view tree of the sub-hierarchy {@code false} otherwise. 12624 * @hide 12625 */ 12626 public boolean hasWindowInsetsAnimationCallback() { 12627 return getListenerInfo().mWindowInsetsAnimationCallback != null; 12628 } 12629 12630 /** 12631 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 12632 * when Window Insets animation is being prepared. 12633 * @param animation current animation 12634 * 12635 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 12636 */ 12637 public void dispatchWindowInsetsAnimationPrepare( 12638 @NonNull WindowInsetsAnimation animation) { 12639 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12640 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 12641 } 12642 } 12643 12644 /** 12645 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 12646 * when Window Insets animation is started. 12647 * @param animation current animation 12648 * @param bounds the upper and lower {@link Bounds} that provides range of 12649 * {@link WindowInsetsAnimation}. 12650 * @return the upper and lower {@link Bounds}. 12651 */ 12652 @NonNull 12653 public Bounds dispatchWindowInsetsAnimationStart( 12654 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 12655 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12656 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 12657 } 12658 return bounds; 12659 } 12660 12661 /** 12662 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 12663 * when Window Insets animation makes progress. 12664 * @param insets The current {@link WindowInsets}. 12665 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 12666 * @return current {@link WindowInsets}. 12667 */ 12668 @NonNull 12669 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 12670 @NonNull List<WindowInsetsAnimation> runningAnimations) { 12671 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12672 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 12673 runningAnimations); 12674 } else { 12675 return insets; 12676 } 12677 } 12678 12679 /** 12680 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 12681 * when Window Insets animation ends. 12682 * @param animation The current ongoing {@link WindowInsetsAnimation}. 12683 */ 12684 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 12685 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12686 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 12687 } 12688 } 12689 12690 /** 12691 * Sets a list of areas within this view's post-layout coordinate space where the system 12692 * should not intercept touch or other pointing device gestures. <em>This method should 12693 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 12694 * 12695 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 12696 * input in order to function correctly in the presence of global system gestures that may 12697 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 12698 * to provide system-level navigation functionality, a view such as a navigation drawer 12699 * container can mark the left (or starting) edge of itself as requiring gesture capture 12700 * priority using this API. The system may then choose to relax its own gesture recognition 12701 * to allow the app to consume the user's gesture. It is not necessary for an app to register 12702 * exclusion rects for broadly spanning regions such as the entirety of a 12703 * <code>ScrollView</code> or for simple press and release click targets such as 12704 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 12705 * a precision touch gesture in a small area in either the X or Y dimension, such as 12706 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 12707 * 12708 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 12709 * exclusions it takes into account. The limit does not apply while the navigation 12710 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 12711 * {@link android.inputmethodservice.InputMethodService input method} and 12712 * {@link Intent#CATEGORY_HOME home activity}. 12713 * </p> 12714 * 12715 * @param rects A list of precision gesture regions that this view needs to function correctly 12716 */ 12717 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 12718 if (rects.isEmpty() && mListenerInfo == null) return; 12719 12720 final ListenerInfo info = getListenerInfo(); 12721 if (info.mSystemGestureExclusionRects != null) { 12722 info.mSystemGestureExclusionRects.clear(); 12723 info.mSystemGestureExclusionRects.addAll(rects); 12724 } else { 12725 info.mSystemGestureExclusionRects = new ArrayList<>(rects); 12726 } 12727 12728 updatePositionUpdateListener(); 12729 postUpdate(this::updateSystemGestureExclusionRects); 12730 } 12731 12732 private void updatePositionUpdateListener() { 12733 final ListenerInfo info = getListenerInfo(); 12734 if (getSystemGestureExclusionRects().isEmpty() 12735 && collectPreferKeepClearRects().isEmpty() 12736 && collectUnrestrictedPreferKeepClearRects().isEmpty() 12737 && (info.mHandwritingArea == null || !shouldTrackHandwritingArea())) { 12738 if (info.mPositionUpdateListener != null) { 12739 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 12740 info.mPositionUpdateListener = null; 12741 info.mPositionChangedUpdate = null; 12742 } 12743 } else { 12744 if (info.mPositionUpdateListener == null) { 12745 info.mPositionChangedUpdate = () -> { 12746 updateSystemGestureExclusionRects(); 12747 updateKeepClearRects(); 12748 updateHandwritingArea(); 12749 }; 12750 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 12751 @Override 12752 public void positionChanged(long n, int l, int t, int r, int b) { 12753 postUpdate(info.mPositionChangedUpdate); 12754 } 12755 12756 @Override 12757 public void positionLost(long frameNumber) { 12758 postUpdate(info.mPositionChangedUpdate); 12759 } 12760 }; 12761 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 12762 } 12763 } 12764 } 12765 12766 /** 12767 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 12768 */ 12769 private void postUpdate(Runnable r) { 12770 // Potentially racey from a background thread. It's ok if it's not perfect. 12771 final Handler h = getHandler(); 12772 if (h != null) { 12773 h.postAtFrontOfQueue(r); 12774 } 12775 } 12776 12777 void updateSystemGestureExclusionRects() { 12778 final AttachInfo ai = mAttachInfo; 12779 if (ai != null) { 12780 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 12781 } 12782 } 12783 12784 /** 12785 * Retrieve the list of areas within this view's post-layout coordinate space where the system 12786 * should not intercept touch or other pointing device gestures. 12787 * 12788 * <p>Do not modify the returned list.</p> 12789 * 12790 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 12791 */ 12792 @NonNull 12793 public List<Rect> getSystemGestureExclusionRects() { 12794 final ListenerInfo info = mListenerInfo; 12795 if (info != null) { 12796 final List<Rect> list = info.mSystemGestureExclusionRects; 12797 if (list != null) { 12798 return list; 12799 } 12800 } 12801 return Collections.emptyList(); 12802 } 12803 12804 /** 12805 * Set a preference to keep the bounds of this view clear from floating windows above this 12806 * view's window. This informs the system that the view is considered a vital area for the 12807 * user and that ideally it should not be covered. Setting this is only appropriate for UI 12808 * where the user would likely take action to uncover it. 12809 * <p> 12810 * The system will try to respect this preference, but when not possible will ignore it. 12811 * <p> 12812 * Note: This is independent from {@link #setPreferKeepClearRects}. If both are set, both will 12813 * be taken into account. 12814 * <p> 12815 * @see #setPreferKeepClearRects 12816 * @see #isPreferKeepClear 12817 * @attr ref android.R.styleable#View_preferKeepClear 12818 */ 12819 public final void setPreferKeepClear(boolean preferKeepClear) { 12820 getListenerInfo().mPreferKeepClear = preferKeepClear; 12821 updatePositionUpdateListener(); 12822 postUpdate(this::updateKeepClearRects); 12823 } 12824 12825 /** 12826 * Retrieve the preference for this view to be kept clear. This is set either by 12827 * {@link #setPreferKeepClear} or via the attribute android.R.styleable#View_preferKeepClear. 12828 * <p> 12829 * If this is {@code true}, the system will ignore the Rects set by 12830 * {@link #setPreferKeepClearRects} and try to keep the whole view clear. 12831 * <p> 12832 * @see #setPreferKeepClear 12833 * @attr ref android.R.styleable#View_preferKeepClear 12834 */ 12835 public final boolean isPreferKeepClear() { 12836 return mListenerInfo != null && mListenerInfo.mPreferKeepClear; 12837 } 12838 12839 /** 12840 * Set a preference to keep the provided rects clear from floating windows above this 12841 * view's window. This informs the system that these rects are considered vital areas for the 12842 * user and that ideally they should not be covered. Setting this is only appropriate for UI 12843 * where the user would likely take action to uncover it. 12844 * <p> 12845 * The system will try to respect this preference, but when not possible will ignore it. 12846 * <p> 12847 * Note: This is independent from {@link #setPreferKeepClear}. If both are set, both will be 12848 * taken into account. 12849 * <p> 12850 * @see #setPreferKeepClear 12851 * @see #getPreferKeepClearRects 12852 * 12853 * @param rects A list of rects in this view's local coordinate system 12854 */ 12855 public final void setPreferKeepClearRects(@NonNull List<Rect> rects) { 12856 final ListenerInfo info = getListenerInfo(); 12857 if (info.mKeepClearRects != null) { 12858 info.mKeepClearRects.clear(); 12859 info.mKeepClearRects.addAll(rects); 12860 } else { 12861 info.mKeepClearRects = new ArrayList<>(rects); 12862 } 12863 updatePositionUpdateListener(); 12864 postUpdate(this::updateKeepClearRects); 12865 } 12866 12867 /** 12868 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 12869 * 12870 * @see #setPreferKeepClearRects 12871 */ 12872 @NonNull 12873 public final List<Rect> getPreferKeepClearRects() { 12874 final ListenerInfo info = mListenerInfo; 12875 if (info != null && info.mKeepClearRects != null) { 12876 return new ArrayList(info.mKeepClearRects); 12877 } 12878 12879 return Collections.emptyList(); 12880 } 12881 12882 /** 12883 * Set a preference to keep the provided rects clear from floating windows above this 12884 * view's window. This informs the system that these rects are considered vital areas for the 12885 * user and that ideally they should not be covered. Setting this is only appropriate for UI 12886 * where the user would likely take action to uncover it. 12887 * <p> 12888 * Note: The difference with {@link #setPreferKeepClearRects} is that the system won't apply 12889 * restrictions to the rects set here. 12890 * <p> 12891 * @see #setPreferKeepClear 12892 * @see #getPreferKeepClearRects 12893 * 12894 * @param rects A list of rects in this view's local coordinate system 12895 * 12896 * @hide 12897 */ 12898 @SystemApi 12899 @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) 12900 public final void setUnrestrictedPreferKeepClearRects(@NonNull List<Rect> rects) { 12901 final ListenerInfo info = getListenerInfo(); 12902 if (info.mUnrestrictedKeepClearRects != null) { 12903 info.mUnrestrictedKeepClearRects.clear(); 12904 info.mUnrestrictedKeepClearRects.addAll(rects); 12905 } else { 12906 info.mUnrestrictedKeepClearRects = new ArrayList<>(rects); 12907 } 12908 updatePositionUpdateListener(); 12909 postUpdate(this::updateKeepClearRects); 12910 } 12911 12912 /** 12913 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 12914 * 12915 * @see #setPreferKeepClearRects 12916 * 12917 * @hide 12918 */ 12919 @SystemApi 12920 @NonNull 12921 public final List<Rect> getUnrestrictedPreferKeepClearRects() { 12922 final ListenerInfo info = mListenerInfo; 12923 if (info != null && info.mUnrestrictedKeepClearRects != null) { 12924 return new ArrayList(info.mUnrestrictedKeepClearRects); 12925 } 12926 12927 return Collections.emptyList(); 12928 } 12929 12930 void updateKeepClearRects() { 12931 final AttachInfo ai = mAttachInfo; 12932 if (ai != null) { 12933 ai.mViewRootImpl.updateKeepClearRectsForView(this); 12934 } 12935 } 12936 12937 /** 12938 * Retrieve the list of areas within this view's post-layout coordinate space which the 12939 * system will try to not cover with other floating elements, like the pip window. 12940 */ 12941 @NonNull 12942 List<Rect> collectPreferKeepClearRects() { 12943 ListenerInfo info = mListenerInfo; 12944 boolean keepClearForFocus = isFocused() 12945 && ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled(); 12946 boolean keepBoundsClear = (info != null && info.mPreferKeepClear) || keepClearForFocus; 12947 boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null; 12948 12949 if (!keepBoundsClear && !hasCustomKeepClearRects) { 12950 return Collections.emptyList(); 12951 } else if (keepBoundsClear && !hasCustomKeepClearRects) { 12952 return Collections.singletonList(new Rect(0, 0, getWidth(), getHeight())); 12953 } 12954 12955 final List<Rect> list = new ArrayList<>(); 12956 if (keepBoundsClear) { 12957 list.add(new Rect(0, 0, getWidth(), getHeight())); 12958 } 12959 12960 if (hasCustomKeepClearRects) { 12961 list.addAll(info.mKeepClearRects); 12962 } 12963 12964 return list; 12965 } 12966 12967 private void updatePreferKeepClearForFocus() { 12968 if (ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()) { 12969 updatePositionUpdateListener(); 12970 post(this::updateKeepClearRects); 12971 } 12972 } 12973 12974 /** 12975 * Retrieve the list of unrestricted areas within this view's post-layout coordinate space 12976 * which the system will try to not cover with other floating elements, like the pip window. 12977 */ 12978 @NonNull 12979 List<Rect> collectUnrestrictedPreferKeepClearRects() { 12980 final ListenerInfo info = mListenerInfo; 12981 if (info != null && info.mUnrestrictedKeepClearRects != null) { 12982 return info.mUnrestrictedKeepClearRects; 12983 } 12984 12985 return Collections.emptyList(); 12986 } 12987 12988 /** 12989 * Set the amount of offset applied to this view's stylus handwriting bounds. A positive offset 12990 * will offset the edge outwards.The base handwriting bounds of a view is its visible bounds. 12991 * The handwriting bounds offsets are applied to the base handwriting bounds to determine the 12992 * final handwriting bounds. 12993 * <p> This method is mainly used to enlarge the view's handwriting bounds for a better user 12994 * experience. 12995 * <p> Note that when the view is clipped (e.g. the view is in a 12996 * {@link android.widget.ScrollView}), the offsets are applied after the view's handwriting 12997 * bounds is clipped. 12998 * 12999 * @param offsetLeft the amount of pixel offset applied to the left edge outwards of the view's 13000 * handwriting bounds. 13001 * @param offsetTop the amount of pixel offset applied to the top edge outwards of the view's 13002 * handwriting bounds. 13003 * @param offsetRight the amount of pixel offset applied to the right edge outwards of the 13004 * view's handwriting bounds. 13005 * @param offsetBottom the amount of pixel offset applied to the bottom edge outwards of the 13006 * view's handwriting bounds. 13007 * 13008 * @see #setAutoHandwritingEnabled(boolean) 13009 * @see #getHandwritingBoundsOffsetLeft() 13010 * @see #getHandwritingBoundsOffsetTop() 13011 * @see #getHandwritingBoundsOffsetRight() 13012 * @see #getHandwritingBoundsOffsetBottom() 13013 */ 13014 public void setHandwritingBoundsOffsets(float offsetLeft, float offsetTop, 13015 float offsetRight, float offsetBottom) { 13016 mHandwritingBoundsOffsetLeft = offsetLeft; 13017 mHandwritingBoundsOffsetTop = offsetTop; 13018 mHandwritingBoundsOffsetRight = offsetRight; 13019 mHandwritingBoundsOffsetBottom = offsetBottom; 13020 } 13021 13022 /** 13023 * Return the amount of offset applied to the left edge of this view's handwriting bounds, 13024 * in the unit of pixel. 13025 * 13026 * @see #setAutoHandwritingEnabled(boolean) 13027 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13028 */ 13029 public float getHandwritingBoundsOffsetLeft() { 13030 return mHandwritingBoundsOffsetLeft; 13031 } 13032 13033 /** 13034 * Return the amount of offset applied to the top edge of this view's handwriting bounds, 13035 * in the unit of pixel. 13036 * 13037 * @see #setAutoHandwritingEnabled(boolean) 13038 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13039 */ 13040 public float getHandwritingBoundsOffsetTop() { 13041 return mHandwritingBoundsOffsetTop; 13042 } 13043 13044 /** 13045 * Return the amount of offset applied to the right edge of this view's handwriting bounds, in 13046 * the unit of pixel. 13047 * 13048 * @see #setAutoHandwritingEnabled(boolean) 13049 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13050 */ 13051 public float getHandwritingBoundsOffsetRight() { 13052 return mHandwritingBoundsOffsetRight; 13053 } 13054 13055 /** 13056 * Return the amount of offset applied to the bottom edge of this view's handwriting bounds, in 13057 * the unit of pixel. 13058 * 13059 * @see #setAutoHandwritingEnabled(boolean) 13060 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13061 */ 13062 public float getHandwritingBoundsOffsetBottom() { 13063 return mHandwritingBoundsOffsetBottom; 13064 } 13065 13066 13067 /** 13068 * Set a handwriting area in this view. If there is any stylus {@link MotionEvent} 13069 * occurs within this area, it will trigger stylus handwriting mode. This can be disabled by 13070 * disabling the auto handwriting initiation by calling 13071 * {@link #setAutoHandwritingEnabled(boolean)} with false. 13072 * 13073 * @attr rect the handwriting area in the view's local coordiniates. 13074 * 13075 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 13076 * @see #setAutoHandwritingEnabled(boolean) 13077 * 13078 * @hide 13079 */ 13080 public void setHandwritingArea(@Nullable Rect rect) { 13081 final ListenerInfo info = getListenerInfo(); 13082 info.mHandwritingArea = rect; 13083 updatePositionUpdateListener(); 13084 postUpdate(this::updateHandwritingArea); 13085 } 13086 13087 /** 13088 * Return the handwriting areas set on this view, in its local coordinates. 13089 * @see #setHandwritingArea(Rect) 13090 * 13091 * @hide 13092 */ 13093 @Nullable 13094 public Rect getHandwritingArea() { 13095 final ListenerInfo info = mListenerInfo; 13096 if (info != null && info.mHandwritingArea != null) { 13097 return new Rect(info.mHandwritingArea); 13098 } 13099 return null; 13100 } 13101 13102 void updateHandwritingArea() { 13103 // If autoHandwritingArea is not enabled, do nothing. 13104 if (!shouldTrackHandwritingArea()) return; 13105 final AttachInfo ai = mAttachInfo; 13106 if (ai != null) { 13107 ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this); 13108 } 13109 } 13110 13111 /** 13112 * Returns true if a stylus {@link MotionEvent} within this view's bounds should initiate 13113 * handwriting mode, either for this view ({@link #isAutoHandwritingEnabled()} is {@code true}) 13114 * or for a handwriting delegate view ({@link #getHandwritingDelegatorCallback()} is not {@code 13115 * null}). 13116 */ 13117 boolean shouldInitiateHandwriting() { 13118 return isAutoHandwritingEnabled() || getHandwritingDelegatorCallback() != null; 13119 } 13120 13121 /** 13122 * Returns whether the handwriting initiator should track the handwriting area for this view, 13123 * either to initiate handwriting mode, or to prepare handwriting delegation, or to show the 13124 * handwriting unsupported message. 13125 * @hide 13126 */ 13127 public boolean shouldTrackHandwritingArea() { 13128 return shouldInitiateHandwriting(); 13129 } 13130 13131 /** 13132 * Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this 13133 * view's bounds. The callback will be called from the UI thread. 13134 * 13135 * <p>Setting a callback allows this view to act as a handwriting delegator, so that handwriting 13136 * mode for a delegate editor view can be initiated by stylus movement on this delegator view. 13137 * The callback implementation is expected to show and focus the delegate editor view. If a view 13138 * which returns {@code true} for {@link #isHandwritingDelegate()} creates an input connection 13139 * while the same stylus {@link MotionEvent} sequence is ongoing, handwriting mode will be 13140 * initiated for that view. 13141 * 13142 * <p>A common use case is a custom view which looks like a text editor but does not actually 13143 * support text editing itself, and clicking on the custom view causes an EditText to be shown. 13144 * To support handwriting initiation in this case, this method can be called on the custom view 13145 * to configure it as a delegator. The EditText should call {@link #setIsHandwritingDelegate} to 13146 * set it as a delegate. The {@code callback} implementation is typically the same as the click 13147 * listener implementation which shows the EditText. 13148 * 13149 * <p>If {@code null} is passed, this view will no longer act as a handwriting initiation 13150 * delegator. 13151 * 13152 * @param callback a callback which should be called when a stylus {@link MotionEvent} occurs 13153 * within this view's bounds 13154 */ 13155 public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { 13156 mHandwritingDelegatorCallback = callback; 13157 if (callback != null) { 13158 setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); 13159 } 13160 } 13161 13162 /** 13163 * Returns the callback set by {@link #setHandwritingDelegatorCallback} which should be called 13164 * when a stylus {@link MotionEvent} occurs within this view's bounds. The callback should only 13165 * be called from the UI thread. 13166 */ 13167 @Nullable 13168 public Runnable getHandwritingDelegatorCallback() { 13169 return mHandwritingDelegatorCallback; 13170 } 13171 13172 /** 13173 * Specifies that this view may act as a handwriting initiation delegator for a delegate editor 13174 * view from the specified package. If this method is not called, delegators may only be used to 13175 * initiate handwriting mode for a delegate editor view from the same package as the delegator 13176 * view. This method allows specifying a different trusted package which may contain a delegate 13177 * editor view linked to this delegator view. 13178 * 13179 * <p>This method has no effect unless {@link #setHandwritingDelegatorCallback} is also called 13180 * to configure this view to act as a handwriting delegator. 13181 * 13182 * <p>If this method is called on the delegator view, then {@link 13183 * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view. 13184 * 13185 * <p>For example, to configure a delegator view in package 1: 13186 * 13187 * <pre> 13188 * delegatorView.setHandwritingDelegatorCallback(callback); 13189 * delegatorView.setAllowedHandwritingDelegatePackage(package2);</pre> 13190 * 13191 * Then to configure the corresponding delegate editor view in package 2: 13192 * 13193 * <pre> 13194 * delegateEditorView.setIsHandwritingDelegate(true); 13195 * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);</pre> 13196 * 13197 * @param allowedPackageName the package name of a delegate editor view linked to this delegator 13198 * view, or {@code null} to restore the default behavior of only allowing delegate editor 13199 * views from the same package as this delegator view 13200 */ 13201 public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) { 13202 mAllowedHandwritingDelegatePackageName = allowedPackageName; 13203 } 13204 13205 /** 13206 * Returns the allowed package for delegate editor views for which this view may act as a 13207 * handwriting delegator, as set by {@link #setAllowedHandwritingDelegatePackage}. If {@link 13208 * #setAllowedHandwritingDelegatePackage} has not been called, or called with {@code null} 13209 * argument, this will return {@code null}, meaning that this delegator view may only be used to 13210 * initiate handwriting mode for a delegate editor view from the same package as this delegator 13211 * view. 13212 */ 13213 @Nullable 13214 public String getAllowedHandwritingDelegatePackageName() { 13215 return mAllowedHandwritingDelegatePackageName; 13216 } 13217 13218 /** 13219 * Sets this view to be a handwriting delegate. If a delegate view creates an input connection 13220 * while a stylus {@link MotionEvent} sequence from a delegator view is ongoing, handwriting 13221 * mode will be initiated for the delegate view. 13222 * 13223 * @param isHandwritingDelegate whether this view is a handwriting initiation delegate 13224 * @see #setHandwritingDelegatorCallback(Runnable) 13225 */ 13226 public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { 13227 mIsHandwritingDelegate = isHandwritingDelegate; 13228 } 13229 13230 /** 13231 * Returns whether this view has been set as a handwriting delegate by {@link 13232 * #setIsHandwritingDelegate}. 13233 */ 13234 public boolean isHandwritingDelegate() { 13235 return mIsHandwritingDelegate; 13236 } 13237 13238 /** 13239 * Specifies that a view from the specified package may act as a handwriting delegator for this 13240 * delegate editor view. If this method is not called, only views from the same package as this 13241 * delegate editor view may act as a handwriting delegator. This method allows specifying a 13242 * different trusted package which may contain a delegator view linked to this delegate editor 13243 * view. 13244 * 13245 * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to 13246 * configure this view to act as a handwriting delegate. 13247 * 13248 * <p>If this method is called on the delegate editor view, then {@link 13249 * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view. 13250 * 13251 * @param allowedPackageName the package name of a delegator view linked to this delegate editor 13252 * view, or {@code null} to restore the default behavior of only allowing delegator views 13253 * from the same package as this delegate editor view 13254 */ 13255 public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) { 13256 mAllowedHandwritingDelegatorPackageName = allowedPackageName; 13257 } 13258 13259 /** 13260 * Returns the allowed package for views which may act as a handwriting delegator for this 13261 * delegate editor view, as set by {@link #setAllowedHandwritingDelegatorPackage}. If {@link 13262 * #setAllowedHandwritingDelegatorPackage} has not been called, or called with {@code null} 13263 * argument, this will return {@code null}, meaning that only views from the same package as 13264 * this delegator editor view may act as a handwriting delegator. 13265 */ 13266 @Nullable 13267 public String getAllowedHandwritingDelegatorPackageName() { 13268 return mAllowedHandwritingDelegatorPackageName; 13269 } 13270 13271 /** 13272 * Sets flags configuring the handwriting delegation behavior for this delegate editor view. 13273 * 13274 * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to 13275 * configure this view to act as a handwriting delegate. 13276 * 13277 * @param flags {@link InputMethodManager#HANDWRITING_DELEGATE_FLAG_HOME_DELEGATOR_ALLOWED} or 13278 * {@code 0} 13279 */ 13280 @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) 13281 public void setHandwritingDelegateFlags( 13282 @InputMethodManager.HandwritingDelegateFlags int flags) { 13283 mHandwritingDelegateFlags = flags; 13284 } 13285 13286 /** 13287 * Returns flags configuring the handwriting delegation behavior for this delegate editor view, 13288 * as set by {@link #setHandwritingDelegateFlags}. 13289 */ 13290 @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) 13291 public @InputMethodManager.HandwritingDelegateFlags int getHandwritingDelegateFlags() { 13292 return mHandwritingDelegateFlags; 13293 } 13294 13295 /** 13296 * Gets the coordinates of this view in the coordinate space of the 13297 * {@link Surface} that contains the view. 13298 * 13299 * <p>In multiple-screen scenarios, if the surface spans multiple screens, 13300 * the coordinate space of the surface also spans multiple screens. 13301 * 13302 * <p>After the method returns, the argument array contains the x and y 13303 * coordinates of the view relative to the view's left and top edges, 13304 * respectively. 13305 * 13306 * @param location A two-element integer array in which the view coordinates 13307 * are stored. The x-coordinate is at index 0; the y-coordinate, at 13308 * index 1. 13309 */ 13310 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 13311 getLocationInWindow(location); 13312 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 13313 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 13314 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 13315 } 13316 } 13317 13318 /** 13319 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 13320 * only available if the view is attached. 13321 * 13322 * @return WindowInsets from the top of the view hierarchy or null if View is detached 13323 */ 13324 public WindowInsets getRootWindowInsets() { 13325 if (mAttachInfo != null) { 13326 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 13327 } 13328 return null; 13329 } 13330 13331 /** 13332 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 13333 * 13334 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 13335 * a window nor a view tree with a decor. 13336 * @see Window#getInsetsController() 13337 */ 13338 public @Nullable WindowInsetsController getWindowInsetsController() { 13339 if (mAttachInfo != null) { 13340 return mAttachInfo.mViewRootImpl.getInsetsController(); 13341 } 13342 ViewParent parent = getParent(); 13343 if (parent instanceof View) { 13344 return ((View) parent).getWindowInsetsController(); 13345 } else if (parent instanceof ViewRootImpl) { 13346 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 13347 return ((ViewRootImpl) parent).getInsetsController(); 13348 } 13349 return null; 13350 } 13351 13352 13353 /** 13354 * Walk up the View hierarchy to find the nearest {@link OnBackInvokedDispatcher}. 13355 * 13356 * @return The {@link OnBackInvokedDispatcher} from this or the nearest 13357 * ancestor, or null if this view is both not attached and have no ancestor providing an 13358 * {@link OnBackInvokedDispatcher}. 13359 */ 13360 @Nullable 13361 public final OnBackInvokedDispatcher findOnBackInvokedDispatcher() { 13362 ViewParent parent = getParent(); 13363 if (parent != null) { 13364 return parent.findOnBackInvokedDispatcherForChild(this, this); 13365 } 13366 return null; 13367 } 13368 13369 /** 13370 * @hide Compute the insets that should be consumed by this view and the ones 13371 * that should propagate to those under it. 13372 * 13373 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 13374 * 13375 * @param inoutInsets the insets given to this view 13376 * @param outLocalInsets the insets that should be applied to this view 13377 * @deprecated use {@link #computeSystemWindowInsets} 13378 * @return 13379 */ 13380 @Deprecated 13381 @UnsupportedAppUsage 13382 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 13383 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 13384 outLocalInsets); 13385 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 13386 return innerInsets.isSystemWindowInsetsConsumed(); 13387 } 13388 13389 /** 13390 * Compute insets that should be consumed by this view and the ones that should propagate 13391 * to those under it. 13392 * 13393 * @param in Insets currently being processed by this View, likely received as a parameter 13394 * to {@link #onApplyWindowInsets(WindowInsets)}. 13395 * @param outLocalInsets A Rect that will receive the insets that should be consumed 13396 * by this view 13397 * @return Insets that should be passed along to views under this one 13398 */ 13399 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 13400 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 13401 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 13402 if (isOptionalFitSystemWindows && mAttachInfo != null) { 13403 OnContentApplyWindowInsetsListener listener = 13404 mAttachInfo.mContentOnApplyWindowInsetsListener; 13405 if (listener == null) { 13406 // The application wants to take care of fitting system window for 13407 // the content. 13408 outLocalInsets.setEmpty(); 13409 return in; 13410 } 13411 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 13412 outLocalInsets.set(result.first.toRect()); 13413 return result.second; 13414 } else { 13415 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 13416 return in.consumeSystemWindowInsets().inset(outLocalInsets); 13417 } 13418 } 13419 13420 /** 13421 * @return True if the window has the {@link OnContentApplyWindowInsetsListener}, and this means 13422 * the framework will apply window insets on the content of the window. 13423 * @hide 13424 */ 13425 protected boolean hasContentOnApplyWindowInsetsListener() { 13426 return mAttachInfo != null && mAttachInfo.mContentOnApplyWindowInsetsListener != null; 13427 } 13428 13429 /** 13430 * Sets whether or not this view should account for system screen decorations 13431 * such as the status bar and inset its content; that is, controlling whether 13432 * the default implementation of {@link #fitSystemWindows(Rect)} will be 13433 * executed. See that method for more details. 13434 * 13435 * <p>Note that if you are providing your own implementation of 13436 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 13437 * flag to true -- your implementation will be overriding the default 13438 * implementation that checks this flag. 13439 * 13440 * @param fitSystemWindows If true, then the default implementation of 13441 * {@link #fitSystemWindows(Rect)} will be executed. 13442 * 13443 * @attr ref android.R.styleable#View_fitsSystemWindows 13444 * @see #getFitsSystemWindows() 13445 * @see #fitSystemWindows(Rect) 13446 * @see #setSystemUiVisibility(int) 13447 */ 13448 public void setFitsSystemWindows(boolean fitSystemWindows) { 13449 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 13450 } 13451 13452 /** 13453 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 13454 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 13455 * will be executed. 13456 * 13457 * @return {@code true} if the default implementation of 13458 * {@link #fitSystemWindows(Rect)} will be executed. 13459 * 13460 * @attr ref android.R.styleable#View_fitsSystemWindows 13461 * @see #setFitsSystemWindows(boolean) 13462 * @see #fitSystemWindows(Rect) 13463 * @see #setSystemUiVisibility(int) 13464 */ 13465 @ViewDebug.ExportedProperty 13466 @InspectableProperty 13467 public boolean getFitsSystemWindows() { 13468 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 13469 } 13470 13471 /** @hide */ 13472 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 13473 public boolean fitsSystemWindows() { 13474 return getFitsSystemWindows(); 13475 } 13476 13477 /** 13478 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 13479 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 13480 */ 13481 @Deprecated 13482 public void requestFitSystemWindows() { 13483 if (mParent != null) { 13484 mParent.requestFitSystemWindows(); 13485 } 13486 } 13487 13488 /** 13489 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 13490 */ 13491 public void requestApplyInsets() { 13492 requestFitSystemWindows(); 13493 } 13494 13495 /** 13496 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 13497 * @hide 13498 */ 13499 @UnsupportedAppUsage 13500 public void makeOptionalFitsSystemWindows() { 13501 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 13502 } 13503 13504 /** 13505 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 13506 * @hide 13507 */ 13508 public void makeFrameworkOptionalFitsSystemWindows() { 13509 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 13510 } 13511 13512 /** 13513 * @hide 13514 */ 13515 public boolean isFrameworkOptionalFitsSystemWindows() { 13516 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 13517 } 13518 13519 /** 13520 * Returns the visibility status for this view. 13521 * 13522 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 13523 * @attr ref android.R.styleable#View_visibility 13524 */ 13525 @ViewDebug.ExportedProperty(mapping = { 13526 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 13527 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 13528 @ViewDebug.IntToString(from = GONE, to = "GONE") 13529 }) 13530 @InspectableProperty(enumMapping = { 13531 @EnumEntry(value = VISIBLE, name = "visible"), 13532 @EnumEntry(value = INVISIBLE, name = "invisible"), 13533 @EnumEntry(value = GONE, name = "gone") 13534 }) 13535 @Visibility 13536 public int getVisibility() { 13537 return mViewFlags & VISIBILITY_MASK; 13538 } 13539 13540 /** 13541 * Set the visibility state of this view. 13542 * 13543 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 13544 * @attr ref android.R.styleable#View_visibility 13545 */ 13546 @RemotableViewMethod 13547 public void setVisibility(@Visibility int visibility) { 13548 setFlags(visibility, VISIBILITY_MASK); 13549 } 13550 13551 /** 13552 * Returns the enabled status for this view. The interpretation of the 13553 * enabled state varies by subclass. 13554 * 13555 * @return True if this view is enabled, false otherwise. 13556 */ 13557 @ViewDebug.ExportedProperty 13558 @InspectableProperty 13559 public boolean isEnabled() { 13560 return (mViewFlags & ENABLED_MASK) == ENABLED; 13561 } 13562 13563 /** 13564 * Set the enabled state of this view. The interpretation of the enabled 13565 * state varies by subclass. 13566 * 13567 * @param enabled True if this view is enabled, false otherwise. 13568 */ 13569 @RemotableViewMethod 13570 public void setEnabled(boolean enabled) { 13571 if (enabled == isEnabled()) return; 13572 13573 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 13574 13575 /* 13576 * The View most likely has to change its appearance, so refresh 13577 * the drawable state. 13578 */ 13579 refreshDrawableState(); 13580 13581 // Invalidate too, since the default behavior for views is to be 13582 // be drawn at 50% alpha rather than to change the drawable. 13583 invalidate(true); 13584 13585 if (!enabled) { 13586 cancelPendingInputEvents(); 13587 } 13588 notifyViewAccessibilityStateChangedIfNeeded( 13589 AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED); 13590 } 13591 13592 /** 13593 * Set whether this view can receive the focus. 13594 * <p> 13595 * Setting this to false will also ensure that this view is not focusable 13596 * in touch mode. 13597 * 13598 * @param focusable If true, this view can receive the focus. 13599 * 13600 * @see #setFocusableInTouchMode(boolean) 13601 * @see #setFocusable(int) 13602 * @attr ref android.R.styleable#View_focusable 13603 */ 13604 @RemotableViewMethod 13605 public void setFocusable(boolean focusable) { 13606 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 13607 } 13608 13609 /** 13610 * Sets whether this view can receive focus. 13611 * <p> 13612 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 13613 * automatically based on the view's interactivity. This is the default. 13614 * <p> 13615 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 13616 * in touch mode. 13617 * 13618 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 13619 * or {@link #FOCUSABLE_AUTO}. 13620 * @see #setFocusableInTouchMode(boolean) 13621 * @attr ref android.R.styleable#View_focusable 13622 */ 13623 @RemotableViewMethod 13624 public void setFocusable(@Focusable int focusable) { 13625 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 13626 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 13627 } 13628 setFlags(focusable, FOCUSABLE_MASK); 13629 } 13630 13631 /** 13632 * Set whether this view can receive focus while in touch mode. 13633 * 13634 * Setting this to true will also ensure that this view is focusable. 13635 * 13636 * @param focusableInTouchMode If true, this view can receive the focus while 13637 * in touch mode. 13638 * 13639 * @see #setFocusable(boolean) 13640 * @attr ref android.R.styleable#View_focusableInTouchMode 13641 */ 13642 @RemotableViewMethod 13643 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 13644 // Focusable in touch mode should always be set before the focusable flag 13645 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 13646 // which, in touch mode, will not successfully request focus on this view 13647 // because the focusable in touch mode flag is not set 13648 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 13649 13650 // Clear FOCUSABLE_AUTO if set. 13651 if (focusableInTouchMode) { 13652 // Clears FOCUSABLE_AUTO if set. 13653 setFlags(FOCUSABLE, FOCUSABLE_MASK); 13654 } 13655 } 13656 13657 /** 13658 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 13659 * to autofill the view with the user's data. 13660 * 13661 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 13662 * For example, if the application accepts either an username or email address to identify 13663 * an user. 13664 * 13665 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 13666 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 13667 * constants such as: 13668 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 13669 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 13670 * {@link #AUTOFILL_HINT_NAME}, 13671 * {@link #AUTOFILL_HINT_PHONE}, 13672 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 13673 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 13674 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 13675 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 13676 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 13677 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 13678 * 13679 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 13680 * @attr ref android.R.styleable#View_autofillHints 13681 */ 13682 public void setAutofillHints(@Nullable String... autofillHints) { 13683 if (autofillHints == null || autofillHints.length == 0) { 13684 mAutofillHints = null; 13685 } else { 13686 mAutofillHints = autofillHints; 13687 } 13688 if (sensitiveContentAppProtection()) { 13689 if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) { 13690 updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); 13691 } 13692 } 13693 } 13694 13695 /** 13696 * @hide 13697 */ 13698 @TestApi 13699 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 13700 boolean wasChanged = isAutofilled != isAutofilled(); 13701 13702 if (wasChanged) { 13703 if (isAutofilled) { 13704 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 13705 } else { 13706 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 13707 } 13708 13709 if (hideHighlight) { 13710 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 13711 } else { 13712 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 13713 } 13714 13715 invalidate(); 13716 } 13717 } 13718 13719 /** 13720 * Set whether this view should have sound effects enabled for events such as 13721 * clicking and touching. 13722 * 13723 * <p>You may wish to disable sound effects for a view if you already play sounds, 13724 * for instance, a dial key that plays dtmf tones. 13725 * 13726 * @param soundEffectsEnabled whether sound effects are enabled for this view. 13727 * @see #isSoundEffectsEnabled() 13728 * @see #playSoundEffect(int) 13729 * @attr ref android.R.styleable#View_soundEffectsEnabled 13730 */ 13731 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 13732 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 13733 } 13734 13735 /** 13736 * @return whether this view should have sound effects enabled for events such as 13737 * clicking and touching. 13738 * 13739 * @see #setSoundEffectsEnabled(boolean) 13740 * @see #playSoundEffect(int) 13741 * @attr ref android.R.styleable#View_soundEffectsEnabled 13742 */ 13743 @ViewDebug.ExportedProperty 13744 @InspectableProperty 13745 public boolean isSoundEffectsEnabled() { 13746 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 13747 } 13748 13749 /** 13750 * Set whether this view should have haptic feedback for events such as 13751 * long presses. 13752 * 13753 * <p>You may wish to disable haptic feedback if your view already controls 13754 * its own haptic feedback. 13755 * 13756 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 13757 * @see #isHapticFeedbackEnabled() 13758 * @see #performHapticFeedback(int) 13759 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 13760 */ 13761 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 13762 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 13763 } 13764 13765 /** 13766 * @return whether this view should have haptic feedback enabled for events 13767 * such as long presses. 13768 * 13769 * @see #setHapticFeedbackEnabled(boolean) 13770 * @see #performHapticFeedback(int) 13771 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 13772 */ 13773 @ViewDebug.ExportedProperty 13774 @InspectableProperty 13775 public boolean isHapticFeedbackEnabled() { 13776 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 13777 } 13778 13779 /** 13780 * Returns the layout direction for this view. 13781 * 13782 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 13783 * {@link #LAYOUT_DIRECTION_RTL}, 13784 * {@link #LAYOUT_DIRECTION_INHERIT} or 13785 * {@link #LAYOUT_DIRECTION_LOCALE}. 13786 * 13787 * @attr ref android.R.styleable#View_layoutDirection 13788 * 13789 * @hide 13790 */ 13791 @ViewDebug.ExportedProperty(category = "layout", mapping = { 13792 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 13793 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 13794 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 13795 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 13796 }) 13797 @InspectableProperty(hasAttributeId = false, enumMapping = { 13798 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 13799 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 13800 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 13801 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 13802 }) 13803 @LayoutDir 13804 public int getRawLayoutDirection() { 13805 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 13806 } 13807 13808 /** 13809 * Set the layout direction for this view. This will propagate a reset of layout direction 13810 * resolution to the view's children and resolve layout direction for this view. 13811 * 13812 * @param layoutDirection the layout direction to set. Should be one of: 13813 * 13814 * {@link #LAYOUT_DIRECTION_LTR}, 13815 * {@link #LAYOUT_DIRECTION_RTL}, 13816 * {@link #LAYOUT_DIRECTION_INHERIT}, 13817 * {@link #LAYOUT_DIRECTION_LOCALE}. 13818 * 13819 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 13820 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 13821 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 13822 * 13823 * @attr ref android.R.styleable#View_layoutDirection 13824 */ 13825 @RemotableViewMethod 13826 public void setLayoutDirection(@LayoutDir int layoutDirection) { 13827 if (getRawLayoutDirection() != layoutDirection) { 13828 // Reset the current layout direction and the resolved one 13829 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 13830 resetRtlProperties(); 13831 // Set the new layout direction (filtered) 13832 mPrivateFlags2 |= 13833 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 13834 // We need to resolve all RTL properties as they all depend on layout direction 13835 resolveRtlPropertiesIfNeeded(); 13836 requestLayout(); 13837 invalidate(true); 13838 } 13839 } 13840 13841 /** 13842 * Returns the resolved layout direction for this view. 13843 * 13844 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 13845 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 13846 * 13847 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 13848 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 13849 * 13850 * @attr ref android.R.styleable#View_layoutDirection 13851 */ 13852 @ViewDebug.ExportedProperty(category = "layout", mapping = { 13853 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 13854 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 13855 }) 13856 @InspectableProperty(enumMapping = { 13857 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 13858 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 13859 }) 13860 @ResolvedLayoutDir 13861 public int getLayoutDirection() { 13862 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 13863 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 13864 } 13865 13866 /** 13867 * Indicates whether or not this view's layout is right-to-left. This is resolved from 13868 * layout attribute and/or the inherited value from the parent 13869 * 13870 * @return true if the layout is right-to-left. 13871 * 13872 * @hide 13873 */ 13874 @ViewDebug.ExportedProperty(category = "layout") 13875 @UnsupportedAppUsage 13876 public boolean isLayoutRtl() { 13877 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 13878 } 13879 13880 /** 13881 * Indicates whether the view is currently tracking transient state that the 13882 * app should not need to concern itself with saving and restoring, but that 13883 * the framework should take special note to preserve when possible. 13884 * 13885 * <p>A view with transient state cannot be trivially rebound from an external 13886 * data source, such as an adapter binding item views in a list. This may be 13887 * because the view is performing an animation, tracking user selection 13888 * of content, or similar.</p> 13889 * 13890 * @return true if the view has transient state 13891 */ 13892 @ViewDebug.ExportedProperty(category = "layout") 13893 public boolean hasTransientState() { 13894 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 13895 } 13896 13897 /** 13898 * Set whether this view is currently tracking transient state that the 13899 * framework should attempt to preserve when possible. This flag is reference counted, 13900 * so every call to setHasTransientState(true) should be paired with a later call 13901 * to setHasTransientState(false). 13902 * 13903 * <p>A view with transient state cannot be trivially rebound from an external 13904 * data source, such as an adapter binding item views in a list. This may be 13905 * because the view is performing an animation, tracking user selection 13906 * of content, or similar.</p> 13907 * 13908 * @param hasTransientState true if this view has transient state 13909 */ 13910 public void setHasTransientState(boolean hasTransientState) { 13911 final boolean oldHasTransientState = hasTransientState(); 13912 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 13913 mTransientStateCount - 1; 13914 if (mTransientStateCount < 0) { 13915 mTransientStateCount = 0; 13916 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 13917 "unmatched pair of setHasTransientState calls"); 13918 } else if ((hasTransientState && mTransientStateCount == 1) || 13919 (!hasTransientState && mTransientStateCount == 0)) { 13920 // update flag if we've just incremented up from 0 or decremented down to 0 13921 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 13922 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 13923 final boolean newHasTransientState = hasTransientState(); 13924 if (mParent != null && newHasTransientState != oldHasTransientState) { 13925 try { 13926 mParent.childHasTransientStateChanged(this, newHasTransientState); 13927 } catch (AbstractMethodError e) { 13928 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13929 " does not fully implement ViewParent", e); 13930 } 13931 } 13932 } 13933 } 13934 13935 /** 13936 * Set the view is tracking translation transient state. This flag is used to check if the view 13937 * need to call setHasTransientState(false) to reset transient state that set when starting 13938 * translation. 13939 * 13940 * @param hasTranslationTransientState true if this view has translation transient state 13941 * @hide 13942 */ 13943 public void setHasTranslationTransientState(boolean hasTranslationTransientState) { 13944 if (hasTranslationTransientState) { 13945 mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 13946 } else { 13947 mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 13948 } 13949 } 13950 13951 /** 13952 * @hide 13953 */ 13954 public boolean hasTranslationTransientState() { 13955 return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) 13956 == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 13957 } 13958 13959 /** 13960 * @hide 13961 */ 13962 public void clearTranslationState() { 13963 if (mViewTranslationCallback != null) { 13964 mViewTranslationCallback.onClearTranslation(this); 13965 } 13966 clearViewTranslationResponse(); 13967 if (hasTranslationTransientState()) { 13968 setHasTransientState(false); 13969 setHasTranslationTransientState(false); 13970 } 13971 } 13972 13973 /** 13974 * Returns true if this view is currently attached to a window. 13975 */ 13976 public boolean isAttachedToWindow() { 13977 return mAttachInfo != null; 13978 } 13979 13980 /** 13981 * Returns true if this view has been through at least one layout since it 13982 * was last attached to or detached from a window. 13983 */ 13984 public boolean isLaidOut() { 13985 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 13986 } 13987 13988 /** 13989 * @return {@code true} if laid-out and not about to do another layout. 13990 */ 13991 boolean isLayoutValid() { 13992 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 13993 } 13994 13995 /** 13996 * If this view doesn't do any drawing on its own, set this flag to 13997 * allow further optimizations. By default, this flag is not set on 13998 * View, but could be set on some View subclasses such as ViewGroup. 13999 * 14000 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 14001 * you should clear this flag. 14002 * 14003 * @param willNotDraw whether or not this View draw on its own 14004 */ 14005 public void setWillNotDraw(boolean willNotDraw) { 14006 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 14007 } 14008 14009 /** 14010 * Returns whether or not this View draws on its own. 14011 * 14012 * @return true if this view has nothing to draw, false otherwise 14013 */ 14014 @ViewDebug.ExportedProperty(category = "drawing") 14015 public boolean willNotDraw() { 14016 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 14017 } 14018 14019 /** 14020 * When a View's drawing cache is enabled, drawing is redirected to an 14021 * offscreen bitmap. Some views, like an ImageView, must be able to 14022 * bypass this mechanism if they already draw a single bitmap, to avoid 14023 * unnecessary usage of the memory. 14024 * 14025 * @param willNotCacheDrawing true if this view does not cache its 14026 * drawing, false otherwise 14027 * 14028 * @deprecated The view drawing cache was largely made obsolete with the introduction of 14029 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 14030 * layers are largely unnecessary and can easily result in a net loss in performance due to the 14031 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 14032 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 14033 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 14034 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 14035 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 14036 * software-rendered usages are discouraged and have compatibility issues with hardware-only 14037 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 14038 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 14039 * reports or unit testing the {@link PixelCopy} API is recommended. 14040 */ 14041 @Deprecated 14042 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 14043 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 14044 } 14045 14046 /** 14047 * Returns whether or not this View can cache its drawing or not. 14048 * 14049 * @return true if this view does not cache its drawing, false otherwise 14050 * 14051 * @deprecated The view drawing cache was largely made obsolete with the introduction of 14052 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 14053 * layers are largely unnecessary and can easily result in a net loss in performance due to the 14054 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 14055 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 14056 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 14057 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 14058 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 14059 * software-rendered usages are discouraged and have compatibility issues with hardware-only 14060 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 14061 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 14062 * reports or unit testing the {@link PixelCopy} API is recommended. 14063 */ 14064 @ViewDebug.ExportedProperty(category = "drawing") 14065 @Deprecated 14066 public boolean willNotCacheDrawing() { 14067 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 14068 } 14069 14070 /** 14071 * Indicates whether this view reacts to click events or not. 14072 * 14073 * @return true if the view is clickable, false otherwise 14074 * 14075 * @see #setClickable(boolean) 14076 * @attr ref android.R.styleable#View_clickable 14077 */ 14078 @ViewDebug.ExportedProperty 14079 @InspectableProperty 14080 public boolean isClickable() { 14081 return (mViewFlags & CLICKABLE) == CLICKABLE; 14082 } 14083 14084 /** 14085 * Enables or disables click events for this view. When a view 14086 * is clickable it will change its state to "pressed" on every click. 14087 * Subclasses should set the view clickable to visually react to 14088 * user's clicks. 14089 * 14090 * @param clickable true to make the view clickable, false otherwise 14091 * 14092 * @see #isClickable() 14093 * @attr ref android.R.styleable#View_clickable 14094 */ 14095 public void setClickable(boolean clickable) { 14096 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 14097 } 14098 14099 /** 14100 * Enables or disables click events for this view when disabled. 14101 * 14102 * @param clickableWhenDisabled true to make the view clickable, false otherwise 14103 * 14104 * @attr ref android.R.styleable#View_allowClickWhenDisabled 14105 */ 14106 public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { 14107 if (clickableWhenDisabled) { 14108 mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 14109 } else { 14110 mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 14111 } 14112 } 14113 14114 /** 14115 * Indicates whether this view reacts to long click events or not. 14116 * 14117 * @return true if the view is long clickable, false otherwise 14118 * 14119 * @see #setLongClickable(boolean) 14120 * @attr ref android.R.styleable#View_longClickable 14121 */ 14122 @InspectableProperty 14123 public boolean isLongClickable() { 14124 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 14125 } 14126 14127 /** 14128 * Enables or disables long click events for this view. When a view is long 14129 * clickable it reacts to the user holding down the button for a longer 14130 * duration than a tap. This event can either launch the listener or a 14131 * context menu. 14132 * 14133 * @param longClickable true to make the view long clickable, false otherwise 14134 * @see #isLongClickable() 14135 * @attr ref android.R.styleable#View_longClickable 14136 */ 14137 public void setLongClickable(boolean longClickable) { 14138 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 14139 } 14140 14141 /** 14142 * Indicates whether this view reacts to context clicks or not. 14143 * 14144 * @return true if the view is context clickable, false otherwise 14145 * @see #setContextClickable(boolean) 14146 * @attr ref android.R.styleable#View_contextClickable 14147 */ 14148 @InspectableProperty 14149 public boolean isContextClickable() { 14150 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 14151 } 14152 14153 /** 14154 * Enables or disables context clicking for this view. This event can launch the listener. 14155 * 14156 * @param contextClickable true to make the view react to a context click, false otherwise 14157 * @see #isContextClickable() 14158 * @attr ref android.R.styleable#View_contextClickable 14159 */ 14160 public void setContextClickable(boolean contextClickable) { 14161 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 14162 } 14163 14164 /** 14165 * Sets the pressed state for this view and provides a touch coordinate for 14166 * animation hinting. 14167 * 14168 * @param pressed Pass true to set the View's internal state to "pressed", 14169 * or false to reverts the View's internal state from a 14170 * previously set "pressed" state. 14171 * @param x The x coordinate of the touch that caused the press 14172 * @param y The y coordinate of the touch that caused the press 14173 */ 14174 private void setPressed(boolean pressed, float x, float y) { 14175 if (pressed) { 14176 drawableHotspotChanged(x, y); 14177 } 14178 14179 setPressed(pressed); 14180 } 14181 14182 /** 14183 * Sets the pressed state for this view. 14184 * 14185 * @see #isClickable() 14186 * @see #setClickable(boolean) 14187 * 14188 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 14189 * the View's internal state from a previously set "pressed" state. 14190 */ 14191 public void setPressed(boolean pressed) { 14192 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 14193 14194 if (pressed) { 14195 mPrivateFlags |= PFLAG_PRESSED; 14196 } else { 14197 mPrivateFlags &= ~PFLAG_PRESSED; 14198 } 14199 14200 if (needsRefresh) { 14201 refreshDrawableState(); 14202 } 14203 dispatchSetPressed(pressed); 14204 } 14205 14206 /** 14207 * Dispatch setPressed to all of this View's children. 14208 * 14209 * @see #setPressed(boolean) 14210 * 14211 * @param pressed The new pressed state 14212 */ 14213 protected void dispatchSetPressed(boolean pressed) { 14214 } 14215 14216 /** 14217 * Indicates whether the view is currently in pressed state. Unless 14218 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 14219 * the pressed state. 14220 * 14221 * @see #setPressed(boolean) 14222 * @see #isClickable() 14223 * @see #setClickable(boolean) 14224 * 14225 * @return true if the view is currently pressed, false otherwise 14226 */ 14227 @ViewDebug.ExportedProperty 14228 @InspectableProperty(hasAttributeId = false) 14229 public boolean isPressed() { 14230 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 14231 } 14232 14233 /** 14234 * @hide 14235 * Indicates whether this view will participate in data collection through 14236 * {@link ViewStructure}. If true, it will not provide any data 14237 * for itself or its children. If false, the normal data collection will be allowed. 14238 * 14239 * @return Returns false if assist data collection is not blocked, else true. 14240 * 14241 * @see #setAssistBlocked(boolean) 14242 * @attr ref android.R.styleable#View_assistBlocked 14243 */ 14244 public boolean isAssistBlocked() { 14245 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 14246 } 14247 14248 /** 14249 * @hide 14250 * Controls whether assist data collection from this view and its children is enabled 14251 * (that is, whether {@link #onProvideStructure} and 14252 * {@link #onProvideVirtualStructure} will be called). The default value is false, 14253 * allowing normal assist collection. Setting this to false will disable assist collection. 14254 * 14255 * @param enabled Set to true to <em>disable</em> assist data collection, or false 14256 * (the default) to allow it. 14257 * 14258 * @see #isAssistBlocked() 14259 * @see #onProvideStructure 14260 * @see #onProvideVirtualStructure 14261 * @attr ref android.R.styleable#View_assistBlocked 14262 */ 14263 @UnsupportedAppUsage 14264 public void setAssistBlocked(boolean enabled) { 14265 if (enabled) { 14266 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 14267 } else { 14268 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 14269 } 14270 } 14271 14272 /** 14273 * Indicates whether this view will save its state (that is, 14274 * whether its {@link #onSaveInstanceState} method will be called). 14275 * 14276 * @return Returns true if the view state saving is enabled, else false. 14277 * 14278 * @see #setSaveEnabled(boolean) 14279 * @attr ref android.R.styleable#View_saveEnabled 14280 */ 14281 @InspectableProperty 14282 public boolean isSaveEnabled() { 14283 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 14284 } 14285 14286 /** 14287 * Controls whether the saving of this view's state is 14288 * enabled (that is, whether its {@link #onSaveInstanceState} method 14289 * will be called). Note that even if freezing is enabled, the 14290 * view still must have an id assigned to it (via {@link #setId(int)}) 14291 * for its state to be saved. This flag can only disable the 14292 * saving of this view; any child views may still have their state saved. 14293 * 14294 * @param enabled Set to false to <em>disable</em> state saving, or true 14295 * (the default) to allow it. 14296 * 14297 * @see #isSaveEnabled() 14298 * @see #setId(int) 14299 * @see #onSaveInstanceState() 14300 * @attr ref android.R.styleable#View_saveEnabled 14301 */ 14302 public void setSaveEnabled(boolean enabled) { 14303 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 14304 } 14305 14306 /** 14307 * Gets whether the framework should discard touches when the view's 14308 * window is obscured by another visible window at the touched location. 14309 * Refer to the {@link View} security documentation for more details. 14310 * 14311 * @return True if touch filtering is enabled. 14312 * 14313 * @see #setFilterTouchesWhenObscured(boolean) 14314 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 14315 */ 14316 @ViewDebug.ExportedProperty 14317 @InspectableProperty 14318 public boolean getFilterTouchesWhenObscured() { 14319 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 14320 } 14321 14322 /** 14323 * Sets whether the framework should discard touches when the view's 14324 * window is obscured by another visible window at the touched location. 14325 * Refer to the {@link View} security documentation for more details. 14326 * 14327 * @param enabled True if touch filtering should be enabled. 14328 * 14329 * @see #getFilterTouchesWhenObscured 14330 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 14331 */ 14332 public void setFilterTouchesWhenObscured(boolean enabled) { 14333 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 14334 FILTER_TOUCHES_WHEN_OBSCURED); 14335 calculateAccessibilityDataSensitive(); 14336 } 14337 14338 /** 14339 * Indicates whether the entire hierarchy under this view will save its 14340 * state when a state saving traversal occurs from its parent. The default 14341 * is true; if false, these views will not be saved unless 14342 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 14343 * 14344 * @return Returns true if the view state saving from parent is enabled, else false. 14345 * 14346 * @see #setSaveFromParentEnabled(boolean) 14347 */ 14348 public boolean isSaveFromParentEnabled() { 14349 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 14350 } 14351 14352 /** 14353 * Controls whether the entire hierarchy under this view will save its 14354 * state when a state saving traversal occurs from its parent. The default 14355 * is true; if false, these views will not be saved unless 14356 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 14357 * 14358 * @param enabled Set to false to <em>disable</em> state saving, or true 14359 * (the default) to allow it. 14360 * 14361 * @see #isSaveFromParentEnabled() 14362 * @see #setId(int) 14363 * @see #onSaveInstanceState() 14364 */ 14365 public void setSaveFromParentEnabled(boolean enabled) { 14366 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 14367 } 14368 14369 14370 /** 14371 * Returns whether this View is currently able to take focus. 14372 * 14373 * @return True if this view can take focus, or false otherwise. 14374 */ 14375 @ViewDebug.ExportedProperty(category = "focus") 14376 public final boolean isFocusable() { 14377 return FOCUSABLE == (mViewFlags & FOCUSABLE); 14378 } 14379 14380 /** 14381 * Returns the focusable setting for this view. 14382 * 14383 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 14384 * @attr ref android.R.styleable#View_focusable 14385 */ 14386 @ViewDebug.ExportedProperty(mapping = { 14387 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 14388 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 14389 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 14390 }, category = "focus") 14391 @InspectableProperty(enumMapping = { 14392 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 14393 @EnumEntry(value = FOCUSABLE, name = "true"), 14394 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 14395 }) 14396 @Focusable 14397 public int getFocusable() { 14398 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 14399 } 14400 14401 /** 14402 * When a view is focusable, it may not want to take focus when in touch mode. 14403 * For example, a button would like focus when the user is navigating via a D-pad 14404 * so that the user can click on it, but once the user starts touching the screen, 14405 * the button shouldn't take focus 14406 * @return Whether the view is focusable in touch mode. 14407 * @attr ref android.R.styleable#View_focusableInTouchMode 14408 */ 14409 @ViewDebug.ExportedProperty(category = "focus") 14410 @InspectableProperty 14411 public final boolean isFocusableInTouchMode() { 14412 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 14413 } 14414 14415 /** 14416 * Returns whether the view should be treated as a focusable unit by screen reader 14417 * accessibility tools. 14418 * <p> 14419 * <b>Note:</b> Use 14420 * {@link androidx.core.view.ViewCompat#setScreenReaderFocusable(View, boolean)} 14421 * for backwards-compatibility. </aside> 14422 * @see #setScreenReaderFocusable(boolean) 14423 * 14424 * @return Whether the view should be treated as a focusable unit by screen reader. 14425 * 14426 * @attr ref android.R.styleable#View_screenReaderFocusable 14427 */ 14428 @InspectableProperty 14429 public boolean isScreenReaderFocusable() { 14430 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 14431 } 14432 14433 /** 14434 * Sets whether this View should be a focusable element for screen readers 14435 * and include non-focusable Views from its subtree when providing feedback. 14436 * <p> 14437 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 14438 * but does not impact input focus behavior. 14439 * 14440 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 14441 * accessibility tools. 14442 * 14443 * @attr ref android.R.styleable#View_screenReaderFocusable 14444 */ 14445 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 14446 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 14447 } 14448 14449 /** 14450 * Gets whether this view is a heading for accessibility purposes. 14451 * 14452 * @return {@code true} if the view is a heading, {@code false} otherwise. 14453 * 14454 * @attr ref android.R.styleable#View_accessibilityHeading 14455 */ 14456 @InspectableProperty 14457 public boolean isAccessibilityHeading() { 14458 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 14459 } 14460 14461 /** 14462 * Set if view is a heading for a section of content for accessibility purposes. 14463 * <p> 14464 * Users of some accessibility services can choose to navigate between headings 14465 * instead of between paragraphs, words, etc. Apps that provide headings on 14466 * sections of text can help the text navigation experience. 14467 * <p> 14468 * <b>Note:</b> Use {@link androidx.core.view.ViewCompat#setAccessibilityHeading(View, boolean)} 14469 * for backwards-compatibility. </aside> 14470 * 14471 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 14472 * 14473 * @attr ref android.R.styleable#View_accessibilityHeading 14474 */ 14475 public void setAccessibilityHeading(boolean isHeading) { 14476 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 14477 } 14478 14479 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 14480 int pflags3 = mPrivateFlags3; 14481 if (newValue) { 14482 pflags3 |= mask; 14483 } else { 14484 pflags3 &= ~mask; 14485 } 14486 14487 if (pflags3 != mPrivateFlags3) { 14488 mPrivateFlags3 = pflags3; 14489 notifyViewAccessibilityStateChangedIfNeeded( 14490 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14491 } 14492 } 14493 14494 /** 14495 * Find the nearest view in the specified direction that can take focus. 14496 * This does not actually give focus to that view. 14497 * 14498 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 14499 * 14500 * @return The nearest focusable in the specified direction, or null if none 14501 * can be found. 14502 */ 14503 public View focusSearch(@FocusRealDirection int direction) { 14504 if (mParent != null) { 14505 return mParent.focusSearch(this, direction); 14506 } else { 14507 return null; 14508 } 14509 } 14510 14511 /** 14512 * Returns whether this View is a root of a keyboard navigation cluster. 14513 * 14514 * @return True if this view is a root of a cluster, or false otherwise. 14515 * @attr ref android.R.styleable#View_keyboardNavigationCluster 14516 */ 14517 @ViewDebug.ExportedProperty(category = "focus") 14518 @InspectableProperty 14519 public final boolean isKeyboardNavigationCluster() { 14520 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 14521 } 14522 14523 /** 14524 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 14525 * will be ignored. 14526 * 14527 * @return the keyboard navigation cluster that this view is in (can be this view) 14528 * or {@code null} if not in one 14529 */ 14530 View findKeyboardNavigationCluster() { 14531 if (mParent instanceof View) { 14532 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 14533 if (cluster != null) { 14534 return cluster; 14535 } else if (isKeyboardNavigationCluster()) { 14536 return this; 14537 } 14538 } 14539 return null; 14540 } 14541 14542 /** 14543 * Set whether this view is a root of a keyboard navigation cluster. 14544 * 14545 * @param isCluster If true, this view is a root of a cluster. 14546 * 14547 * @attr ref android.R.styleable#View_keyboardNavigationCluster 14548 */ 14549 public void setKeyboardNavigationCluster(boolean isCluster) { 14550 if (isCluster) { 14551 mPrivateFlags3 |= PFLAG3_CLUSTER; 14552 } else { 14553 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 14554 } 14555 } 14556 14557 /** 14558 * Sets this View as the one which receives focus the next time cluster navigation jumps 14559 * to the cluster containing this View. This does NOT change focus even if the cluster 14560 * containing this view is current. 14561 * 14562 * @hide 14563 */ 14564 @TestApi 14565 public final void setFocusedInCluster() { 14566 setFocusedInCluster(findKeyboardNavigationCluster()); 14567 } 14568 14569 private void setFocusedInCluster(View cluster) { 14570 if (this instanceof ViewGroup) { 14571 ((ViewGroup) this).mFocusedInCluster = null; 14572 } 14573 if (cluster == this) { 14574 return; 14575 } 14576 ViewParent parent = mParent; 14577 View child = this; 14578 while (parent instanceof ViewGroup) { 14579 ((ViewGroup) parent).mFocusedInCluster = child; 14580 if (parent == cluster) { 14581 break; 14582 } 14583 child = (View) parent; 14584 parent = parent.getParent(); 14585 } 14586 } 14587 14588 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 14589 if (oldFocus != null) { 14590 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 14591 View cluster = findKeyboardNavigationCluster(); 14592 if (oldCluster != cluster) { 14593 // Going from one cluster to another, so save last-focused. 14594 // This covers cluster jumps because they are always FOCUS_DOWN 14595 oldFocus.setFocusedInCluster(oldCluster); 14596 if (!(oldFocus.mParent instanceof ViewGroup)) { 14597 return; 14598 } 14599 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 14600 // This is a result of ordered navigation so consider navigation through 14601 // the previous cluster "complete" and clear its last-focused memory. 14602 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 14603 } else if (oldFocus instanceof ViewGroup 14604 && ((ViewGroup) oldFocus).getDescendantFocusability() 14605 == ViewGroup.FOCUS_AFTER_DESCENDANTS 14606 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 14607 // This means oldFocus is not focusable since it obviously has a focusable 14608 // child (this). Don't restore focus to it in the future. 14609 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 14610 } 14611 } 14612 } 14613 } 14614 14615 /** 14616 * Returns whether this View should receive focus when the focus is restored for the view 14617 * hierarchy containing this view. 14618 * <p> 14619 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 14620 * window or serves as a target of cluster navigation. 14621 * 14622 * @see #restoreDefaultFocus() 14623 * 14624 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 14625 * @attr ref android.R.styleable#View_focusedByDefault 14626 */ 14627 @ViewDebug.ExportedProperty(category = "focus") 14628 @InspectableProperty 14629 public final boolean isFocusedByDefault() { 14630 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 14631 } 14632 14633 /** 14634 * Sets whether this View should receive focus when the focus is restored for the view 14635 * hierarchy containing this view. 14636 * <p> 14637 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 14638 * window or serves as a target of cluster navigation. 14639 * 14640 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 14641 * {@code false} otherwise. 14642 * 14643 * @see #restoreDefaultFocus() 14644 * 14645 * @attr ref android.R.styleable#View_focusedByDefault 14646 */ 14647 @RemotableViewMethod 14648 public void setFocusedByDefault(boolean isFocusedByDefault) { 14649 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 14650 return; 14651 } 14652 14653 if (isFocusedByDefault) { 14654 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 14655 } else { 14656 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 14657 } 14658 14659 if (mParent instanceof ViewGroup) { 14660 if (isFocusedByDefault) { 14661 ((ViewGroup) mParent).setDefaultFocus(this); 14662 } else { 14663 ((ViewGroup) mParent).clearDefaultFocus(this); 14664 } 14665 } 14666 } 14667 14668 /** 14669 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 14670 * 14671 * @return {@code true} if this view has default focus, {@code false} otherwise 14672 */ 14673 boolean hasDefaultFocus() { 14674 return isFocusedByDefault(); 14675 } 14676 14677 /** 14678 * Find the nearest keyboard navigation cluster in the specified direction. 14679 * This does not actually give focus to that cluster. 14680 * 14681 * @param currentCluster The starting point of the search. Null means the current cluster is not 14682 * found yet 14683 * @param direction Direction to look 14684 * 14685 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 14686 * can be found 14687 */ 14688 public View keyboardNavigationClusterSearch(View currentCluster, 14689 @FocusDirection int direction) { 14690 if (isKeyboardNavigationCluster()) { 14691 currentCluster = this; 14692 } 14693 if (isRootNamespace()) { 14694 // Root namespace means we should consider ourselves the top of the 14695 // tree for group searching; otherwise we could be group searching 14696 // into other tabs. see LocalActivityManager and TabHost for more info. 14697 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 14698 this, currentCluster, direction); 14699 } else if (mParent != null) { 14700 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 14701 } 14702 return null; 14703 } 14704 14705 /** 14706 * This method is the last chance for the focused view and its ancestors to 14707 * respond to an arrow key. This is called when the focused view did not 14708 * consume the key internally, nor could the view system find a new view in 14709 * the requested direction to give focus to. 14710 * 14711 * @param focused The currently focused view. 14712 * @param direction The direction focus wants to move. One of FOCUS_UP, 14713 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 14714 * @return True if the this view consumed this unhandled move. 14715 */ 14716 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 14717 return false; 14718 } 14719 14720 /** 14721 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 14722 * have {@link android.R.attr#state_focused} defined in its background. 14723 * 14724 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 14725 * highlight, {@code false} otherwise. 14726 * 14727 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 14728 */ 14729 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 14730 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 14731 } 14732 14733 /** 14734 * Returns whether this View should use a default focus highlight when it gets focused but 14735 * doesn't have {@link android.R.attr#state_focused} defined in its background. 14736 * 14737 * @return True if this View should use a default focus highlight. 14738 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 14739 */ 14740 @ViewDebug.ExportedProperty(category = "focus") 14741 @InspectableProperty 14742 public final boolean getDefaultFocusHighlightEnabled() { 14743 return mDefaultFocusHighlightEnabled; 14744 } 14745 14746 /** 14747 * If a user manually specified the next view id for a particular direction, 14748 * use the root to look up the view. 14749 * @param root The root view of the hierarchy containing this view. 14750 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 14751 * or FOCUS_BACKWARD. 14752 * @return The user specified next view, or null if there is none. 14753 */ 14754 View findUserSetNextFocus(View root, @FocusDirection int direction) { 14755 switch (direction) { 14756 case FOCUS_LEFT: 14757 if (mNextFocusLeftId == View.NO_ID) return null; 14758 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 14759 case FOCUS_RIGHT: 14760 if (mNextFocusRightId == View.NO_ID) return null; 14761 return findViewInsideOutShouldExist(root, mNextFocusRightId); 14762 case FOCUS_UP: 14763 if (mNextFocusUpId == View.NO_ID) return null; 14764 return findViewInsideOutShouldExist(root, mNextFocusUpId); 14765 case FOCUS_DOWN: 14766 if (mNextFocusDownId == View.NO_ID) return null; 14767 return findViewInsideOutShouldExist(root, mNextFocusDownId); 14768 case FOCUS_FORWARD: 14769 if (mNextFocusForwardId == View.NO_ID) return null; 14770 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 14771 case FOCUS_BACKWARD: { 14772 if (mID == View.NO_ID) return null; 14773 final View rootView = root; 14774 final View startView = this; 14775 // Since we have forward links but no backward links, we need to find the view that 14776 // forward links to this view. We can't just find the view with the specified ID 14777 // because view IDs need not be unique throughout the tree. 14778 return root.findViewByPredicateInsideOut(startView, 14779 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 14780 == startView); 14781 } 14782 } 14783 return null; 14784 } 14785 14786 /** 14787 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 14788 * use the root to look up the view. 14789 * 14790 * @param root the root view of the hierarchy containing this view 14791 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 14792 * @return the user-specified next cluster, or {@code null} if there is none 14793 */ 14794 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 14795 switch (direction) { 14796 case FOCUS_FORWARD: 14797 if (mNextClusterForwardId == View.NO_ID) return null; 14798 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 14799 case FOCUS_BACKWARD: { 14800 if (mID == View.NO_ID) return null; 14801 final int id = mID; 14802 return root.findViewByPredicateInsideOut(this, 14803 (Predicate<View>) t -> t.mNextClusterForwardId == id); 14804 } 14805 } 14806 return null; 14807 } 14808 14809 private View findViewInsideOutShouldExist(View root, int id) { 14810 return findViewInsideOutShouldExist(root, this, id); 14811 } 14812 14813 private View findViewInsideOutShouldExist(View root, View start, int id) { 14814 if (mMatchIdPredicate == null) { 14815 mMatchIdPredicate = new MatchIdPredicate(); 14816 } 14817 mMatchIdPredicate.mId = id; 14818 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 14819 if (result == null) { 14820 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 14821 } 14822 return result; 14823 } 14824 14825 /** 14826 * Find and return all focusable views that are descendants of this view, 14827 * possibly including this view if it is focusable itself. 14828 * 14829 * @param direction The direction of the focus 14830 * @return A list of focusable views 14831 */ 14832 public ArrayList<View> getFocusables(@FocusDirection int direction) { 14833 ArrayList<View> result = new ArrayList<View>(24); 14834 addFocusables(result, direction); 14835 return result; 14836 } 14837 14838 /** 14839 * Add any focusable views that are descendants of this view (possibly 14840 * including this view if it is focusable itself) to views. If we are in touch mode, 14841 * only add views that are also focusable in touch mode. 14842 * 14843 * @param views Focusable views found so far 14844 * @param direction The direction of the focus 14845 */ 14846 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 14847 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 14848 } 14849 14850 /** 14851 * Adds any focusable views that are descendants of this view (possibly 14852 * including this view if it is focusable itself) to views. This method 14853 * adds all focusable views regardless if we are in touch mode or 14854 * only views focusable in touch mode if we are in touch mode or 14855 * only views that can take accessibility focus if accessibility is enabled 14856 * depending on the focusable mode parameter. 14857 * 14858 * @param views Focusable views found so far or null if all we are interested is 14859 * the number of focusables. 14860 * @param direction The direction of the focus. 14861 * @param focusableMode The type of focusables to be added. 14862 * 14863 * @see #FOCUSABLES_ALL 14864 * @see #FOCUSABLES_TOUCH_MODE 14865 */ 14866 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 14867 @FocusableMode int focusableMode) { 14868 if (views == null) { 14869 return; 14870 } 14871 if (!canTakeFocus()) { 14872 return; 14873 } 14874 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 14875 && !isFocusableInTouchMode()) { 14876 return; 14877 } 14878 views.add(this); 14879 } 14880 14881 /** 14882 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 14883 * including this view if it is a cluster root itself) to views. 14884 * 14885 * @param views Keyboard navigation cluster roots found so far 14886 * @param direction Direction to look 14887 */ 14888 public void addKeyboardNavigationClusters( 14889 @NonNull Collection<View> views, 14890 int direction) { 14891 if (!isKeyboardNavigationCluster()) { 14892 return; 14893 } 14894 if (!hasFocusable()) { 14895 return; 14896 } 14897 views.add(this); 14898 } 14899 14900 /** 14901 * Finds the Views that contain given text. The containment is case insensitive. 14902 * The search is performed by either the text that the View renders or the content 14903 * description that describes the view for accessibility purposes and the view does 14904 * not render or both. Clients can specify how the search is to be performed via 14905 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 14906 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 14907 * 14908 * @param outViews The output list of matching Views. 14909 * @param searched The text to match against. 14910 * 14911 * @see #FIND_VIEWS_WITH_TEXT 14912 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 14913 * @see #setContentDescription(CharSequence) 14914 */ 14915 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 14916 @FindViewFlags int flags) { 14917 if (getAccessibilityNodeProvider() != null) { 14918 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 14919 outViews.add(this); 14920 } 14921 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 14922 && (searched != null && searched.length() > 0) 14923 && (mContentDescription != null && mContentDescription.length() > 0)) { 14924 String searchedLowerCase = searched.toString().toLowerCase(); 14925 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 14926 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 14927 outViews.add(this); 14928 } 14929 } 14930 } 14931 14932 /** 14933 * Find and return all touchable views that are descendants of this view, 14934 * possibly including this view if it is touchable itself. 14935 * 14936 * @return A list of touchable views 14937 */ 14938 public ArrayList<View> getTouchables() { 14939 ArrayList<View> result = new ArrayList<View>(); 14940 addTouchables(result); 14941 return result; 14942 } 14943 14944 /** 14945 * Add any touchable views that are descendants of this view (possibly 14946 * including this view if it is touchable itself) to views. 14947 * 14948 * @param views Touchable views found so far 14949 */ 14950 public void addTouchables(ArrayList<View> views) { 14951 final int viewFlags = mViewFlags; 14952 14953 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 14954 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 14955 && (viewFlags & ENABLED_MASK) == ENABLED) { 14956 views.add(this); 14957 } 14958 } 14959 14960 /** 14961 * Returns whether this View is accessibility focused. 14962 * 14963 * @return True if this View is accessibility focused. 14964 */ 14965 @InspectableProperty(hasAttributeId = false) 14966 public boolean isAccessibilityFocused() { 14967 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 14968 } 14969 14970 /** 14971 * Call this to try to give accessibility focus to this view. 14972 * 14973 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 14974 * returns false or the view is no visible or the view already has accessibility 14975 * focus. 14976 * 14977 * See also {@link #focusSearch(int)}, which is what you call to say that you 14978 * have focus, and you want your parent to look for the next one. 14979 * 14980 * <p> 14981 * <b>Note:</b> Avoid setting accessibility focus. This is intended to be controlled by screen 14982 * readers. Apps changing focus can confuse screen readers, so the resulting behavior can vary 14983 * by device and screen reader version. 14984 * 14985 * @return Whether this view actually took accessibility focus. 14986 * 14987 * @hide 14988 */ 14989 @UnsupportedAppUsage 14990 public boolean requestAccessibilityFocus() { 14991 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 14992 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 14993 return false; 14994 } 14995 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 14996 return false; 14997 } 14998 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 14999 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 15000 ViewRootImpl viewRootImpl = getViewRootImpl(); 15001 if (viewRootImpl != null) { 15002 viewRootImpl.setAccessibilityFocus(this, null); 15003 } 15004 invalidate(); 15005 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 15006 return true; 15007 } 15008 return false; 15009 } 15010 15011 /** 15012 * Call this to try to clear accessibility focus of this view. 15013 * 15014 * See also {@link #focusSearch(int)}, which is what you call to say that you 15015 * have focus, and you want your parent to look for the next one. 15016 * 15017 * @hide 15018 */ 15019 @UnsupportedAppUsage 15020 public void clearAccessibilityFocus() { 15021 clearAccessibilityFocusNoCallbacks(0); 15022 15023 // Clear the global reference of accessibility focus if this view or 15024 // any of its descendants had accessibility focus. This will NOT send 15025 // an event or update internal state if focus is cleared from a 15026 // descendant view, which may leave views in inconsistent states. 15027 final ViewRootImpl viewRootImpl = getViewRootImpl(); 15028 if (viewRootImpl != null) { 15029 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 15030 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 15031 viewRootImpl.setAccessibilityFocus(null, null); 15032 } 15033 } 15034 } 15035 15036 private void sendAccessibilityHoverEvent(int eventType) { 15037 // Since we are not delivering to a client accessibility events from not 15038 // important views (unless the clinet request that) we need to fire the 15039 // event from the deepest view exposed to the client. As a consequence if 15040 // the user crosses a not exposed view the client will see enter and exit 15041 // of the exposed predecessor followed by and enter and exit of that same 15042 // predecessor when entering and exiting the not exposed descendant. This 15043 // is fine since the client has a clear idea which view is hovered at the 15044 // price of a couple more events being sent. This is a simple and 15045 // working solution. 15046 View source = this; 15047 while (true) { 15048 if (source.includeForAccessibility(false)) { 15049 source.sendAccessibilityEvent(eventType); 15050 return; 15051 } 15052 ViewParent parent = source.getParent(); 15053 if (parent instanceof View) { 15054 source = (View) parent; 15055 } else { 15056 return; 15057 } 15058 } 15059 } 15060 15061 /** 15062 * Clears accessibility focus without calling any callback methods 15063 * normally invoked in {@link #clearAccessibilityFocus()}. This method 15064 * is used separately from that one for clearing accessibility focus when 15065 * giving this focus to another view. 15066 * 15067 * @param action The action, if any, that led to focus being cleared. Set to 15068 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 15069 * the window. 15070 */ 15071 void clearAccessibilityFocusNoCallbacks(int action) { 15072 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 15073 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 15074 invalidate(); 15075 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 15076 AccessibilityEvent event = AccessibilityEvent.obtain( 15077 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 15078 event.setAction(action); 15079 if (mAccessibilityDelegate != null) { 15080 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 15081 } else { 15082 sendAccessibilityEventUnchecked(event); 15083 } 15084 } 15085 15086 updatePreferKeepClearForFocus(); 15087 } 15088 } 15089 15090 /** 15091 * Call this to try to give focus to a specific view or to one of its 15092 * descendants. 15093 * 15094 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 15095 * false), or if it can't be focused due to other conditions (not focusable in touch mode 15096 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 15097 * enabled, or has no size). 15098 * 15099 * See also {@link #focusSearch(int)}, which is what you call to say that you 15100 * have focus, and you want your parent to look for the next one. 15101 * 15102 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 15103 * {@link #FOCUS_DOWN} and <code>null</code>. 15104 * 15105 * @return Whether this view or one of its descendants actually took focus. 15106 */ 15107 public final boolean requestFocus() { 15108 return requestFocus(View.FOCUS_DOWN); 15109 } 15110 15111 /** 15112 * This will request focus for whichever View was last focused within this 15113 * cluster before a focus-jump out of it. 15114 * 15115 * @hide 15116 */ 15117 @TestApi 15118 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 15119 // Prioritize focusableByDefault over algorithmic focus selection. 15120 if (restoreDefaultFocus()) { 15121 return true; 15122 } 15123 return requestFocus(direction); 15124 } 15125 15126 /** 15127 * This will request focus for whichever View not in a cluster was last focused before a 15128 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 15129 * the "first" focusable view it finds. 15130 * 15131 * @hide 15132 */ 15133 @TestApi 15134 public boolean restoreFocusNotInCluster() { 15135 return requestFocus(View.FOCUS_DOWN); 15136 } 15137 15138 /** 15139 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 15140 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 15141 * 15142 * @return Whether this view or one of its descendants actually took focus 15143 */ 15144 public boolean restoreDefaultFocus() { 15145 return requestFocus(View.FOCUS_DOWN); 15146 } 15147 15148 /** 15149 * Call this to try to give focus to a specific view or to one of its 15150 * descendants and give it a hint about what direction focus is heading. 15151 * 15152 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 15153 * false), or if it is focusable and it is not focusable in touch mode 15154 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 15155 * 15156 * See also {@link #focusSearch(int)}, which is what you call to say that you 15157 * have focus, and you want your parent to look for the next one. 15158 * 15159 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 15160 * <code>null</code> set for the previously focused rectangle. 15161 * 15162 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 15163 * @return Whether this view or one of its descendants actually took focus. 15164 */ 15165 public final boolean requestFocus(int direction) { 15166 return requestFocus(direction, null); 15167 } 15168 15169 /** 15170 * Call this to try to give focus to a specific view or to one of its descendants 15171 * and give it hints about the direction and a specific rectangle that the focus 15172 * is coming from. The rectangle can help give larger views a finer grained hint 15173 * about where focus is coming from, and therefore, where to show selection, or 15174 * forward focus change internally. 15175 * 15176 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 15177 * false), or if it is focusable and it is not focusable in touch mode 15178 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 15179 * 15180 * A View will not take focus if it is not visible. 15181 * 15182 * A View will not take focus if one of its parents has 15183 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 15184 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 15185 * 15186 * See also {@link #focusSearch(int)}, which is what you call to say that you 15187 * have focus, and you want your parent to look for the next one. 15188 * 15189 * You may wish to override this method if your custom {@link View} has an internal 15190 * {@link View} that it wishes to forward the request to. 15191 * 15192 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 15193 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 15194 * to give a finer grained hint about where focus is coming from. May be null 15195 * if there is no hint. 15196 * @return Whether this view or one of its descendants actually took focus. 15197 */ 15198 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 15199 return requestFocusNoSearch(direction, previouslyFocusedRect); 15200 } 15201 15202 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 15203 // need to be focusable 15204 if (!canTakeFocus()) { 15205 return false; 15206 } 15207 15208 // need to be focusable in touch mode if in touch mode 15209 if (isInTouchMode() && 15210 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 15211 return false; 15212 } 15213 15214 // need to not have any parents blocking us 15215 if (hasAncestorThatBlocksDescendantFocus()) { 15216 return false; 15217 } 15218 15219 if (!isLayoutValid()) { 15220 mPrivateFlags |= PFLAG_WANTS_FOCUS; 15221 } else { 15222 clearParentsWantFocus(); 15223 } 15224 15225 handleFocusGainInternal(direction, previouslyFocusedRect); 15226 return true; 15227 } 15228 15229 void clearParentsWantFocus() { 15230 if (mParent instanceof View) { 15231 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 15232 ((View) mParent).clearParentsWantFocus(); 15233 } 15234 } 15235 15236 /** 15237 * Call this to try to give focus to a specific view or to one of its descendants. This is a 15238 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 15239 * touch mode to request focus when they are touched. 15240 * 15241 * @return Whether this view or one of its descendants actually took focus. 15242 * 15243 * @see #isInTouchMode() 15244 * 15245 */ 15246 public final boolean requestFocusFromTouch() { 15247 // Leave touch mode if we need to 15248 if (isInTouchMode()) { 15249 ViewRootImpl viewRoot = getViewRootImpl(); 15250 if (viewRoot != null) { 15251 viewRoot.ensureTouchMode(false); 15252 } 15253 } 15254 return requestFocus(View.FOCUS_DOWN); 15255 } 15256 15257 /** 15258 * @return Whether any ancestor of this view blocks descendant focus. 15259 */ 15260 private boolean hasAncestorThatBlocksDescendantFocus() { 15261 final boolean focusableInTouchMode = isFocusableInTouchMode(); 15262 ViewParent ancestor = mParent; 15263 while (ancestor instanceof ViewGroup) { 15264 final ViewGroup vgAncestor = (ViewGroup) ancestor; 15265 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 15266 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 15267 return true; 15268 } else { 15269 ancestor = vgAncestor.getParent(); 15270 } 15271 } 15272 return false; 15273 } 15274 15275 /** 15276 * Gets the mode for determining whether this View is important for accessibility. 15277 * A view is important for accessibility if it fires accessibility events and if it 15278 * is reported to accessibility services that query the screen. 15279 * 15280 * @return The mode for determining whether a view is important for accessibility, one 15281 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 15282 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 15283 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 15284 * 15285 * @attr ref android.R.styleable#View_importantForAccessibility 15286 * 15287 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 15288 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 15289 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 15290 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 15291 */ 15292 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 15293 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 15294 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 15295 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 15296 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 15297 to = "noHideDescendants") 15298 }) 15299 @InspectableProperty(enumMapping = { 15300 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 15301 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 15302 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 15303 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 15304 name = "noHideDescendants"), 15305 }) 15306 public int getImportantForAccessibility() { 15307 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 15308 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 15309 } 15310 15311 /** 15312 * Sets the live region mode for this view. This indicates to accessibility 15313 * services whether they should automatically notify the user about changes 15314 * to the view's content description or text, or to the content descriptions 15315 * or text of the view's children (where applicable). 15316 * <p> 15317 * Different priority levels are available: 15318 * <ul> 15319 * <li> 15320 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}: 15321 * Indicates that updates to the region should be presented to the user. Suitable in most 15322 * cases for prominent updates within app content that don't require the user's immediate 15323 * attention. 15324 * </li> 15325 * <li> 15326 * {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}: Indicates that updates to the region have 15327 * the highest priority and should be presented to the user immediately. This may result 15328 * in disruptive notifications from an accessibility service, which may potentially 15329 * interrupt other feedback or user actions, so it should generally be used only for 15330 * critical, time-sensitive information. 15331 * </li> 15332 * <li> 15333 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}: Disables change announcements (the default for 15334 * most views). 15335 * </li> 15336 * </ul> 15337 * <p> 15338 * Examples: 15339 * <ul> 15340 * <li> 15341 * Selecting an option in a dropdown menu updates a panel below with the updated 15342 * content. This panel may be marked as a live region with 15343 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE} to notify users of the change. A screen 15344 * reader may queue changes as announcements that don't disrupt ongoing speech. 15345 * </li> 15346 * <li> 15347 * An emergency alert may be marked with {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 15348 * to immediately inform users of the emergency. 15349 * </li> 15350 * </ul> 15351 * <p> 15352 * For error notifications, like an "incorrect password" warning in a login screen, views 15353 * should send a {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} 15354 * {@code AccessibilityEvent} with a content change type 15355 * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set 15356 * {@link AccessibilityNodeInfo#setError(CharSequence)}. Custom widgets should provide 15357 * error-setting methods that support accessibility. For example, use 15358 * {@link android.widget.TextView#setError(CharSequence)} instead of explicitly sending events. 15359 * <p> 15360 * Don't use live regions for frequently-updating UI elements (e.g., progress bars), as this can 15361 * overwhelm the user with feedback from accessibility services. If necessary, use 15362 * {@link AccessibilityNodeInfo#setMinDurationBetweenContentChanges(Duration)} to throttle 15363 * feedback and reduce disruptions. 15364 * <p> 15365 * <aside><b>Note:</b> Use 15366 * {@link androidx.core.view.ViewCompat#setAccessibilityLiveRegion(View, int)} 15367 * for backwards-compatibility. </aside> 15368 * 15369 * @param mode The live region mode for this view, one of: 15370 * <ul> 15371 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 15372 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 15373 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 15374 * </ul> 15375 * @attr ref android.R.styleable#View_accessibilityLiveRegion 15376 */ setAccessibilityLiveRegion(int mode)15377 public void setAccessibilityLiveRegion(int mode) { 15378 if (mode != getAccessibilityLiveRegion()) { 15379 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 15380 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 15381 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 15382 notifyViewAccessibilityStateChangedIfNeeded( 15383 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15384 } 15385 } 15386 15387 /** 15388 * Gets the live region mode for this View. 15389 * 15390 * @return The live region mode for the view. 15391 * 15392 * @attr ref android.R.styleable#View_accessibilityLiveRegion 15393 * 15394 * @see #setAccessibilityLiveRegion(int) 15395 */ 15396 @InspectableProperty(enumMapping = { 15397 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 15398 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 15399 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 15400 }) getAccessibilityLiveRegion()15401 public int getAccessibilityLiveRegion() { 15402 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 15403 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 15404 } 15405 15406 /** 15407 * Sets how to determine whether this view is important for accessibility 15408 * which is if it fires accessibility events and if it is reported to 15409 * accessibility services that query the screen. 15410 * 15411 * @param mode How to determine whether this view is important for accessibility. 15412 * 15413 * @attr ref android.R.styleable#View_importantForAccessibility 15414 * 15415 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 15416 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 15417 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 15418 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 15419 */ setImportantForAccessibility(int mode)15420 public void setImportantForAccessibility(int mode) { 15421 final int oldMode = getImportantForAccessibility(); 15422 if (mode != oldMode) { 15423 final boolean hideDescendants = 15424 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 15425 15426 // If this node or its descendants are no longer important, try to 15427 // clear accessibility focus. 15428 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 15429 final View focusHost = findAccessibilityFocusHost(hideDescendants); 15430 if (focusHost != null) { 15431 focusHost.clearAccessibilityFocus(); 15432 } 15433 } 15434 15435 // If we're moving between AUTO and another state, we might not need 15436 // to send a subtree changed notification. We'll store the computed 15437 // importance, since we'll need to check it later to make sure. 15438 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 15439 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 15440 final boolean oldIncludeForAccessibility = 15441 maySkipNotify && includeForAccessibility(false); 15442 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 15443 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 15444 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 15445 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility(false)) { 15446 notifySubtreeAccessibilityStateChangedIfNeeded(); 15447 } else { 15448 notifyViewAccessibilityStateChangedIfNeeded( 15449 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15450 } 15451 } 15452 } 15453 15454 /** 15455 * Returns the view within this view's hierarchy that is hosting 15456 * accessibility focus. 15457 * 15458 * @param searchDescendants whether to search for focus in descendant views 15459 * @return the view hosting accessibility focus, or {@code null} 15460 */ findAccessibilityFocusHost(boolean searchDescendants)15461 private View findAccessibilityFocusHost(boolean searchDescendants) { 15462 if (isAccessibilityFocusedViewOrHost()) { 15463 return this; 15464 } 15465 15466 if (searchDescendants) { 15467 final ViewRootImpl viewRoot = getViewRootImpl(); 15468 if (viewRoot != null) { 15469 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 15470 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 15471 return focusHost; 15472 } 15473 } 15474 } 15475 15476 return null; 15477 } 15478 15479 /** 15480 * Computes whether this view should be exposed for accessibility. In 15481 * general, views that are interactive or provide information are exposed 15482 * while views that serve only as containers are hidden. 15483 * <p> 15484 * If an ancestor of this view has importance 15485 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 15486 * returns <code>false</code>. 15487 * <p> 15488 * Otherwise, the value is computed according to the view's 15489 * {@link #getImportantForAccessibility()} value: 15490 * <ol> 15491 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 15492 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 15493 * </code> 15494 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 15495 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 15496 * view satisfies any of the following: 15497 * <ul> 15498 * <li>Is actionable, e.g. {@link #isClickable()}, 15499 * {@link #isLongClickable()}, {@link #isContextClickable()}, 15500 * {@link #isScreenReaderFocusable()}, or {@link #isFocusable()} 15501 * <li>Has an {@link AccessibilityDelegate} 15502 * <li>Has an {@link AccessibilityNodeProvider} 15503 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 15504 * {@link OnKeyListener}, etc. 15505 * <li>Is an accessibility live region, e.g. 15506 * {@link #getAccessibilityLiveRegion()} is not 15507 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 15508 * </ul> 15509 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 15510 * <li>Is an accessibility heading, see {@link #setAccessibilityHeading(boolean)}.</li> 15511 * </ol> 15512 * 15513 * @return Whether the view is exposed for accessibility. 15514 * @see #setImportantForAccessibility(int) 15515 * @see #getImportantForAccessibility() 15516 */ isImportantForAccessibility()15517 public boolean isImportantForAccessibility() { 15518 final int mode = getImportantForAccessibility(); 15519 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 15520 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 15521 return false; 15522 } 15523 15524 // Check parent mode to ensure we're not hidden. 15525 ViewParent parent = mParent; 15526 while (parent instanceof View) { 15527 if (((View) parent).getImportantForAccessibility() 15528 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 15529 return false; 15530 } 15531 parent = parent.getParent(); 15532 } 15533 15534 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 15535 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 15536 || getAccessibilityDelegate() != null 15537 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 15538 || isAccessibilityPane() || isAccessibilityHeading(); 15539 } 15540 15541 /** 15542 * Gets the parent for accessibility purposes. Note that the parent for 15543 * accessibility is not necessary the immediate parent. It is the first 15544 * predecessor that is important for accessibility. 15545 * 15546 * @return The parent for accessibility purposes. 15547 */ getParentForAccessibility()15548 public ViewParent getParentForAccessibility() { 15549 if (mParent instanceof View) { 15550 View parentView = (View) mParent; 15551 if (parentView.includeForAccessibility()) { 15552 return mParent; 15553 } else { 15554 return mParent.getParentForAccessibility(); 15555 } 15556 } 15557 return null; 15558 } 15559 15560 /** @hide */ 15561 @Nullable getSelfOrParentImportantForA11y()15562 View getSelfOrParentImportantForA11y() { 15563 if (isImportantForAccessibility()) return this; 15564 ViewParent parent = getParentForAccessibility(); 15565 if (parent instanceof View) return (View) parent; 15566 return null; 15567 } 15568 15569 /** 15570 * Adds the children of this View relevant for accessibility to the given list 15571 * as output. Since some Views are not important for accessibility the added 15572 * child views are not necessarily direct children of this view, rather they are 15573 * the first level of descendants important for accessibility. 15574 * 15575 * @param outChildren The output list that will receive children for accessibility. 15576 */ addChildrenForAccessibility(ArrayList<View> outChildren)15577 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 15578 15579 } 15580 15581 /** 15582 * @see #includeForAccessibility(boolean) 15583 * @hide 15584 */ 15585 @UnsupportedAppUsage includeForAccessibility()15586 public boolean includeForAccessibility() { 15587 return includeForAccessibility(true); 15588 } 15589 15590 /** 15591 * Whether to regard this view for accessibility. 15592 * 15593 * <p> 15594 * If this decision is used for generating the accessibility node tree then this returns false 15595 * for {@link #isAccessibilityDataPrivate()} views queried by non-accessibility tools. 15596 * </p> 15597 * <p> 15598 * Otherwise, a view is regarded for accessibility if: 15599 * <li>the view returns true for {@link #isImportantForAccessibility()}, or</li> 15600 * <li>the querying accessibility service has explicitly requested that views not important for 15601 * accessibility are regarded by setting 15602 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}</li> 15603 * </p> 15604 * 15605 * @param forNodeTree True if the result of this function will be used for generating a node 15606 * tree, otherwise false (like when sending {@link AccessibilityEvent}s). 15607 * @return Whether to regard the view for accessibility. 15608 * @hide 15609 */ includeForAccessibility(boolean forNodeTree)15610 public boolean includeForAccessibility(boolean forNodeTree) { 15611 if (mAttachInfo == null) { 15612 return false; 15613 } 15614 15615 if (forNodeTree) { 15616 // The AccessibilityDataPrivate property should not effect whether this View is 15617 // included for consideration when sending AccessibilityEvents. Events copy their 15618 // source View's AccessibilityDataPrivate value, and then filtering is done when 15619 // AccessibilityManagerService propagates events to each recipient AccessibilityService. 15620 if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool() 15621 && isAccessibilityDataSensitive()) { 15622 return false; 15623 } 15624 } 15625 15626 return (mAttachInfo.mAccessibilityFetchFlags 15627 & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 15628 || isImportantForAccessibility(); 15629 } 15630 15631 /** 15632 * Whether this view should restrict accessibility service access only to services that have the 15633 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 15634 * set to true. 15635 * 15636 * <p> 15637 * See default behavior provided by {@link #ACCESSIBILITY_DATA_SENSITIVE_AUTO}. Otherwise, 15638 * returns true for {@link #ACCESSIBILITY_DATA_SENSITIVE_YES} or false for {@link 15639 * #ACCESSIBILITY_DATA_SENSITIVE_NO}. 15640 * </p> 15641 * 15642 * @return True if this view should restrict accessibility service access to services that have 15643 * the isAccessibilityTool property. 15644 */ 15645 @ViewDebug.ExportedProperty(category = "accessibility") isAccessibilityDataSensitive()15646 public boolean isAccessibilityDataSensitive() { 15647 if (mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_AUTO) { 15648 calculateAccessibilityDataSensitive(); 15649 } 15650 return mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_YES; 15651 } 15652 15653 /** 15654 * Calculate and cache the inferred value for {@link #isAccessibilityDataSensitive()}. 15655 * 15656 * <p> 15657 * <strong>Note:</strong> This method needs to be called any time one of the below conditions 15658 * changes, to recalculate the new value. 15659 * </p> 15660 */ calculateAccessibilityDataSensitive()15661 void calculateAccessibilityDataSensitive() { 15662 // Use the explicit value if set. 15663 if (mExplicitAccessibilityDataSensitive != ACCESSIBILITY_DATA_SENSITIVE_AUTO) { 15664 mInferredAccessibilityDataSensitive = mExplicitAccessibilityDataSensitive; 15665 } else if (getFilterTouchesWhenObscured()) { 15666 // Views that set filterTouchesWhenObscured default to accessibilityDataSensitive. 15667 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; 15668 } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataSensitive()) { 15669 // Descendants of accessibilityDataSensitive Views are also accessibilityDataSensitive. 15670 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; 15671 } else { 15672 // Otherwise, default to not accessibilityDataSensitive. 15673 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_NO; 15674 } 15675 } 15676 15677 /** 15678 * Specifies whether this view should only allow interactions from 15679 * {@link android.accessibilityservice.AccessibilityService}s with the 15680 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 15681 * set to true. 15682 */ setAccessibilityDataSensitive( @ccessibilityDataSensitive int accessibilityDataSensitive)15683 public void setAccessibilityDataSensitive( 15684 @AccessibilityDataSensitive int accessibilityDataSensitive) { 15685 mExplicitAccessibilityDataSensitive = accessibilityDataSensitive; 15686 calculateAccessibilityDataSensitive(); 15687 } 15688 15689 /** 15690 * Returns whether the View is considered actionable from 15691 * accessibility perspective. Such view are important for 15692 * accessibility. 15693 * 15694 * @return True if the view is actionable for accessibility. 15695 * 15696 * @hide 15697 */ isActionableForAccessibility()15698 public boolean isActionableForAccessibility() { 15699 return (isClickable() || isLongClickable() || isFocusable() || isContextClickable() 15700 || isScreenReaderFocusable()); 15701 } 15702 15703 /** 15704 * Returns whether the View has registered callbacks which makes it 15705 * important for accessibility. 15706 * 15707 * @return True if the view is actionable for accessibility. 15708 */ hasListenersForAccessibility()15709 private boolean hasListenersForAccessibility() { 15710 ListenerInfo info = getListenerInfo(); 15711 return mTouchDelegate != null || info.mOnKeyListener != null 15712 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 15713 || info.mOnHoverListener != null || info.mOnDragListener != null; 15714 } 15715 15716 /** 15717 * Notifies that the accessibility state of this view changed. The change 15718 * is local to this view and does not represent structural changes such 15719 * as children and parent. For example, the view became focusable. Some of 15720 * the notification is at at most once every 15721 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 15722 * to avoid unnecessary load to the system. Also once a view has a pending 15723 * notification this method is a NOP until the notification has been sent. 15724 * 15725 * @hide 15726 */ 15727 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) notifyViewAccessibilityStateChangedIfNeeded(int changeType)15728 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 15729 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 15730 return; 15731 } 15732 15733 // Changes to views with a pane title count as window state changes, as the pane title 15734 // marks them as significant parts of the UI. A visible view with a nulled title may send 15735 // a disappeared event. 15736 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 15737 && (isAccessibilityPane() 15738 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) 15739 && isAggregatedVisible())) { 15740 // If the pane isn't visible, content changed events are sufficient unless we're 15741 // reporting that the view just disappeared 15742 if ((isAggregatedVisible()) 15743 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 15744 final AccessibilityEvent event = AccessibilityEvent.obtain(); 15745 onInitializeAccessibilityEvent(event); 15746 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 15747 event.setContentChangeTypes(changeType); 15748 event.setSource(this); 15749 onPopulateAccessibilityEvent(event); 15750 if (mParent != null) { 15751 try { 15752 mParent.requestSendAccessibilityEvent(this, event); 15753 } catch (AbstractMethodError e) { 15754 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 15755 + " does not fully implement ViewParent", e); 15756 } 15757 } 15758 return; 15759 } 15760 } 15761 15762 // If this is a live region, we should send a subtree change event 15763 // from this view immediately. Otherwise, we can let it propagate up. 15764 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 15765 final AccessibilityEvent event = AccessibilityEvent.obtain(); 15766 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 15767 event.setContentChangeTypes(changeType); 15768 sendAccessibilityEventUnchecked(event); 15769 } else if (mParent != null) { 15770 try { 15771 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 15772 } catch (AbstractMethodError e) { 15773 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15774 " does not fully implement ViewParent", e); 15775 } 15776 } 15777 } 15778 15779 /** 15780 * Notifies that the accessibility state of this view changed. The change 15781 * is *not* local to this view and does represent structural changes such 15782 * as children and parent. For example, the view size changed. Some of the 15783 * notification is at at most once every 15784 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 15785 * to avoid unnecessary load to the system. Also once a view has a pending 15786 * notification this method is a NOP until the notification has been sent. 15787 * 15788 * @hide 15789 */ 15790 @UnsupportedAppUsage notifySubtreeAccessibilityStateChangedIfNeeded()15791 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 15792 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 15793 return; 15794 } 15795 15796 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 15797 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 15798 if (mParent != null) { 15799 try { 15800 mParent.notifySubtreeAccessibilityStateChanged( 15801 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 15802 } catch (AbstractMethodError e) { 15803 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15804 " does not fully implement ViewParent", e); 15805 } 15806 } 15807 } 15808 } 15809 notifySubtreeAccessibilityStateChangedByParentIfNeeded()15810 private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { 15811 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 15812 return; 15813 } 15814 15815 final View sendA11yEventView = (View) getParentForAccessibility(); 15816 if (sendA11yEventView != null && sendA11yEventView.isShown()) { 15817 sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); 15818 } 15819 } 15820 15821 /** 15822 * Changes the visibility of this View without triggering any other changes. This should only 15823 * be used by animation frameworks, such as {@link android.transition.Transition}, where 15824 * visibility changes should not adjust focus or trigger a new layout. Application developers 15825 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 15826 * 15827 * <p>Only call this method when a temporary visibility must be applied during an 15828 * animation and the original visibility value is guaranteed to be reset after the 15829 * animation completes. Use {@link #setVisibility} in all other cases.</p> 15830 * 15831 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 15832 * @see #setVisibility(int) 15833 */ setTransitionVisibility(@isibility int visibility)15834 public void setTransitionVisibility(@Visibility int visibility) { 15835 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 15836 } 15837 15838 /** 15839 * Reset the flag indicating the accessibility state of the subtree rooted 15840 * at this view changed. 15841 */ resetSubtreeAccessibilityStateChanged()15842 void resetSubtreeAccessibilityStateChanged() { 15843 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 15844 } 15845 15846 /** 15847 * Report an accessibility action to this view's parents for delegated processing. 15848 * 15849 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 15850 * call this method to delegate an accessibility action to a supporting parent. If the parent 15851 * returns true from its 15852 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 15853 * method this method will return true to signify that the action was consumed.</p> 15854 * 15855 * <p>This method is useful for implementing nested scrolling child views. If 15856 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 15857 * a custom view implementation may invoke this method to allow a parent to consume the 15858 * scroll first. If this method returns true the custom view should skip its own scrolling 15859 * behavior.</p> 15860 * 15861 * @param action Accessibility action to delegate 15862 * @param arguments Optional action arguments 15863 * @return true if the action was consumed by a parent 15864 */ dispatchNestedPrePerformAccessibilityAction(int action, @Nullable Bundle arguments)15865 public boolean dispatchNestedPrePerformAccessibilityAction(int action, 15866 @Nullable Bundle arguments) { 15867 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 15868 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 15869 return true; 15870 } 15871 } 15872 return false; 15873 } 15874 15875 /** 15876 * Performs the specified accessibility action on the view. For 15877 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 15878 * <p> 15879 * If an {@link AccessibilityDelegate} has been specified via calling 15880 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 15881 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 15882 * is responsible for handling this call. 15883 * </p> 15884 * 15885 * <p>The default implementation will delegate 15886 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 15887 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 15888 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 15889 * 15890 * <p> 15891 * <b>Note:</b> Avoid setting accessibility focus with 15892 * {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS}. This is intended to be controlled 15893 * by screen readers. Apps changing focus can confuse screen readers, so the resulting behavior 15894 * can vary by device and screen reader version. 15895 * 15896 * @param action The action to perform. 15897 * @param arguments Optional action arguments. 15898 * @return Whether the action was performed. 15899 */ performAccessibilityAction(int action, @Nullable Bundle arguments)15900 public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) { 15901 if (mAccessibilityDelegate != null) { 15902 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 15903 } else { 15904 return performAccessibilityActionInternal(action, arguments); 15905 } 15906 } 15907 15908 /** 15909 * @see #performAccessibilityAction(int, Bundle) 15910 * 15911 * Note: Called from the default {@link AccessibilityDelegate}. 15912 * 15913 * @hide 15914 */ 15915 @UnsupportedAppUsage performAccessibilityActionInternal(int action, @Nullable Bundle arguments)15916 public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) { 15917 if (isNestedScrollingEnabled() 15918 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 15919 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 15920 || action == R.id.accessibilityActionScrollUp 15921 || action == R.id.accessibilityActionScrollLeft 15922 || action == R.id.accessibilityActionScrollDown 15923 || action == R.id.accessibilityActionScrollRight)) { 15924 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 15925 return true; 15926 } 15927 } 15928 15929 switch (action) { 15930 case AccessibilityNodeInfo.ACTION_CLICK: { 15931 if (isClickable()) { 15932 performClickInternal(); 15933 return true; 15934 } 15935 } break; 15936 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 15937 if (isLongClickable()) { 15938 performLongClick(); 15939 return true; 15940 } 15941 } break; 15942 case AccessibilityNodeInfo.ACTION_FOCUS: { 15943 if (!hasFocus()) { 15944 // Get out of touch mode since accessibility 15945 // wants to move focus around. 15946 getViewRootImpl().ensureTouchMode(false); 15947 return requestFocus(); 15948 } 15949 } break; 15950 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 15951 if (hasFocus()) { 15952 clearFocus(); 15953 return !isFocused(); 15954 } 15955 } break; 15956 case AccessibilityNodeInfo.ACTION_SELECT: { 15957 if (!isSelected()) { 15958 setSelected(true); 15959 return isSelected(); 15960 } 15961 } break; 15962 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 15963 if (isSelected()) { 15964 setSelected(false); 15965 return !isSelected(); 15966 } 15967 } break; 15968 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 15969 if (!isAccessibilityFocused()) { 15970 return requestAccessibilityFocus(); 15971 } 15972 } break; 15973 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 15974 if (isAccessibilityFocused()) { 15975 clearAccessibilityFocus(); 15976 return true; 15977 } 15978 } break; 15979 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 15980 if (arguments != null) { 15981 final int granularity = arguments.getInt( 15982 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 15983 final boolean extendSelection = arguments.getBoolean( 15984 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 15985 return traverseAtGranularity(granularity, true, extendSelection); 15986 } 15987 } break; 15988 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 15989 if (arguments != null) { 15990 final int granularity = arguments.getInt( 15991 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 15992 final boolean extendSelection = arguments.getBoolean( 15993 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 15994 return traverseAtGranularity(granularity, false, extendSelection); 15995 } 15996 } break; 15997 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 15998 CharSequence text = getIterableTextForAccessibility(); 15999 if (text == null) { 16000 return false; 16001 } 16002 final int start = (arguments != null) ? arguments.getInt( 16003 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 16004 final int end = (arguments != null) ? arguments.getInt( 16005 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 16006 // Only cursor position can be specified (selection length == 0) 16007 if ((getAccessibilitySelectionStart() != start 16008 || getAccessibilitySelectionEnd() != end) 16009 && (start == end)) { 16010 setAccessibilitySelection(start, end); 16011 notifyViewAccessibilityStateChangedIfNeeded( 16012 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16013 return true; 16014 } 16015 } break; 16016 case R.id.accessibilityActionShowOnScreen: { 16017 if (mAttachInfo != null) { 16018 final Rect r = mAttachInfo.mTmpInvalRect; 16019 getDrawingRect(r); 16020 return requestRectangleOnScreen(r, true); 16021 } 16022 } break; 16023 case R.id.accessibilityActionContextClick: { 16024 if (isContextClickable()) { 16025 performContextClick(); 16026 return true; 16027 } 16028 } break; 16029 case R.id.accessibilityActionShowTooltip: { 16030 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 16031 // Tooltip already showing 16032 return false; 16033 } 16034 return showLongClickTooltip(0, 0); 16035 } 16036 case R.id.accessibilityActionHideTooltip: { 16037 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 16038 // No tooltip showing 16039 return false; 16040 } 16041 hideTooltip(); 16042 return true; 16043 } 16044 case R.id.accessibilityActionDragDrop: { 16045 if (!canAcceptAccessibilityDrop()) { 16046 return false; 16047 } 16048 try { 16049 if (mAttachInfo != null && mAttachInfo.mSession != null) { 16050 final int[] location = new int[2]; 16051 getLocationInWindow(location); 16052 final int centerX = location[0] + getWidth() / 2; 16053 final int centerY = location[1] + getHeight() / 2; 16054 return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, 16055 centerX, centerY); 16056 } 16057 } catch (RemoteException e) { 16058 Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); 16059 } 16060 return false; 16061 } 16062 case R.id.accessibilityActionDragCancel: { 16063 if (!startedSystemDragForAccessibility()) { 16064 return false; 16065 } 16066 if (mAttachInfo != null && mAttachInfo.mDragToken != null) { 16067 cancelDragAndDrop(); 16068 return true; 16069 } 16070 return false; 16071 } 16072 } 16073 return false; 16074 } 16075 canAcceptAccessibilityDrop()16076 private boolean canAcceptAccessibilityDrop() { 16077 if (!canAcceptDrag()) { 16078 return false; 16079 } 16080 ListenerInfo li = mListenerInfo; 16081 return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); 16082 } 16083 traverseAtGranularity(int granularity, boolean forward, boolean extendSelection)16084 private boolean traverseAtGranularity(int granularity, boolean forward, 16085 boolean extendSelection) { 16086 CharSequence text = getIterableTextForAccessibility(); 16087 if (text == null || text.length() == 0) { 16088 return false; 16089 } 16090 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 16091 if (iterator == null) { 16092 return false; 16093 } 16094 int current = getAccessibilitySelectionEnd(); 16095 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 16096 current = forward ? 0 : text.length(); 16097 } 16098 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 16099 if (range == null) { 16100 return false; 16101 } 16102 final int segmentStart = range[0]; 16103 final int segmentEnd = range[1]; 16104 int selectionStart; 16105 int selectionEnd; 16106 if (extendSelection && isAccessibilitySelectionExtendable()) { 16107 prepareForExtendedAccessibilitySelection(); 16108 selectionStart = getAccessibilitySelectionStart(); 16109 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 16110 selectionStart = forward ? segmentStart : segmentEnd; 16111 } 16112 selectionEnd = forward ? segmentEnd : segmentStart; 16113 } else { 16114 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 16115 } 16116 setAccessibilitySelection(selectionStart, selectionEnd); 16117 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 16118 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 16119 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 16120 return true; 16121 } 16122 16123 /** 16124 * Gets the text reported for accessibility purposes. 16125 * 16126 * @return The accessibility text. 16127 * 16128 * @hide 16129 */ 16130 @UnsupportedAppUsage getIterableTextForAccessibility()16131 public CharSequence getIterableTextForAccessibility() { 16132 return getContentDescription(); 16133 } 16134 16135 /** 16136 * Gets whether accessibility selection can be extended. 16137 * 16138 * @return If selection is extensible. 16139 * 16140 * @hide 16141 */ isAccessibilitySelectionExtendable()16142 public boolean isAccessibilitySelectionExtendable() { 16143 return false; 16144 } 16145 16146 /** 16147 * Prepare for extended selection. 16148 * @hide 16149 */ prepareForExtendedAccessibilitySelection()16150 public void prepareForExtendedAccessibilitySelection() { 16151 return; 16152 } 16153 16154 /** 16155 * @hide 16156 */ getAccessibilitySelectionStart()16157 public int getAccessibilitySelectionStart() { 16158 return mAccessibilityCursorPosition; 16159 } 16160 16161 /** 16162 * @hide 16163 */ getAccessibilitySelectionEnd()16164 public int getAccessibilitySelectionEnd() { 16165 return getAccessibilitySelectionStart(); 16166 } 16167 16168 /** 16169 * @hide 16170 */ setAccessibilitySelection(int start, int end)16171 public void setAccessibilitySelection(int start, int end) { 16172 if (start == end && end == mAccessibilityCursorPosition) { 16173 return; 16174 } 16175 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 16176 mAccessibilityCursorPosition = start; 16177 } else { 16178 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 16179 } 16180 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 16181 } 16182 sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex)16183 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 16184 int fromIndex, int toIndex) { 16185 if (mParent == null) { 16186 return; 16187 } 16188 AccessibilityEvent event = AccessibilityEvent.obtain( 16189 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 16190 onInitializeAccessibilityEvent(event); 16191 onPopulateAccessibilityEvent(event); 16192 event.setFromIndex(fromIndex); 16193 event.setToIndex(toIndex); 16194 event.setAction(action); 16195 event.setMovementGranularity(granularity); 16196 mParent.requestSendAccessibilityEvent(this, event); 16197 } 16198 16199 /** 16200 * @hide 16201 */ 16202 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getIteratorForGranularity(int granularity)16203 public TextSegmentIterator getIteratorForGranularity(int granularity) { 16204 switch (granularity) { 16205 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 16206 CharSequence text = getIterableTextForAccessibility(); 16207 if (text != null && text.length() > 0) { 16208 CharacterTextSegmentIterator iterator = 16209 CharacterTextSegmentIterator.getInstance( 16210 mContext.getResources().getConfiguration().locale); 16211 iterator.initialize(text.toString()); 16212 return iterator; 16213 } 16214 } break; 16215 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 16216 CharSequence text = getIterableTextForAccessibility(); 16217 if (text != null && text.length() > 0) { 16218 WordTextSegmentIterator iterator = 16219 WordTextSegmentIterator.getInstance( 16220 mContext.getResources().getConfiguration().locale); 16221 iterator.initialize(text.toString()); 16222 return iterator; 16223 } 16224 } break; 16225 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 16226 CharSequence text = getIterableTextForAccessibility(); 16227 if (text != null && text.length() > 0) { 16228 ParagraphTextSegmentIterator iterator = 16229 ParagraphTextSegmentIterator.getInstance(); 16230 iterator.initialize(text.toString()); 16231 return iterator; 16232 } 16233 } break; 16234 } 16235 return null; 16236 } 16237 16238 /** 16239 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 16240 * and {@link #onFinishTemporaryDetach()}. 16241 * 16242 * <p>This method always returns {@code true} when called directly or indirectly from 16243 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 16244 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 16245 * <ul> 16246 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 16247 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 16248 * </ul> 16249 * </p> 16250 * 16251 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 16252 * and {@link #onFinishTemporaryDetach()}. 16253 */ isTemporarilyDetached()16254 public final boolean isTemporarilyDetached() { 16255 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 16256 } 16257 16258 /** 16259 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 16260 * a container View. 16261 */ 16262 @CallSuper dispatchStartTemporaryDetach()16263 public void dispatchStartTemporaryDetach() { 16264 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 16265 notifyEnterOrExitForAutoFillIfNeeded(false); 16266 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 16267 onStartTemporaryDetach(); 16268 } 16269 16270 /** 16271 * This is called when a container is going to temporarily detach a child, with 16272 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 16273 * It will either be followed by {@link #onFinishTemporaryDetach()} or 16274 * {@link #onDetachedFromWindow()} when the container is done. 16275 */ onStartTemporaryDetach()16276 public void onStartTemporaryDetach() { 16277 removeUnsetPressCallback(); 16278 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 16279 } 16280 16281 /** 16282 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 16283 * a container View. 16284 */ 16285 @CallSuper dispatchFinishTemporaryDetach()16286 public void dispatchFinishTemporaryDetach() { 16287 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 16288 onFinishTemporaryDetach(); 16289 if (hasWindowFocus() && hasFocus()) { 16290 notifyFocusChangeToImeFocusController(true /* hasFocus */); 16291 } 16292 notifyEnterOrExitForAutoFillIfNeeded(true); 16293 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 16294 } 16295 16296 /** 16297 * Called after {@link #onStartTemporaryDetach} when the container is done 16298 * changing the view. 16299 */ onFinishTemporaryDetach()16300 public void onFinishTemporaryDetach() { 16301 } 16302 16303 /** 16304 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 16305 * for this view's window. Returns null if the view is not currently attached 16306 * to the window. Normally you will not need to use this directly, but 16307 * just use the standard high-level event callbacks like 16308 * {@link #onKeyDown(int, KeyEvent)}. 16309 */ getKeyDispatcherState()16310 public KeyEvent.DispatcherState getKeyDispatcherState() { 16311 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 16312 } 16313 16314 /** 16315 * Dispatch a key event before it is processed by any input method 16316 * associated with the view hierarchy. This can be used to intercept 16317 * key events in special situations before the IME consumes them; a 16318 * typical example would be handling the BACK key to update the application's 16319 * UI instead of allowing the IME to see it and close itself. 16320 * 16321 * @param event The key event to be dispatched. 16322 * @return True if the event was handled, false otherwise. 16323 */ dispatchKeyEventPreIme(KeyEvent event)16324 public boolean dispatchKeyEventPreIme(KeyEvent event) { 16325 return onKeyPreIme(event.getKeyCode(), event); 16326 } 16327 16328 /** 16329 * Dispatch a key event to the next view on the focus path. This path runs 16330 * from the top of the view tree down to the currently focused view. If this 16331 * view has focus, it will dispatch to itself. Otherwise it will dispatch 16332 * the next node down the focus path. This method also fires any key 16333 * listeners. 16334 * 16335 * @param event The key event to be dispatched. 16336 * @return True if the event was handled, false otherwise. 16337 */ dispatchKeyEvent(KeyEvent event)16338 public boolean dispatchKeyEvent(KeyEvent event) { 16339 if (mInputEventConsistencyVerifier != null) { 16340 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 16341 } 16342 16343 // Give any attached key listener a first crack at the event. 16344 //noinspection SimplifiableIfStatement 16345 ListenerInfo li = mListenerInfo; 16346 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 16347 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 16348 return true; 16349 } 16350 16351 if (event.dispatch(this, mAttachInfo != null 16352 ? mAttachInfo.mKeyDispatchState : null, this)) { 16353 return true; 16354 } 16355 16356 if (mInputEventConsistencyVerifier != null) { 16357 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16358 } 16359 return false; 16360 } 16361 16362 /** 16363 * Dispatches a key shortcut event. 16364 * 16365 * @param event The key event to be dispatched. 16366 * @return True if the event was handled by the view, false otherwise. 16367 */ dispatchKeyShortcutEvent(KeyEvent event)16368 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 16369 return onKeyShortcut(event.getKeyCode(), event); 16370 } 16371 16372 /** 16373 * Pass the touch screen motion event down to the target view, or this 16374 * view if it is the target. 16375 * 16376 * @param event The motion event to be dispatched. 16377 * @return True if the event was handled by the view, false otherwise. 16378 * 16379 * @see #onTouchEvent(MotionEvent) 16380 */ dispatchTouchEvent(MotionEvent event)16381 public boolean dispatchTouchEvent(MotionEvent event) { 16382 // If the event should be handled by accessibility focus first. 16383 if (event.isTargetAccessibilityFocus()) { 16384 // We don't have focus or no virtual descendant has it, do not handle the event. 16385 if (!isAccessibilityFocusedViewOrHost()) { 16386 return false; 16387 } 16388 // We have focus and got the event, then use normal event dispatch. 16389 event.setTargetAccessibilityFocus(false); 16390 } 16391 boolean result = false; 16392 16393 if (mInputEventConsistencyVerifier != null) { 16394 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 16395 } 16396 16397 final int actionMasked = event.getActionMasked(); 16398 if (actionMasked == MotionEvent.ACTION_DOWN) { 16399 // Defensive cleanup for new gesture 16400 stopNestedScroll(); 16401 } 16402 16403 if (onFilterTouchEventForSecurity(event)) { 16404 result = performOnTouchCallback(event); 16405 } 16406 16407 if (!result && mInputEventConsistencyVerifier != null) { 16408 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16409 } 16410 16411 // Clean up after nested scrolls if this is the end of a gesture; 16412 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 16413 // of the gesture. 16414 if (actionMasked == MotionEvent.ACTION_UP || 16415 actionMasked == MotionEvent.ACTION_CANCEL || 16416 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 16417 stopNestedScroll(); 16418 } 16419 16420 return result; 16421 } 16422 16423 /** 16424 * Returns {@code true} if the {@link MotionEvent} from {@link #dispatchTouchEvent} was 16425 * handled by this view. 16426 */ performOnTouchCallback(MotionEvent event)16427 private boolean performOnTouchCallback(MotionEvent event) { 16428 boolean handled = false; 16429 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 16430 handled = true; 16431 } 16432 //noinspection SimplifiableIfStatement 16433 ListenerInfo li = mListenerInfo; 16434 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED) { 16435 try { 16436 Trace.traceBegin(TRACE_TAG_VIEW, "View.onTouchListener#onTouch"); 16437 handled = li.mOnTouchListener.onTouch(this, event); 16438 } finally { 16439 Trace.traceEnd(TRACE_TAG_VIEW); 16440 } 16441 } 16442 if (handled) { 16443 return true; 16444 } 16445 try { 16446 Trace.traceBegin(TRACE_TAG_VIEW, "View#onTouchEvent"); 16447 return onTouchEvent(event); 16448 } finally { 16449 Trace.traceEnd(TRACE_TAG_VIEW); 16450 } 16451 } 16452 isAccessibilityFocusedViewOrHost()16453 boolean isAccessibilityFocusedViewOrHost() { 16454 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 16455 .getAccessibilityFocusedHost() == this); 16456 } 16457 16458 /** 16459 * Returns whether this view can receive pointer events. 16460 * 16461 * @return {@code true} if this view can receive pointer events. 16462 * @hide 16463 */ canReceivePointerEvents()16464 protected boolean canReceivePointerEvents() { 16465 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 16466 } 16467 16468 /** 16469 * Filter the touch event to apply security policies. 16470 * 16471 * @param event The motion event to be filtered. 16472 * @return True if the event should be dispatched, false if the event should be dropped. 16473 * 16474 * @see #getFilterTouchesWhenObscured 16475 */ onFilterTouchEventForSecurity(MotionEvent event)16476 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 16477 //noinspection RedundantIfStatement 16478 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 16479 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 16480 // Window is obscured, drop this touch. 16481 return false; 16482 } 16483 return true; 16484 } 16485 16486 /** 16487 * Pass a trackball motion event down to the focused view. 16488 * 16489 * @param event The motion event to be dispatched. 16490 * @return True if the event was handled by the view, false otherwise. 16491 * 16492 * @see #onTrackballEvent(MotionEvent) 16493 */ dispatchTrackballEvent(MotionEvent event)16494 public boolean dispatchTrackballEvent(MotionEvent event) { 16495 if (mInputEventConsistencyVerifier != null) { 16496 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 16497 } 16498 16499 return onTrackballEvent(event); 16500 } 16501 16502 /** 16503 * Pass a captured pointer event down to the focused view. 16504 * 16505 * @param event The motion event to be dispatched. 16506 * @return True if the event was handled by the view, false otherwise. 16507 */ dispatchCapturedPointerEvent(MotionEvent event)16508 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 16509 if (!hasPointerCapture()) { 16510 return false; 16511 } 16512 //noinspection SimplifiableIfStatement 16513 ListenerInfo li = mListenerInfo; 16514 if (li != null && li.mOnCapturedPointerListener != null 16515 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 16516 return true; 16517 } 16518 return onCapturedPointerEvent(event); 16519 } 16520 16521 /** 16522 * Dispatch a generic motion event. 16523 * <p> 16524 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 16525 * are delivered to the view under the pointer. All other generic motion events are 16526 * delivered to the focused view. Hover events are handled specially and are delivered 16527 * to {@link #onHoverEvent(MotionEvent)} first. 16528 * </p> 16529 * 16530 * @param event The motion event to be dispatched. 16531 * @return True if the event was handled by the view, false otherwise. 16532 * 16533 * @see #onHoverEvent(MotionEvent) 16534 * @see #onGenericMotionEvent(MotionEvent) 16535 */ dispatchGenericMotionEvent(MotionEvent event)16536 public boolean dispatchGenericMotionEvent(MotionEvent event) { 16537 if (mInputEventConsistencyVerifier != null) { 16538 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 16539 } 16540 16541 final int source = event.getSource(); 16542 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 16543 final int action = event.getAction(); 16544 if (action == MotionEvent.ACTION_HOVER_ENTER 16545 || action == MotionEvent.ACTION_HOVER_MOVE 16546 || action == MotionEvent.ACTION_HOVER_EXIT) { 16547 if (dispatchHoverEvent(event)) { 16548 return true; 16549 } 16550 } else if (dispatchGenericPointerEvent(event)) { 16551 return true; 16552 } 16553 } else if (dispatchGenericFocusedEvent(event)) { 16554 return true; 16555 } 16556 16557 if (dispatchGenericMotionEventInternal(event)) { 16558 return true; 16559 } 16560 16561 if (mInputEventConsistencyVerifier != null) { 16562 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16563 } 16564 return false; 16565 } 16566 dispatchGenericMotionEventInternal(MotionEvent event)16567 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 16568 final boolean isRotaryEncoderEvent = event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER); 16569 if (isRotaryEncoderEvent) { 16570 // Determine and cache rotary scroll haptics support if it's not yet determined. 16571 // Caching the support is important for two reasons: 16572 // 1) Limits call to `ViewConfiguration#get`, which we should avoid if possible. 16573 // 2) Limits latency from the `ViewConfiguration` API, which may be slow due to feature 16574 // flag querying. 16575 if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_DETERMINED) == 0) { 16576 if (ViewConfiguration.get(mContext) 16577 .isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()) { 16578 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_ENABLED; 16579 } 16580 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_DETERMINED; 16581 } 16582 } 16583 final boolean processForRotaryScrollHaptics = 16584 isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0); 16585 if (processForRotaryScrollHaptics) { 16586 mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT; 16587 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT; 16588 } 16589 16590 //noinspection SimplifiableIfStatement 16591 ListenerInfo li = mListenerInfo; 16592 if (li != null && li.mOnGenericMotionListener != null 16593 && (mViewFlags & ENABLED_MASK) == ENABLED 16594 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 16595 return true; 16596 } 16597 16598 final boolean onGenericMotionEventResult = onGenericMotionEvent(event); 16599 // Process scroll haptics after `onGenericMotionEvent`, since that's where scrolling usually 16600 // happens. Some views may return false from `onGenericMotionEvent` even if they have done 16601 // scrolling, so disregard the return value when processing for scroll haptics. 16602 if (processForRotaryScrollHaptics) { 16603 if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT) != 0) { 16604 doRotaryProgressForScrollHaptics(event); 16605 } else { 16606 doRotaryLimitForScrollHaptics(event); 16607 } 16608 } 16609 if (onGenericMotionEventResult) { 16610 return true; 16611 } 16612 16613 final int actionButton = event.getActionButton(); 16614 switch (event.getActionMasked()) { 16615 case MotionEvent.ACTION_BUTTON_PRESS: 16616 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 16617 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 16618 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 16619 if (performContextClick(event.getX(), event.getY())) { 16620 mInContextButtonPress = true; 16621 setPressed(true, event.getX(), event.getY()); 16622 removeTapCallback(); 16623 removeLongPressCallback(); 16624 return true; 16625 } 16626 } 16627 break; 16628 16629 case MotionEvent.ACTION_BUTTON_RELEASE: 16630 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 16631 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 16632 mInContextButtonPress = false; 16633 mIgnoreNextUpEvent = true; 16634 } 16635 break; 16636 } 16637 16638 if (mInputEventConsistencyVerifier != null) { 16639 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16640 } 16641 return false; 16642 } 16643 16644 /** 16645 * Dispatch a hover event. 16646 * <p> 16647 * Do not call this method directly. 16648 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 16649 * </p> 16650 * 16651 * @param event The motion event to be dispatched. 16652 * @return True if the event was handled by the view, false otherwise. 16653 */ dispatchHoverEvent(MotionEvent event)16654 protected boolean dispatchHoverEvent(MotionEvent event) { 16655 ListenerInfo li = mListenerInfo; 16656 //noinspection SimplifiableIfStatement 16657 if (li != null && li.mOnHoverListener != null 16658 && (mViewFlags & ENABLED_MASK) == ENABLED 16659 && li.mOnHoverListener.onHover(this, event)) { 16660 return true; 16661 } 16662 16663 return onHoverEvent(event); 16664 } 16665 16666 /** 16667 * Returns true if the view has a child to which it has recently sent 16668 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 16669 * it does not have a hovered child, then it must be the innermost hovered view. 16670 * @hide 16671 */ hasHoveredChild()16672 protected boolean hasHoveredChild() { 16673 return false; 16674 } 16675 16676 /** 16677 * Returns true if the given point, in local coordinates, is inside the hovered child. 16678 * 16679 * @hide 16680 */ pointInHoveredChild(MotionEvent event)16681 protected boolean pointInHoveredChild(MotionEvent event) { 16682 return false; 16683 } 16684 16685 /** 16686 * Dispatch a generic motion event to the view under the first pointer. 16687 * <p> 16688 * Do not call this method directly. 16689 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 16690 * </p> 16691 * 16692 * @param event The motion event to be dispatched. 16693 * @return True if the event was handled by the view, false otherwise. 16694 */ dispatchGenericPointerEvent(MotionEvent event)16695 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 16696 return false; 16697 } 16698 16699 /** 16700 * Dispatch a generic motion event to the currently focused view. 16701 * <p> 16702 * Do not call this method directly. 16703 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 16704 * </p> 16705 * 16706 * @param event The motion event to be dispatched. 16707 * @return True if the event was handled by the view, false otherwise. 16708 */ dispatchGenericFocusedEvent(MotionEvent event)16709 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 16710 return false; 16711 } 16712 16713 /** 16714 * Dispatch a pointer event. 16715 * <p> 16716 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 16717 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 16718 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 16719 * and should not be expected to handle other pointing device features. 16720 * </p> 16721 * 16722 * @param event The motion event to be dispatched. 16723 * @return True if the event was handled by the view, false otherwise. 16724 * @hide 16725 */ 16726 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchPointerEvent(MotionEvent event)16727 public final boolean dispatchPointerEvent(MotionEvent event) { 16728 if (event.isTouchEvent()) { 16729 return dispatchTouchEvent(event); 16730 } else { 16731 return dispatchGenericMotionEvent(event); 16732 } 16733 } 16734 16735 /** 16736 * Called when the window containing this view gains or loses window focus. 16737 * ViewGroups should override to route to their children. 16738 * 16739 * @param hasFocus True if the window containing this view now has focus, 16740 * false otherwise. 16741 */ dispatchWindowFocusChanged(boolean hasFocus)16742 public void dispatchWindowFocusChanged(boolean hasFocus) { 16743 onWindowFocusChanged(hasFocus); 16744 } 16745 16746 /** 16747 * Called when the window containing this view gains or loses focus. Note 16748 * that this is separate from view focus: to receive key events, both 16749 * your view and its window must have focus. If a window is displayed 16750 * on top of yours that takes input focus, then your own window will lose 16751 * focus but the view focus will remain unchanged. 16752 * 16753 * @param hasWindowFocus True if the window containing this view now has 16754 * focus, false otherwise. 16755 */ onWindowFocusChanged(boolean hasWindowFocus)16756 public void onWindowFocusChanged(boolean hasWindowFocus) { 16757 if (!hasWindowFocus) { 16758 if (isPressed()) { 16759 setPressed(false); 16760 } 16761 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16762 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 16763 notifyFocusChangeToImeFocusController(false /* hasFocus */); 16764 } 16765 removeLongPressCallback(); 16766 removeTapCallback(); 16767 onFocusLost(); 16768 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 16769 notifyFocusChangeToImeFocusController(true /* hasFocus */); 16770 ViewRootImpl viewRoot = getViewRootImpl(); 16771 if (viewRoot != null && initiationWithoutInputConnection() && onCheckIsTextEditor()) { 16772 viewRoot.getHandwritingInitiator().onEditorFocused(this); 16773 } 16774 } 16775 16776 refreshDrawableState(); 16777 } 16778 16779 /** 16780 * Returns true if this view is in a window that currently has window focus. 16781 * Note that this is not the same as the view itself having focus. 16782 * 16783 * @return True if this view is in a window that currently has window focus. 16784 */ hasWindowFocus()16785 public boolean hasWindowFocus() { 16786 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 16787 } 16788 16789 /** 16790 * @return {@code true} if this view is in a window that currently has IME focusable state. 16791 * @hide 16792 */ hasImeFocus()16793 public boolean hasImeFocus() { 16794 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 16795 } 16796 16797 /** 16798 * Dispatch a view visibility change down the view hierarchy. 16799 * ViewGroups should override to route to their children. 16800 * @param changedView The view whose visibility changed. Could be 'this' or 16801 * an ancestor view. 16802 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 16803 * {@link #INVISIBLE} or {@link #GONE}. 16804 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)16805 protected void dispatchVisibilityChanged(@NonNull View changedView, 16806 @Visibility int visibility) { 16807 onVisibilityChanged(changedView, visibility); 16808 } 16809 16810 /** 16811 * Called when the visibility of the view or an ancestor of the view has 16812 * changed. 16813 * 16814 * @param changedView The view whose visibility changed. May be 16815 * {@code this} or an ancestor view. 16816 * @param visibility The new visibility, one of {@link #VISIBLE}, 16817 * {@link #INVISIBLE} or {@link #GONE}. 16818 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)16819 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 16820 } 16821 16822 /** 16823 * Dispatch a hint about whether this view is displayed. For instance, when 16824 * a View moves out of the screen, it might receives a display hint indicating 16825 * the view is not displayed. Applications should not <em>rely</em> on this hint 16826 * as there is no guarantee that they will receive one. 16827 * 16828 * @param hint A hint about whether or not this view is displayed: 16829 * {@link #VISIBLE} or {@link #INVISIBLE}. 16830 */ dispatchDisplayHint(@isibility int hint)16831 public void dispatchDisplayHint(@Visibility int hint) { 16832 onDisplayHint(hint); 16833 } 16834 16835 /** 16836 * Gives this view a hint about whether is displayed or not. For instance, when 16837 * a View moves out of the screen, it might receives a display hint indicating 16838 * the view is not displayed. Applications should not <em>rely</em> on this hint 16839 * as there is no guarantee that they will receive one. 16840 * 16841 * @param hint A hint about whether or not this view is displayed: 16842 * {@link #VISIBLE} or {@link #INVISIBLE}. 16843 */ onDisplayHint(@isibility int hint)16844 protected void onDisplayHint(@Visibility int hint) { 16845 } 16846 16847 /** 16848 * Dispatch a window visibility change down the view hierarchy. 16849 * ViewGroups should override to route to their children. 16850 * 16851 * @param visibility The new visibility of the window. 16852 * 16853 * @see #onWindowVisibilityChanged(int) 16854 */ dispatchWindowVisibilityChanged(@isibility int visibility)16855 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 16856 onWindowVisibilityChanged(visibility); 16857 } 16858 16859 /** 16860 * Called when the window containing has change its visibility 16861 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 16862 * that this tells you whether or not your window is being made visible 16863 * to the window manager; this does <em>not</em> tell you whether or not 16864 * your window is obscured by other windows on the screen, even if it 16865 * is itself visible. 16866 * 16867 * @param visibility The new visibility of the window. 16868 */ onWindowVisibilityChanged(@isibility int visibility)16869 protected void onWindowVisibilityChanged(@Visibility int visibility) { 16870 if (visibility == VISIBLE) { 16871 initialAwakenScrollBars(); 16872 } 16873 } 16874 16875 /** 16876 * @return true if this view and all ancestors are visible as of the last 16877 * {@link #onVisibilityAggregated(boolean)} call. 16878 * 16879 * @hide 16880 */ isAggregatedVisible()16881 public boolean isAggregatedVisible() { 16882 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 16883 } 16884 16885 /** 16886 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 16887 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 16888 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 16889 * 16890 * @param isVisible true if this view's visibility to the user is uninterrupted by its 16891 * ancestors or by window visibility 16892 * @return true if this view is visible to the user, not counting clipping or overlapping 16893 */ dispatchVisibilityAggregated(boolean isVisible)16894 boolean dispatchVisibilityAggregated(boolean isVisible) { 16895 final boolean thisVisible = getVisibility() == VISIBLE; 16896 // If we're not visible but something is telling us we are, ignore it. 16897 if (thisVisible || !isVisible) { 16898 onVisibilityAggregated(isVisible); 16899 } 16900 return thisVisible && isVisible; 16901 } 16902 16903 /** 16904 * Called when the user-visibility of this View is potentially affected by a change 16905 * to this view itself, an ancestor view or the window this view is attached to. 16906 * 16907 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 16908 * and this view's window is also visible 16909 */ 16910 @CallSuper onVisibilityAggregated(boolean isVisible)16911 public void onVisibilityAggregated(boolean isVisible) { 16912 // Update our internal visibility tracking so we can detect changes 16913 boolean oldVisible = isAggregatedVisible(); 16914 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 16915 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 16916 if (isVisible && mAttachInfo != null) { 16917 initialAwakenScrollBars(); 16918 } 16919 16920 final Drawable dr = mBackground; 16921 if (dr != null && isVisible != dr.isVisible()) { 16922 dr.setVisible(isVisible, false); 16923 } 16924 final Drawable hl = mDefaultFocusHighlight; 16925 if (hl != null && isVisible != hl.isVisible()) { 16926 hl.setVisible(isVisible, false); 16927 } 16928 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 16929 if (fg != null && isVisible != fg.isVisible()) { 16930 fg.setVisible(isVisible, false); 16931 } 16932 notifyAutofillManagerViewVisibilityChanged(isVisible); 16933 if (isVisible != oldVisible) { 16934 if (isAccessibilityPane()) { 16935 notifyViewAccessibilityStateChangedIfNeeded(isVisible 16936 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 16937 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 16938 } 16939 16940 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 16941 updateSensitiveViewsCountIfNeeded(isVisible); 16942 16943 if (!getSystemGestureExclusionRects().isEmpty()) { 16944 postUpdate(this::updateSystemGestureExclusionRects); 16945 } 16946 16947 if (!collectPreferKeepClearRects().isEmpty()) { 16948 postUpdate(this::updateKeepClearRects); 16949 } 16950 } 16951 } 16952 notifyAutofillManagerViewVisibilityChanged(boolean isVisible)16953 private void notifyAutofillManagerViewVisibilityChanged(boolean isVisible) { 16954 if (isAutofillable()) { 16955 AutofillManager afm = getAutofillManager(); 16956 16957 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 16958 if (mVisibilityChangeForAutofillHandler != null) { 16959 mVisibilityChangeForAutofillHandler.removeMessages(0); 16960 } 16961 16962 // If the view is in the background but still part of the hierarchy this is called 16963 // with isVisible=false. Hence visibility==false requires further checks 16964 if (isVisible) { 16965 afm.notifyViewVisibilityChanged(this, true); 16966 } else { 16967 if (mVisibilityChangeForAutofillHandler == null) { 16968 mVisibilityChangeForAutofillHandler = 16969 new VisibilityChangeForAutofillHandler(afm, this); 16970 } 16971 // Let current operation (e.g. removal of the view from the hierarchy) 16972 // finish before checking state 16973 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 16974 } 16975 } 16976 } 16977 } 16978 16979 /** 16980 * Returns the current visibility of the window this view is attached to 16981 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 16982 * 16983 * @return Returns the current visibility of the view's window. 16984 */ 16985 @Visibility getWindowVisibility()16986 public int getWindowVisibility() { 16987 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 16988 } 16989 16990 /** 16991 * Retrieve the overall visible display size in which the window this view is 16992 * attached to has been positioned in. This takes into account screen 16993 * decorations above the window, for both cases where the window itself 16994 * is being position inside of them or the window is being placed under 16995 * then and covered insets are used for the window to position its content 16996 * inside. In effect, this tells you the available area where content can 16997 * be placed and remain visible to users. 16998 * 16999 * @param outRect Filled in with the visible display frame. If the view 17000 * is not attached to a window, this is simply the raw display size. 17001 */ getWindowVisibleDisplayFrame(Rect outRect)17002 public void getWindowVisibleDisplayFrame(Rect outRect) { 17003 if (mAttachInfo != null) { 17004 mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); 17005 return; 17006 } 17007 // TODO (b/327559224): Refine the behavior to better reflect the window environment with API 17008 // doc updates. 17009 final WindowManager windowManager = mContext.getSystemService(WindowManager.class); 17010 final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); 17011 final Insets insets = metrics.getWindowInsets().getInsets( 17012 WindowInsets.Type.navigationBars() | WindowInsets.Type.displayCutout()); 17013 outRect.set(metrics.getBounds()); 17014 outRect.inset(insets); 17015 outRect.offsetTo(0, 0); 17016 } 17017 17018 /** 17019 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 17020 * is currently in without any insets. 17021 * 17022 * @hide 17023 */ 17024 @UnsupportedAppUsage 17025 @TestApi getWindowDisplayFrame(@onNull Rect outRect)17026 public void getWindowDisplayFrame(@NonNull Rect outRect) { 17027 if (mAttachInfo != null) { 17028 mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); 17029 return; 17030 } 17031 // The view is not attached to a display so we don't have a context. 17032 // Make a best guess about the display size. 17033 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 17034 d.getRectSize(outRect); 17035 } 17036 17037 /** 17038 * Dispatch a notification about a resource configuration change down 17039 * the view hierarchy. 17040 * ViewGroups should override to route to their children. 17041 * 17042 * @param newConfig The new resource configuration. 17043 * 17044 * @see #onConfigurationChanged(android.content.res.Configuration) 17045 */ dispatchConfigurationChanged(Configuration newConfig)17046 public void dispatchConfigurationChanged(Configuration newConfig) { 17047 onConfigurationChanged(newConfig); 17048 } 17049 17050 /** 17051 * Called when the current configuration of the resources being used 17052 * by the application have changed. You can use this to decide when 17053 * to reload resources that can changed based on orientation and other 17054 * configuration characteristics. You only need to use this if you are 17055 * not relying on the normal {@link android.app.Activity} mechanism of 17056 * recreating the activity instance upon a configuration change. 17057 * 17058 * @param newConfig The new resource configuration. 17059 */ onConfigurationChanged(Configuration newConfig)17060 protected void onConfigurationChanged(Configuration newConfig) { 17061 } 17062 17063 /** 17064 * Private function to aggregate all per-view attributes in to the view 17065 * root. 17066 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)17067 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 17068 performCollectViewAttributes(attachInfo, visibility); 17069 } 17070 performCollectViewAttributes(AttachInfo attachInfo, int visibility)17071 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 17072 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 17073 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 17074 attachInfo.mKeepScreenOn = true; 17075 } 17076 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 17077 ListenerInfo li = mListenerInfo; 17078 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 17079 attachInfo.mHasSystemUiListeners = true; 17080 } 17081 } 17082 } 17083 needGlobalAttributesUpdate(boolean force)17084 void needGlobalAttributesUpdate(boolean force) { 17085 final AttachInfo ai = mAttachInfo; 17086 if (ai != null && !ai.mRecomputeGlobalAttributes) { 17087 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 17088 || ai.mHasSystemUiListeners) { 17089 ai.mRecomputeGlobalAttributes = true; 17090 } 17091 } 17092 } 17093 17094 /** 17095 * Returns the touch mode state associated with this view. 17096 * 17097 * Attached views return the touch mode state from the associated window's display. 17098 * Detached views just return the default touch mode value defined in 17099 * {@code com.android.internal.R.bool.config_defaultInTouchMode}. 17100 * 17101 * Touch mode is entered once the user begins interacting with the device by touch, and 17102 * affects various things like whether focus highlight is always visible to the user. 17103 * 17104 * @return the touch mode state associated with this view 17105 */ 17106 @ViewDebug.ExportedProperty isInTouchMode()17107 public boolean isInTouchMode() { 17108 if (mAttachInfo != null) { 17109 return mAttachInfo.mInTouchMode; 17110 } 17111 return mResources.getBoolean(com.android.internal.R.bool.config_defaultInTouchMode); 17112 } 17113 17114 /** 17115 * Returns the context the view is running in, through which it can 17116 * access the current theme, resources, etc. 17117 * 17118 * @return The view's Context. 17119 */ 17120 @ViewDebug.CapturedViewProperty 17121 @UiContext getContext()17122 public final Context getContext() { 17123 return mContext; 17124 } 17125 17126 /** 17127 * Handle a key event before it is processed by any input method 17128 * associated with the view hierarchy. This can be used to intercept 17129 * key events in special situations before the IME consumes them; a 17130 * typical example would be handling the BACK key to update the application's 17131 * UI instead of allowing the IME to see it and close itself. Due to a bug, 17132 * this function is not called for BACK key events on Android T and U, when 17133 * the IME is shown. 17134 * 17135 * @param keyCode The value in event.getKeyCode(). 17136 * @param event Description of the key event. 17137 * @return If you handled the event, return true. If you want to allow the 17138 * event to be handled by the next receiver, return false. 17139 */ onKeyPreIme(int keyCode, KeyEvent event)17140 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 17141 return false; 17142 } 17143 17144 /** 17145 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 17146 * KeyEvent.Callback.onKeyDown()}: perform press of the view 17147 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 17148 * is released, if the view is enabled and clickable. 17149 * <p> 17150 * Key presses in software keyboards will generally NOT trigger this 17151 * listener, although some may elect to do so in some situations. Do not 17152 * rely on this to catch software key presses. 17153 * 17154 * @param keyCode a key code that represents the button pressed, from 17155 * {@link android.view.KeyEvent} 17156 * @param event the KeyEvent object that defines the button action 17157 */ onKeyDown(int keyCode, KeyEvent event)17158 public boolean onKeyDown(int keyCode, KeyEvent event) { 17159 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 17160 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 17161 return true; 17162 } 17163 17164 if (event.getRepeatCount() == 0) { 17165 // Long clickable items don't necessarily have to be clickable. 17166 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 17167 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 17168 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 17169 // For the purposes of menu anchoring and drawable hotspots, 17170 // key events are considered to be at the center of the view. 17171 final float x = getWidth() / 2f; 17172 final float y = getHeight() / 2f; 17173 if (clickable) { 17174 setPressed(true, x, y); 17175 } 17176 checkForLongClick( 17177 ViewConfiguration.getLongPressTimeout(), 17178 x, 17179 y, 17180 // This is not a touch gesture -- do not classify it as one. 17181 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 17182 return true; 17183 } 17184 } 17185 } 17186 17187 return false; 17188 } 17189 17190 /** 17191 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 17192 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 17193 * the event). 17194 * <p>Key presses in software keyboards will generally NOT trigger this listener, 17195 * although some may elect to do so in some situations. Do not rely on this to 17196 * catch software key presses. 17197 */ onKeyLongPress(int keyCode, KeyEvent event)17198 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 17199 return false; 17200 } 17201 17202 /** 17203 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 17204 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 17205 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 17206 * or {@link KeyEvent#KEYCODE_SPACE} is released. 17207 * <p>Key presses in software keyboards will generally NOT trigger this listener, 17208 * although some may elect to do so in some situations. Do not rely on this to 17209 * catch software key presses. 17210 * 17211 * @param keyCode A key code that represents the button pressed, from 17212 * {@link android.view.KeyEvent}. 17213 * @param event The KeyEvent object that defines the button action. 17214 */ onKeyUp(int keyCode, KeyEvent event)17215 public boolean onKeyUp(int keyCode, KeyEvent event) { 17216 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 17217 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 17218 return true; 17219 } 17220 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 17221 setPressed(false); 17222 17223 if (!mHasPerformedLongPress) { 17224 // This is a tap, so remove the longpress check 17225 removeLongPressCallback(); 17226 if (!event.isCanceled()) { 17227 return performClickInternal(); 17228 } 17229 } 17230 } 17231 } 17232 return false; 17233 } 17234 17235 /** 17236 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 17237 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 17238 * the event). 17239 * <p>Key presses in software keyboards will generally NOT trigger this listener, 17240 * although some may elect to do so in some situations. Do not rely on this to 17241 * catch software key presses. 17242 * 17243 * @param keyCode A key code that represents the button pressed, from 17244 * {@link android.view.KeyEvent}. 17245 * @param repeatCount The number of times the action was made. 17246 * @param event The KeyEvent object that defines the button action. 17247 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)17248 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 17249 return false; 17250 } 17251 17252 /** 17253 * Called on the focused view when a key shortcut event is not handled. 17254 * Override this method to implement local key shortcuts for the View. 17255 * Key shortcuts can also be implemented by setting the 17256 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 17257 * 17258 * @param keyCode The value in event.getKeyCode(). 17259 * @param event Description of the key event. 17260 * @return If you handled the event, return true. If you want to allow the 17261 * event to be handled by the next receiver, return false. 17262 */ onKeyShortcut(int keyCode, KeyEvent event)17263 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 17264 return false; 17265 } 17266 17267 /** 17268 * Check whether the called view is a text editor, in which case it 17269 * would make sense to automatically display a soft input window for 17270 * it. Subclasses should override this if they implement 17271 * {@link #onCreateInputConnection(EditorInfo)} to return true if 17272 * a call on that method would return a non-null InputConnection, and 17273 * they are really a first-class editor that the user would normally 17274 * start typing on when the go into a window containing your view. 17275 * 17276 * <p>The default implementation always returns false. This does 17277 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 17278 * will not be called or the user can not otherwise perform edits on your 17279 * view; it is just a hint to the system that this is not the primary 17280 * purpose of this view. 17281 * 17282 * @return Returns true if this view is a text editor, else false. 17283 */ onCheckIsTextEditor()17284 public boolean onCheckIsTextEditor() { 17285 return false; 17286 } 17287 17288 /** 17289 * Create a new InputConnection for an InputMethod to interact 17290 * with the view. The default implementation returns null, since it doesn't 17291 * support input methods. You can override this to implement such support. 17292 * This is only needed for views that take focus and text input. 17293 * 17294 * <p>When implementing this, you probably also want to implement 17295 * {@link #onCheckIsTextEditor()} to indicate you will return a 17296 * non-null InputConnection.</p> 17297 * 17298 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 17299 * object correctly and in its entirety, so that the connected IME can rely 17300 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 17301 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 17302 * must be filled in with the correct cursor position for IMEs to work correctly 17303 * with your application.</p> 17304 * 17305 * @param outAttrs Fill in with attribute information about the connection. 17306 */ onCreateInputConnection(EditorInfo outAttrs)17307 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 17308 return null; 17309 } 17310 17311 /** 17312 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 17313 * that the system has successfully initialized an {@link InputConnection} and it is ready for 17314 * use. 17315 * 17316 * <p>The default implementation does nothing, since a view doesn't support input methods by 17317 * default (see {@link #onCreateInputConnection}). 17318 * 17319 * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, 17320 * after it's been fully initialized by the system. 17321 * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. 17322 * @param handler The dedicated {@link Handler} on which IPC method calls from input methods 17323 * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If 17324 * that method returns null, this parameter will be null also. 17325 * 17326 * @hide 17327 */ onInputConnectionOpenedInternal(@onNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler)17328 public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, 17329 @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} 17330 17331 /** 17332 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 17333 * that the {@link InputConnection} has been closed. 17334 * 17335 * <p>The default implementation does nothing, since a view doesn't support input methods by 17336 * default (see {@link #onCreateInputConnection}). 17337 * 17338 * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when 17339 * the {@link InputConnection} is closed or the connection is not valid and managed by 17340 * {@link com.android.server.inputmethod.InputMethodManagerService}. 17341 * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. 17342 * 17343 * @hide 17344 */ onInputConnectionClosedInternal()17345 public void onInputConnectionClosedInternal() {} 17346 17347 /** 17348 * Called by the {@link android.view.inputmethod.InputMethodManager} 17349 * when a view who is not the current 17350 * input connection target is trying to make a call on the manager. The 17351 * default implementation returns false; you can override this to return 17352 * true for certain views if you are performing InputConnection proxying 17353 * to them. 17354 * @param view The View that is making the InputMethodManager call. 17355 * @return Return true to allow the call, false to reject. 17356 */ checkInputConnectionProxy(View view)17357 public boolean checkInputConnectionProxy(View view) { 17358 return false; 17359 } 17360 17361 /** 17362 * Show the context menu for this view. It is not safe to hold on to the 17363 * menu after returning from this method. 17364 * 17365 * You should normally not overload this method. Overload 17366 * {@link #onCreateContextMenu(ContextMenu)} or define an 17367 * {@link OnCreateContextMenuListener} to add items to the context menu. 17368 * 17369 * @param menu The context menu to populate 17370 */ createContextMenu(ContextMenu menu)17371 public void createContextMenu(ContextMenu menu) { 17372 ContextMenuInfo menuInfo = getContextMenuInfo(); 17373 17374 // Sets the current menu info so all items added to menu will have 17375 // my extra info set. 17376 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 17377 17378 onCreateContextMenu(menu); 17379 ListenerInfo li = mListenerInfo; 17380 if (li != null && li.mOnCreateContextMenuListener != null) { 17381 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 17382 } 17383 17384 // Clear the extra information so subsequent items that aren't mine don't 17385 // have my extra info. 17386 ((MenuBuilder)menu).setCurrentMenuInfo(null); 17387 17388 if (mParent != null) { 17389 mParent.createContextMenu(menu); 17390 } 17391 } 17392 17393 /** 17394 * Views should implement this if they have extra information to associate 17395 * with the context menu. The return result is supplied as a parameter to 17396 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 17397 * callback. 17398 * 17399 * @return Extra information about the item for which the context menu 17400 * should be shown. This information will vary across different 17401 * subclasses of View. 17402 */ getContextMenuInfo()17403 protected ContextMenuInfo getContextMenuInfo() { 17404 return null; 17405 } 17406 17407 /** 17408 * Views should implement this if the view itself is going to add items to 17409 * the context menu. 17410 * 17411 * @param menu the context menu to populate 17412 */ onCreateContextMenu(ContextMenu menu)17413 protected void onCreateContextMenu(ContextMenu menu) { 17414 } 17415 17416 /** 17417 * Implement this method to handle trackball motion events. 17418 * <p> 17419 * The <em>relative</em> movement of the trackball since the last event 17420 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 17421 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 17422 * that a movement of 1 corresponds to the user pressing one DPAD key (so 17423 * they will often be fractional values, representing the more fine-grained 17424 * movement information available from a trackball). 17425 * </p> 17426 * 17427 * @param event The motion event. 17428 * @return True if the event was handled, false otherwise. 17429 */ onTrackballEvent(MotionEvent event)17430 public boolean onTrackballEvent(MotionEvent event) { 17431 return false; 17432 } 17433 17434 /** 17435 * Implement this method to handle generic motion events. 17436 * <p> 17437 * Generic motion events describe joystick movements, hover events from mouse or stylus 17438 * devices, trackpad touches, scroll wheel movements and other motion events not handled 17439 * by {@link #onTouchEvent(MotionEvent)} or {@link #onTrackballEvent(MotionEvent)}. 17440 * The {@link MotionEvent#getSource() source} of the motion event specifies 17441 * the class of input that was received. Implementations of this method 17442 * must examine the bits in the source before processing the event. 17443 * The following code example shows how this is done. 17444 * </p><p> 17445 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 17446 * are delivered to the view under the pointer. All other generic motion events are 17447 * delivered to the focused view. 17448 * </p> 17449 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 17450 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 17451 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 17452 * // process the joystick movement... 17453 * return true; 17454 * } 17455 * } 17456 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 17457 * switch (event.getAction()) { 17458 * case MotionEvent.ACTION_HOVER_MOVE: 17459 * // process the hover movement... 17460 * return true; 17461 * case MotionEvent.ACTION_SCROLL: 17462 * // process the scroll wheel movement... 17463 * return true; 17464 * } 17465 * } 17466 * return super.onGenericMotionEvent(event); 17467 * }</pre> 17468 * 17469 * @param event The generic motion event being processed. 17470 * @return True if the event was handled, false otherwise. 17471 */ onGenericMotionEvent(MotionEvent event)17472 public boolean onGenericMotionEvent(MotionEvent event) { 17473 return false; 17474 } 17475 17476 /** 17477 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 17478 * <p> 17479 * This method is dispatching hover events to the delegate target to support explore by touch. 17480 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 17481 * the delegate target according to the pointer and the touch area of the delegate while touch 17482 * exploration enabled. 17483 * </p> 17484 * 17485 * @param event The motion event dispatch to the delegate target. 17486 * @return True if the event was handled, false otherwise. 17487 * 17488 * @see #onHoverEvent 17489 */ dispatchTouchExplorationHoverEvent(MotionEvent event)17490 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 17491 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 17492 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 17493 return false; 17494 } 17495 17496 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 17497 final int action = event.getActionMasked(); 17498 boolean pointInDelegateRegion = false; 17499 boolean handled = false; 17500 17501 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 17502 for (int i = 0; i < info.getRegionCount(); i++) { 17503 Region r = info.getRegionAt(i); 17504 if (r.contains((int) event.getX(), (int) event.getY())) { 17505 pointInDelegateRegion = true; 17506 } 17507 } 17508 17509 // Explore by touch should dispatch events to children under the pointer first if any 17510 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 17511 // hover events but receive accessibility focus, it should also not delegate to these 17512 // views when hovered. 17513 if (!oldHoveringTouchDelegate) { 17514 if ((action == MotionEvent.ACTION_HOVER_ENTER 17515 || action == MotionEvent.ACTION_HOVER_MOVE) 17516 && !pointInHoveredChild(event) 17517 && pointInDelegateRegion) { 17518 mHoveringTouchDelegate = true; 17519 } 17520 } else { 17521 if (action == MotionEvent.ACTION_HOVER_EXIT 17522 || (action == MotionEvent.ACTION_HOVER_MOVE 17523 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 17524 mHoveringTouchDelegate = false; 17525 } 17526 } 17527 switch (action) { 17528 case MotionEvent.ACTION_HOVER_MOVE: 17529 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 17530 // Inside bounds, dispatch as is. 17531 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 17532 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 17533 // Moving inbound, synthesize hover enter. 17534 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 17535 ? event : MotionEvent.obtainNoHistory(event); 17536 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 17537 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 17538 eventNoHistory.setAction(action); 17539 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 17540 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 17541 // Moving outbound, synthesize hover exit. 17542 final boolean hoverExitPending = event.isHoverExitPending(); 17543 event.setHoverExitPending(true); 17544 mTouchDelegate.onTouchExplorationHoverEvent(event); 17545 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 17546 ? event : MotionEvent.obtainNoHistory(event); 17547 eventNoHistory.setHoverExitPending(hoverExitPending); 17548 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 17549 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 17550 } // else: outside bounds, do nothing. 17551 break; 17552 case MotionEvent.ACTION_HOVER_ENTER: 17553 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 17554 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 17555 } 17556 break; 17557 case MotionEvent.ACTION_HOVER_EXIT: 17558 if (oldHoveringTouchDelegate) { 17559 mTouchDelegate.onTouchExplorationHoverEvent(event); 17560 } 17561 break; 17562 } 17563 return handled; 17564 } 17565 17566 /** 17567 * Implement this method to handle hover events. 17568 * <p> 17569 * This method is called whenever a pointer is hovering into, over, or out of the 17570 * bounds of a view and the view is not currently being touched. 17571 * Hover events are represented as pointer events with action 17572 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 17573 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 17574 * </p> 17575 * <ul> 17576 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 17577 * when the pointer enters the bounds of the view.</li> 17578 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 17579 * when the pointer has already entered the bounds of the view and has moved.</li> 17580 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 17581 * when the pointer has exited the bounds of the view or when the pointer is 17582 * about to go down due to a button click, tap, or similar user action that 17583 * causes the view to be touched.</li> 17584 * </ul> 17585 * <p> 17586 * The view should implement this method to return true to indicate that it is 17587 * handling the hover event, such as by changing its drawable state. 17588 * </p><p> 17589 * The default implementation calls {@link #setHovered} to update the hovered state 17590 * of the view when a hover enter or hover exit event is received, if the view 17591 * is enabled and is clickable. The default implementation also sends hover 17592 * accessibility events. 17593 * </p> 17594 * 17595 * @param event The motion event that describes the hover. 17596 * @return True if the view handled the hover event. 17597 * 17598 * @see #isHovered 17599 * @see #setHovered 17600 * @see #onHoverChanged 17601 */ onHoverEvent(MotionEvent event)17602 public boolean onHoverEvent(MotionEvent event) { 17603 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 17604 return true; 17605 } 17606 17607 // The root view may receive hover (or touch) events that are outside the bounds of 17608 // the window. This code ensures that we only send accessibility events for 17609 // hovers that are actually within the bounds of the root view. 17610 final int action = event.getActionMasked(); 17611 if (!mSendingHoverAccessibilityEvents) { 17612 if ((action == MotionEvent.ACTION_HOVER_ENTER 17613 || action == MotionEvent.ACTION_HOVER_MOVE) 17614 && !hasHoveredChild() 17615 && pointInView(event.getX(), event.getY())) { 17616 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 17617 mSendingHoverAccessibilityEvents = true; 17618 } 17619 } else { 17620 if (action == MotionEvent.ACTION_HOVER_EXIT 17621 || (action == MotionEvent.ACTION_HOVER_MOVE 17622 && !pointInView(event.getX(), event.getY()))) { 17623 mSendingHoverAccessibilityEvents = false; 17624 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 17625 } 17626 } 17627 17628 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 17629 && event.isFromSource(InputDevice.SOURCE_MOUSE) 17630 && isOnScrollbar(event.getX(), event.getY())) { 17631 awakenScrollBars(); 17632 } 17633 17634 // If we consider ourself hoverable, or if we we're already hovered, 17635 // handle changing state in response to ENTER and EXIT events. 17636 if (isHoverable() || isHovered()) { 17637 switch (action) { 17638 case MotionEvent.ACTION_HOVER_ENTER: 17639 setHovered(true); 17640 break; 17641 case MotionEvent.ACTION_HOVER_EXIT: 17642 setHovered(false); 17643 break; 17644 } 17645 17646 // Dispatch the event to onGenericMotionEvent before returning true. 17647 // This is to provide compatibility with existing applications that 17648 // handled HOVER_MOVE events in onGenericMotionEvent and that would 17649 // break because of the new default handling for hoverable views 17650 // in onHoverEvent. 17651 // Note that onGenericMotionEvent will be called by default when 17652 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 17653 dispatchGenericMotionEventInternal(event); 17654 // The event was already handled by calling setHovered(), so always 17655 // return true. 17656 return true; 17657 } 17658 17659 return false; 17660 } 17661 17662 /** 17663 * Returns true if the view should handle {@link #onHoverEvent} 17664 * by calling {@link #setHovered} to change its hovered state. 17665 * 17666 * @return True if the view is hoverable. 17667 */ isHoverable()17668 private boolean isHoverable() { 17669 final int viewFlags = mViewFlags; 17670 if ((viewFlags & ENABLED_MASK) == DISABLED) { 17671 return false; 17672 } 17673 17674 return (viewFlags & CLICKABLE) == CLICKABLE 17675 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 17676 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 17677 } 17678 17679 /** 17680 * Returns true if the view is currently hovered. 17681 * 17682 * @return True if the view is currently hovered. 17683 * 17684 * @see #setHovered 17685 * @see #onHoverChanged 17686 */ 17687 @ViewDebug.ExportedProperty isHovered()17688 public boolean isHovered() { 17689 return (mPrivateFlags & PFLAG_HOVERED) != 0; 17690 } 17691 17692 /** 17693 * Sets whether the view is currently hovered. 17694 * <p> 17695 * Calling this method also changes the drawable state of the view. This 17696 * enables the view to react to hover by using different drawable resources 17697 * to change its appearance. 17698 * </p><p> 17699 * The {@link #onHoverChanged} method is called when the hovered state changes. 17700 * </p> 17701 * 17702 * @param hovered True if the view is hovered. 17703 * 17704 * @see #isHovered 17705 * @see #onHoverChanged 17706 */ setHovered(boolean hovered)17707 public void setHovered(boolean hovered) { 17708 if (hovered) { 17709 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 17710 mPrivateFlags |= PFLAG_HOVERED; 17711 refreshDrawableState(); 17712 onHoverChanged(true); 17713 } 17714 } else { 17715 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 17716 mPrivateFlags &= ~PFLAG_HOVERED; 17717 refreshDrawableState(); 17718 onHoverChanged(false); 17719 } 17720 } 17721 } 17722 17723 /** 17724 * Implement this method to handle hover state changes. 17725 * <p> 17726 * This method is called whenever the hover state changes as a result of a 17727 * call to {@link #setHovered}. 17728 * </p> 17729 * 17730 * @param hovered The current hover state, as returned by {@link #isHovered}. 17731 * 17732 * @see #isHovered 17733 * @see #setHovered 17734 */ onHoverChanged(boolean hovered)17735 public void onHoverChanged(boolean hovered) { 17736 } 17737 17738 /** 17739 * Handles scroll bar dragging by mouse input. 17740 * 17741 * @hide 17742 * @param event The motion event. 17743 * 17744 * @return true if the event was handled as a scroll bar dragging, false otherwise. 17745 */ handleScrollBarDragging(MotionEvent event)17746 protected boolean handleScrollBarDragging(MotionEvent event) { 17747 if (mScrollCache == null) { 17748 return false; 17749 } 17750 final float x = event.getX(); 17751 final float y = event.getY(); 17752 final int action = event.getAction(); 17753 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 17754 && action != MotionEvent.ACTION_DOWN) 17755 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 17756 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 17757 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 17758 return false; 17759 } 17760 17761 switch (action) { 17762 case MotionEvent.ACTION_MOVE: 17763 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 17764 return false; 17765 } 17766 if (mScrollCache.mScrollBarDraggingState 17767 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 17768 final Rect bounds = mScrollCache.mScrollBarBounds; 17769 getVerticalScrollBarBounds(bounds, null); 17770 final int range = computeVerticalScrollRange(); 17771 final int offset = computeVerticalScrollOffset(); 17772 final int extent = computeVerticalScrollExtent(); 17773 17774 final int thumbLength = ScrollBarUtils.getThumbLength( 17775 bounds.height(), bounds.width(), extent, range); 17776 final int thumbOffset = ScrollBarUtils.getThumbOffset( 17777 bounds.height(), thumbLength, extent, range, offset); 17778 17779 final float diff = y - mScrollCache.mScrollBarDraggingPos; 17780 final float maxThumbOffset = bounds.height() - thumbLength; 17781 final float newThumbOffset = 17782 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 17783 final int height = getHeight(); 17784 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 17785 && height > 0 && extent > 0) { 17786 final int newY = Math.round((range - extent) 17787 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 17788 if (newY != getScrollY()) { 17789 mScrollCache.mScrollBarDraggingPos = y; 17790 setScrollY(newY); 17791 } 17792 } 17793 return true; 17794 } 17795 if (mScrollCache.mScrollBarDraggingState 17796 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 17797 final Rect bounds = mScrollCache.mScrollBarBounds; 17798 getHorizontalScrollBarBounds(bounds, null); 17799 final int range = computeHorizontalScrollRange(); 17800 final int offset = computeHorizontalScrollOffset(); 17801 final int extent = computeHorizontalScrollExtent(); 17802 17803 final int thumbLength = ScrollBarUtils.getThumbLength( 17804 bounds.width(), bounds.height(), extent, range); 17805 final int thumbOffset = ScrollBarUtils.getThumbOffset( 17806 bounds.width(), thumbLength, extent, range, offset); 17807 17808 final float diff = x - mScrollCache.mScrollBarDraggingPos; 17809 final float maxThumbOffset = bounds.width() - thumbLength; 17810 final float newThumbOffset = 17811 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 17812 final int width = getWidth(); 17813 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 17814 && width > 0 && extent > 0) { 17815 final int newX = Math.round((range - extent) 17816 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 17817 if (newX != getScrollX()) { 17818 mScrollCache.mScrollBarDraggingPos = x; 17819 setScrollX(newX); 17820 } 17821 } 17822 return true; 17823 } 17824 case MotionEvent.ACTION_DOWN: 17825 if (mScrollCache.state == ScrollabilityCache.OFF) { 17826 return false; 17827 } 17828 if (isOnVerticalScrollbarThumb(x, y)) { 17829 mScrollCache.mScrollBarDraggingState = 17830 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 17831 mScrollCache.mScrollBarDraggingPos = y; 17832 return true; 17833 } 17834 if (isOnHorizontalScrollbarThumb(x, y)) { 17835 mScrollCache.mScrollBarDraggingState = 17836 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 17837 mScrollCache.mScrollBarDraggingPos = x; 17838 return true; 17839 } 17840 } 17841 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 17842 return false; 17843 } 17844 17845 /** 17846 * Implement this method to handle touch screen motion events. 17847 * <p> 17848 * If this method is used to detect click actions, it is recommended that 17849 * the actions be performed by implementing and calling 17850 * {@link #performClick()}. This will ensure consistent system behavior, 17851 * including: 17852 * <ul> 17853 * <li>obeying click sound preferences 17854 * <li>dispatching OnClickListener calls 17855 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 17856 * accessibility features are enabled 17857 * </ul> 17858 * 17859 * @param event The motion event. 17860 * @return True if the event was handled, false otherwise. 17861 */ onTouchEvent(MotionEvent event)17862 public boolean onTouchEvent(MotionEvent event) { 17863 final float x = event.getX(); 17864 final float y = event.getY(); 17865 final int viewFlags = mViewFlags; 17866 final int action = event.getAction(); 17867 17868 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 17869 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 17870 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 17871 17872 if ((viewFlags & ENABLED_MASK) == DISABLED 17873 && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { 17874 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 17875 setPressed(false); 17876 } 17877 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 17878 // A disabled view that is clickable still consumes the touch 17879 // events, it just doesn't respond to them. 17880 return clickable; 17881 } 17882 if (mTouchDelegate != null) { 17883 if (mTouchDelegate.onTouchEvent(event)) { 17884 return true; 17885 } 17886 } 17887 17888 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 17889 switch (action) { 17890 case MotionEvent.ACTION_UP: 17891 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 17892 if ((viewFlags & TOOLTIP) == TOOLTIP) { 17893 handleTooltipUp(); 17894 } 17895 if (!clickable) { 17896 removeTapCallback(); 17897 removeLongPressCallback(); 17898 mInContextButtonPress = false; 17899 mHasPerformedLongPress = false; 17900 mIgnoreNextUpEvent = false; 17901 break; 17902 } 17903 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 17904 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 17905 // take focus if we don't have it already and we should in 17906 // touch mode. 17907 boolean focusTaken = false; 17908 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 17909 focusTaken = requestFocus(); 17910 } 17911 17912 if (prepressed) { 17913 // The button is being released before we actually 17914 // showed it as pressed. Make it show the pressed 17915 // state now (before scheduling the click) to ensure 17916 // the user sees it. 17917 setPressed(true, x, y); 17918 } 17919 17920 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 17921 // This is a tap, so remove the longpress check 17922 removeLongPressCallback(); 17923 17924 // Only perform take click actions if we were in the pressed state 17925 if (!focusTaken) { 17926 // Use a Runnable and post this rather than calling 17927 // performClick directly. This lets other visual state 17928 // of the view update before click actions start. 17929 if (mPerformClick == null) { 17930 mPerformClick = new PerformClick(); 17931 } 17932 if (!post(mPerformClick)) { 17933 performClickInternal(); 17934 } 17935 } 17936 } 17937 17938 if (mUnsetPressedState == null) { 17939 mUnsetPressedState = new UnsetPressedState(); 17940 } 17941 17942 if (prepressed) { 17943 postDelayed(mUnsetPressedState, 17944 ViewConfiguration.getPressedStateDuration()); 17945 } else if (!post(mUnsetPressedState)) { 17946 // If the post failed, unpress right now 17947 mUnsetPressedState.run(); 17948 } 17949 17950 removeTapCallback(); 17951 } 17952 mIgnoreNextUpEvent = false; 17953 break; 17954 17955 case MotionEvent.ACTION_DOWN: 17956 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 17957 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 17958 } 17959 mHasPerformedLongPress = false; 17960 17961 if (!clickable) { 17962 checkForLongClick( 17963 ViewConfiguration.getLongPressTimeout(), 17964 x, 17965 y, 17966 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 17967 break; 17968 } 17969 17970 if (performButtonActionOnTouchDown(event)) { 17971 break; 17972 } 17973 17974 // Walk up the hierarchy to determine if we're inside a scrolling container. 17975 boolean isInScrollingContainer = isInScrollingContainer(); 17976 17977 // For views inside a scrolling container, delay the pressed feedback for 17978 // a short period in case this is a scroll. 17979 if (isInScrollingContainer) { 17980 mPrivateFlags |= PFLAG_PREPRESSED; 17981 if (mPendingCheckForTap == null) { 17982 mPendingCheckForTap = new CheckForTap(); 17983 } 17984 mPendingCheckForTap.x = event.getX(); 17985 mPendingCheckForTap.y = event.getY(); 17986 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 17987 } else { 17988 // Not inside a scrolling container, so show the feedback right away 17989 setPressed(true, x, y); 17990 checkForLongClick( 17991 ViewConfiguration.getLongPressTimeout(), 17992 x, 17993 y, 17994 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 17995 } 17996 break; 17997 17998 case MotionEvent.ACTION_CANCEL: 17999 if (clickable) { 18000 setPressed(false); 18001 } 18002 removeTapCallback(); 18003 removeLongPressCallback(); 18004 mInContextButtonPress = false; 18005 mHasPerformedLongPress = false; 18006 mIgnoreNextUpEvent = false; 18007 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 18008 break; 18009 18010 case MotionEvent.ACTION_MOVE: 18011 if (clickable) { 18012 drawableHotspotChanged(x, y); 18013 } 18014 18015 final int motionClassification = event.getClassification(); 18016 final boolean ambiguousGesture = 18017 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 18018 int touchSlop = mTouchSlop; 18019 if (ambiguousGesture && hasPendingLongPressCallback()) { 18020 if (!pointInView(x, y, touchSlop)) { 18021 // The default action here is to cancel long press. But instead, we 18022 // just extend the timeout here, in case the classification 18023 // stays ambiguous. 18024 removeLongPressCallback(); 18025 long delay = (long) (ViewConfiguration.getLongPressTimeout() 18026 * mAmbiguousGestureMultiplier); 18027 // Subtract the time already spent 18028 delay -= event.getEventTime() - event.getDownTime(); 18029 checkForLongClick( 18030 delay, 18031 x, 18032 y, 18033 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 18034 } 18035 touchSlop *= mAmbiguousGestureMultiplier; 18036 } 18037 18038 // Be lenient about moving outside of buttons 18039 if (!pointInView(x, y, touchSlop)) { 18040 // Outside button 18041 // Remove any future long press/tap checks 18042 removeTapCallback(); 18043 removeLongPressCallback(); 18044 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 18045 setPressed(false); 18046 } 18047 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 18048 } 18049 18050 final boolean deepPress = 18051 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 18052 if (deepPress && hasPendingLongPressCallback()) { 18053 // process the long click action immediately 18054 removeLongPressCallback(); 18055 checkForLongClick( 18056 0 /* send immediately */, 18057 x, 18058 y, 18059 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 18060 } 18061 18062 break; 18063 } 18064 18065 return true; 18066 } 18067 18068 return false; 18069 } 18070 18071 /** 18072 * Called by {@link #measure(int, int)} to check if the current frame presentation got 18073 * delayed by an expensive view mesures during the input event dispatching. (e.g. scrolling) 18074 */ hasExpensiveMeasuresDuringInputEvent()18075 private boolean hasExpensiveMeasuresDuringInputEvent() { 18076 final AttachInfo attachInfo = mAttachInfo; 18077 if (attachInfo == null || attachInfo.mRootView == null) { 18078 return false; 18079 } 18080 if (!attachInfo.mHandlingPointerEvent) { 18081 return false; 18082 } 18083 final ViewFrameInfo info = attachInfo.mViewRootImpl.mViewFrameInfo; 18084 final long durationFromVsyncTimeMs = (System.nanoTime() 18085 - Choreographer.getInstance().getLastFrameTimeNanos()) / TimeUtils.NANOS_PER_MS; 18086 return durationFromVsyncTimeMs > 3L || info.getAndIncreaseViewMeasuredCount() > 10; 18087 } 18088 18089 /** 18090 * @hide 18091 */ 18092 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isInScrollingContainer()18093 public boolean isInScrollingContainer() { 18094 ViewParent p = getParent(); 18095 while (p != null && p instanceof ViewGroup) { 18096 if (((ViewGroup) p).shouldDelayChildPressedState()) { 18097 return true; 18098 } 18099 p = p.getParent(); 18100 } 18101 return false; 18102 } 18103 18104 /** 18105 * Remove the longpress detection timer. 18106 */ removeLongPressCallback()18107 private void removeLongPressCallback() { 18108 if (mPendingCheckForLongPress != null) { 18109 removeCallbacks(mPendingCheckForLongPress); 18110 } 18111 } 18112 18113 /** 18114 * Return true if the long press callback is scheduled to run sometime in the future. 18115 * Return false if there is no scheduled long press callback at the moment. 18116 */ hasPendingLongPressCallback()18117 private boolean hasPendingLongPressCallback() { 18118 if (mPendingCheckForLongPress == null) { 18119 return false; 18120 } 18121 final AttachInfo attachInfo = mAttachInfo; 18122 if (attachInfo == null) { 18123 return false; 18124 } 18125 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 18126 } 18127 18128 /** 18129 * Remove the pending click action 18130 */ 18131 @UnsupportedAppUsage removePerformClickCallback()18132 private void removePerformClickCallback() { 18133 if (mPerformClick != null) { 18134 removeCallbacks(mPerformClick); 18135 } 18136 } 18137 18138 /** 18139 * Remove the prepress detection timer. 18140 */ removeUnsetPressCallback()18141 private void removeUnsetPressCallback() { 18142 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 18143 setPressed(false); 18144 removeCallbacks(mUnsetPressedState); 18145 } 18146 } 18147 18148 /** 18149 * Remove the tap detection timer. 18150 */ removeTapCallback()18151 private void removeTapCallback() { 18152 if (mPendingCheckForTap != null) { 18153 mPrivateFlags &= ~PFLAG_PREPRESSED; 18154 removeCallbacks(mPendingCheckForTap); 18155 } 18156 } 18157 18158 /** 18159 * Cancels a pending long press. Your subclass can use this if you 18160 * want the context menu to come up if the user presses and holds 18161 * at the same place, but you don't want it to come up if they press 18162 * and then move around enough to cause scrolling. 18163 */ cancelLongPress()18164 public void cancelLongPress() { 18165 removeLongPressCallback(); 18166 18167 /* 18168 * The prepressed state handled by the tap callback is a display 18169 * construct, but the tap callback will post a long press callback 18170 * less its own timeout. Remove it here. 18171 */ 18172 removeTapCallback(); 18173 } 18174 18175 /** 18176 * Sets the TouchDelegate for this View. 18177 */ setTouchDelegate(TouchDelegate delegate)18178 public void setTouchDelegate(TouchDelegate delegate) { 18179 mTouchDelegate = delegate; 18180 } 18181 18182 /** 18183 * Gets the TouchDelegate for this View. 18184 */ getTouchDelegate()18185 public TouchDelegate getTouchDelegate() { 18186 return mTouchDelegate; 18187 } 18188 18189 /** 18190 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 18191 * 18192 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 18193 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 18194 * available. This method should only be called for touch events. 18195 * 18196 * <p class="note">This API is not intended for most applications. Buffered dispatch 18197 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 18198 * streams will not improve your input latency. Side effects include: increased latency, 18199 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 18200 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 18201 * you.</p> 18202 * 18203 * To receive unbuffered events for arbitrary input device source classes, use 18204 * {@link #requestUnbufferedDispatch(int)}, 18205 * 18206 * @see View#requestUnbufferedDispatch(int) 18207 */ requestUnbufferedDispatch(MotionEvent event)18208 public final void requestUnbufferedDispatch(MotionEvent event) { 18209 final int action = event.getAction(); 18210 if (mAttachInfo == null 18211 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 18212 || !event.isTouchEvent()) { 18213 return; 18214 } 18215 mAttachInfo.mUnbufferedDispatchRequested = true; 18216 } 18217 18218 /** 18219 * Request unbuffered dispatch of the given event source class to this view. 18220 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 18221 * automatically terminate, and allows the specification of arbitrary input source classes. 18222 * 18223 * <p>Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, calling this method 18224 * will not result in any behavioral changes when this View is not attached to a window. 18225 * 18226 * @param source The combined input source class to request unbuffered dispatch for. All 18227 * events coming from these source classes will not be buffered. Set to 18228 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 18229 * 18230 * @see View#requestUnbufferedDispatch(MotionEvent) 18231 */ requestUnbufferedDispatch(@nputSourceClass int source)18232 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 18233 if (mUnbufferedInputSource == source) { 18234 return; 18235 } 18236 mUnbufferedInputSource = source; 18237 if (mParent != null) { 18238 mParent.onDescendantUnbufferedRequested(); 18239 } 18240 } 18241 hasSize()18242 private boolean hasSize() { 18243 return (mBottom > mTop) && (mRight > mLeft); 18244 } 18245 canTakeFocus()18246 private boolean canTakeFocus() { 18247 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 18248 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 18249 && ((mViewFlags & ENABLED_MASK) == ENABLED) 18250 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 18251 } 18252 18253 /** 18254 * Set flags controlling behavior of this view. 18255 * 18256 * @param flags Constant indicating the value which should be set 18257 * @param mask Constant indicating the bit range that should be changed 18258 */ 18259 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)18260 void setFlags(int flags, int mask) { 18261 final boolean accessibilityEnabled = 18262 AccessibilityManager.getInstance(mContext).isEnabled(); 18263 final boolean oldIncludeForAccessibility = 18264 accessibilityEnabled && includeForAccessibility(false); 18265 18266 int old = mViewFlags; 18267 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 18268 18269 int changed = mViewFlags ^ old; 18270 if (changed == 0) { 18271 return; 18272 } 18273 int privateFlags = mPrivateFlags; 18274 boolean shouldNotifyFocusableAvailable = false; 18275 18276 // If focusable is auto, update the FOCUSABLE bit. 18277 int focusableChangedByAuto = 0; 18278 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 18279 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 18280 // Heuristic only takes into account whether view is clickable. 18281 final int newFocus; 18282 if ((mViewFlags & CLICKABLE) != 0) { 18283 newFocus = FOCUSABLE; 18284 } else { 18285 newFocus = NOT_FOCUSABLE; 18286 } 18287 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 18288 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 18289 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 18290 } 18291 18292 /* Check if the FOCUSABLE bit has changed */ 18293 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 18294 if (((old & FOCUSABLE) == FOCUSABLE) 18295 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 18296 /* Give up focus if we are no longer focusable */ 18297 clearFocus(); 18298 if (mParent instanceof ViewGroup) { 18299 ((ViewGroup) mParent).clearFocusedInCluster(); 18300 } 18301 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 18302 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 18303 /* 18304 * Tell the view system that we are now available to take focus 18305 * if no one else already has it. 18306 */ 18307 if (mParent != null) { 18308 ViewRootImpl viewRootImpl = getViewRootImpl(); 18309 if (!sAutoFocusableOffUIThreadWontNotifyParents 18310 || focusableChangedByAuto == 0 18311 || viewRootImpl == null 18312 || viewRootImpl.mThread == Thread.currentThread()) { 18313 shouldNotifyFocusableAvailable = canTakeFocus(); 18314 } 18315 } 18316 } 18317 } 18318 18319 final int newVisibility = flags & VISIBILITY_MASK; 18320 if (newVisibility == VISIBLE) { 18321 if ((changed & VISIBILITY_MASK) != 0) { 18322 /* 18323 * If this view is becoming visible, invalidate it in case it changed while 18324 * it was not visible. Marking it drawn ensures that the invalidation will 18325 * go through. 18326 */ 18327 mPrivateFlags |= PFLAG_DRAWN; 18328 invalidate(true); 18329 18330 needGlobalAttributesUpdate(true); 18331 18332 // a view becoming visible is worth notifying the parent about in case nothing has 18333 // focus. Even if this specific view isn't focusable, it may contain something that 18334 // is, so let the root view try to give this focus if nothing else does. 18335 shouldNotifyFocusableAvailable = hasSize(); 18336 } 18337 } 18338 18339 if ((changed & ENABLED_MASK) != 0) { 18340 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 18341 // a view becoming enabled should notify the parent as long as the view is also 18342 // visible and the parent wasn't already notified by becoming visible during this 18343 // setFlags invocation. 18344 shouldNotifyFocusableAvailable = canTakeFocus(); 18345 } else { 18346 if (isFocused()) clearFocus(); 18347 } 18348 } 18349 18350 if (shouldNotifyFocusableAvailable && mParent != null) { 18351 mParent.focusableViewAvailable(this); 18352 } 18353 18354 /* Check if the GONE bit has changed */ 18355 if ((changed & GONE) != 0) { 18356 needGlobalAttributesUpdate(false); 18357 requestLayout(); 18358 18359 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 18360 if (hasFocus()) { 18361 clearFocus(); 18362 if (mParent instanceof ViewGroup) { 18363 ((ViewGroup) mParent).clearFocusedInCluster(); 18364 } 18365 } 18366 clearAccessibilityFocus(); 18367 destroyDrawingCache(); 18368 if (mParent instanceof View) { 18369 // GONE views noop invalidation, so invalidate the parent 18370 ((View) mParent).invalidate(true); 18371 } 18372 // Mark the view drawn to ensure that it gets invalidated properly the next 18373 // time it is visible and gets invalidated 18374 mPrivateFlags |= PFLAG_DRAWN; 18375 } 18376 if (mAttachInfo != null) { 18377 mAttachInfo.mViewVisibilityChanged = true; 18378 } 18379 } 18380 18381 /* Check if the VISIBLE bit has changed */ 18382 if ((changed & INVISIBLE) != 0) { 18383 needGlobalAttributesUpdate(false); 18384 /* 18385 * If this view is becoming invisible, set the DRAWN flag so that 18386 * the next invalidate() will not be skipped. 18387 */ 18388 mPrivateFlags |= PFLAG_DRAWN; 18389 18390 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 18391 // root view becoming invisible shouldn't clear focus and accessibility focus 18392 if (getRootView() != this) { 18393 if (hasFocus()) { 18394 clearFocus(); 18395 if (mParent instanceof ViewGroup) { 18396 ((ViewGroup) mParent).clearFocusedInCluster(); 18397 } 18398 } 18399 clearAccessibilityFocus(); 18400 } 18401 } 18402 if (mAttachInfo != null) { 18403 mAttachInfo.mViewVisibilityChanged = true; 18404 } 18405 } 18406 18407 if ((changed & VISIBILITY_MASK) != 0) { 18408 // If the view is invisible, cleanup its display list to free up resources 18409 if (newVisibility != VISIBLE && mAttachInfo != null) { 18410 cleanupDraw(); 18411 } 18412 18413 if (mParent instanceof ViewGroup) { 18414 ViewGroup parent = (ViewGroup) mParent; 18415 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 18416 newVisibility); 18417 parent.invalidate(true); 18418 } else if (mParent != null) { 18419 mParent.invalidateChild(this, null); 18420 } 18421 18422 if (mAttachInfo != null) { 18423 dispatchVisibilityChanged(this, newVisibility); 18424 18425 // Aggregated visibility changes are dispatched to attached views 18426 // in visible windows where the parent is currently shown/drawn 18427 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 18428 // discounting clipping or overlapping. This makes it a good place 18429 // to change animation states. 18430 if (mParent != null && getWindowVisibility() == VISIBLE && 18431 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 18432 dispatchVisibilityAggregated(newVisibility == VISIBLE); 18433 } 18434 // If this view is invisible from visible, then sending the A11y event by its 18435 // parent which is shown and has the accessibility important. 18436 if ((old & VISIBILITY_MASK) == VISIBLE) { 18437 notifySubtreeAccessibilityStateChangedByParentIfNeeded(); 18438 } else { 18439 notifySubtreeAccessibilityStateChangedIfNeeded(); 18440 } 18441 } 18442 } 18443 18444 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 18445 destroyDrawingCache(); 18446 } 18447 18448 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 18449 destroyDrawingCache(); 18450 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18451 invalidateParentCaches(); 18452 } 18453 18454 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 18455 destroyDrawingCache(); 18456 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18457 } 18458 18459 if ((changed & DRAW_MASK) != 0) { 18460 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 18461 if (mBackground != null 18462 || mDefaultFocusHighlight != null 18463 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 18464 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18465 } else { 18466 mPrivateFlags |= PFLAG_SKIP_DRAW; 18467 } 18468 } else { 18469 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18470 } 18471 requestLayout(); 18472 invalidate(true); 18473 } 18474 18475 if ((changed & KEEP_SCREEN_ON) != 0) { 18476 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 18477 mParent.recomputeViewAttributes(this); 18478 } 18479 } 18480 18481 if (accessibilityEnabled) { 18482 // If we're an accessibility pane and the visibility changed, we already have sent 18483 // a state change, so we really don't need to report other changes. 18484 if (isAccessibilityPane()) { 18485 changed &= ~VISIBILITY_MASK; 18486 } 18487 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 18488 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 18489 || (changed & CONTEXT_CLICKABLE) != 0) { 18490 if (oldIncludeForAccessibility != includeForAccessibility(false)) { 18491 notifySubtreeAccessibilityStateChangedIfNeeded(); 18492 } else { 18493 notifyViewAccessibilityStateChangedIfNeeded( 18494 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 18495 } 18496 } else if ((changed & ENABLED_MASK) != 0) { 18497 notifyViewAccessibilityStateChangedIfNeeded( 18498 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 18499 } 18500 } 18501 } 18502 18503 /** 18504 * Change the view's z order in the tree, so it's on top of other sibling 18505 * views. This ordering change may affect layout, if the parent container 18506 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 18507 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 18508 * method should be followed by calls to {@link #requestLayout()} and 18509 * {@link View#invalidate()} on the view's parent to force the parent to redraw 18510 * with the new child ordering. 18511 * 18512 * @see ViewGroup#bringChildToFront(View) 18513 */ bringToFront()18514 public void bringToFront() { 18515 if (mParent != null) { 18516 mParent.bringChildToFront(this); 18517 } 18518 } 18519 getScrollFeedbackProvider()18520 private HapticScrollFeedbackProvider getScrollFeedbackProvider() { 18521 if (mScrollFeedbackProvider == null) { 18522 mScrollFeedbackProvider = new HapticScrollFeedbackProvider(this, 18523 ViewConfiguration.get(mContext), /* disabledIfViewPlaysScrollHaptics= */ false); 18524 } 18525 return mScrollFeedbackProvider; 18526 } 18527 doRotaryProgressForScrollHaptics(MotionEvent rotaryEvent)18528 private void doRotaryProgressForScrollHaptics(MotionEvent rotaryEvent) { 18529 final float axisScrollValue = rotaryEvent.getAxisValue(MotionEvent.AXIS_SCROLL); 18530 final float verticalScrollFactor = 18531 ViewConfiguration.get(mContext).getScaledVerticalScrollFactor(); 18532 final int scrollAmount = -Math.round(axisScrollValue * verticalScrollFactor); 18533 getScrollFeedbackProvider().onScrollProgress( 18534 rotaryEvent.getDeviceId(), InputDevice.SOURCE_ROTARY_ENCODER, 18535 MotionEvent.AXIS_SCROLL, scrollAmount); 18536 } 18537 doRotaryLimitForScrollHaptics(MotionEvent rotaryEvent)18538 private void doRotaryLimitForScrollHaptics(MotionEvent rotaryEvent) { 18539 final boolean isStart = rotaryEvent.getAxisValue(MotionEvent.AXIS_SCROLL) > 0; 18540 getScrollFeedbackProvider().onScrollLimit( 18541 rotaryEvent.getDeviceId(), InputDevice.SOURCE_ROTARY_ENCODER, 18542 MotionEvent.AXIS_SCROLL, isStart); 18543 } 18544 processScrollEventForRotaryEncoderHaptics()18545 private void processScrollEventForRotaryEncoderHaptics() { 18546 if ((mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT) != 0) { 18547 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT; 18548 mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT; 18549 } 18550 } 18551 18552 /** 18553 * This is called in response to an internal scroll in this view (i.e., the 18554 * view scrolled its own contents). This is typically as a result of 18555 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 18556 * called. 18557 * 18558 * @param l Current horizontal scroll origin. 18559 * @param t Current vertical scroll origin. 18560 * @param oldl Previous horizontal scroll origin. 18561 * @param oldt Previous vertical scroll origin. 18562 */ onScrollChanged(int l, int t, int oldl, int oldt)18563 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 18564 notifySubtreeAccessibilityStateChangedIfNeeded(); 18565 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 18566 18567 processScrollEventForRotaryEncoderHaptics(); 18568 18569 mBackgroundSizeChanged = true; 18570 mDefaultFocusHighlightSizeChanged = true; 18571 if (mForegroundInfo != null) { 18572 mForegroundInfo.mBoundsChanged = true; 18573 } 18574 18575 final AttachInfo ai = mAttachInfo; 18576 if (ai != null) { 18577 ai.mViewScrollChanged = true; 18578 } 18579 18580 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 18581 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 18582 } 18583 } 18584 18585 /** 18586 * Interface definition for a callback to be invoked when the scroll 18587 * X or Y positions of a view change. 18588 * <p> 18589 * <b>Note:</b> Some views handle scrolling independently from View and may 18590 * have their own separate listeners for scroll-type events. For example, 18591 * {@link android.widget.ListView ListView} allows clients to register an 18592 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 18593 * to listen for changes in list scroll position. 18594 * 18595 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 18596 */ 18597 public interface OnScrollChangeListener { 18598 /** 18599 * Called when the scroll position of a view changes. 18600 * 18601 * @param v The view whose scroll position has changed. 18602 * @param scrollX Current horizontal scroll origin. 18603 * @param scrollY Current vertical scroll origin. 18604 * @param oldScrollX Previous horizontal scroll origin. 18605 * @param oldScrollY Previous vertical scroll origin. 18606 */ 18607 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 18608 } 18609 18610 /** 18611 * Interface definition for a callback to be invoked when the layout bounds of a view 18612 * changes due to layout processing. 18613 */ 18614 public interface OnLayoutChangeListener { 18615 /** 18616 * Called when the layout bounds of a view changes due to layout processing. 18617 * 18618 * @param v The view whose bounds have changed. 18619 * @param left The new value of the view's left property. 18620 * @param top The new value of the view's top property. 18621 * @param right The new value of the view's right property. 18622 * @param bottom The new value of the view's bottom property. 18623 * @param oldLeft The previous value of the view's left property. 18624 * @param oldTop The previous value of the view's top property. 18625 * @param oldRight The previous value of the view's right property. 18626 * @param oldBottom The previous value of the view's bottom property. 18627 */ 18628 void onLayoutChange(View v, int left, int top, int right, int bottom, 18629 int oldLeft, int oldTop, int oldRight, int oldBottom); 18630 } 18631 18632 /** 18633 * This is called during layout when the size of this view has changed. If 18634 * you were just added to the view hierarchy, you're called with the old 18635 * values of 0. 18636 * 18637 * @param w Current width of this view. 18638 * @param h Current height of this view. 18639 * @param oldw Old width of this view. 18640 * @param oldh Old height of this view. 18641 */ onSizeChanged(int w, int h, int oldw, int oldh)18642 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 18643 } 18644 18645 /** 18646 * Called by draw to draw the child views. This may be overridden 18647 * by derived classes to gain control just before its children are drawn 18648 * (but after its own view has been drawn). 18649 * @param canvas the canvas on which to draw the view 18650 */ dispatchDraw(@onNull Canvas canvas)18651 protected void dispatchDraw(@NonNull Canvas canvas) { 18652 18653 } 18654 18655 /** 18656 * Gets the parent of this view. Note that the parent is a 18657 * ViewParent and not necessarily a View. 18658 * 18659 * @return Parent of this view. 18660 */ getParent()18661 public final ViewParent getParent() { 18662 return mParent; 18663 } 18664 18665 /** 18666 * Set the horizontal scrolled position of your view. This will cause a call to 18667 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18668 * invalidated. 18669 * @param value the x position to scroll to 18670 */ setScrollX(int value)18671 public void setScrollX(int value) { 18672 scrollTo(value, mScrollY); 18673 } 18674 18675 /** 18676 * Set the vertical scrolled position of your view. This will cause a call to 18677 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18678 * invalidated. 18679 * @param value the y position to scroll to 18680 */ setScrollY(int value)18681 public void setScrollY(int value) { 18682 scrollTo(mScrollX, value); 18683 } 18684 18685 /** 18686 * Return the scrolled left position of this view. This is the left edge of 18687 * the displayed part of your view. You do not need to draw any pixels 18688 * farther left, since those are outside of the frame of your view on 18689 * screen. 18690 * 18691 * @return The left edge of the displayed part of your view, in pixels. 18692 */ 18693 @InspectableProperty getScrollX()18694 public final int getScrollX() { 18695 return mScrollX; 18696 } 18697 18698 /** 18699 * Return the scrolled top position of this view. This is the top edge of 18700 * the displayed part of your view. You do not need to draw any pixels above 18701 * it, since those are outside of the frame of your view on screen. 18702 * 18703 * @return The top edge of the displayed part of your view, in pixels. 18704 */ 18705 @InspectableProperty getScrollY()18706 public final int getScrollY() { 18707 return mScrollY; 18708 } 18709 18710 /** 18711 * Return the width of your view. 18712 * 18713 * @return The width of your view, in pixels. 18714 */ 18715 @ViewDebug.ExportedProperty(category = "layout") getWidth()18716 public final int getWidth() { 18717 return mRight - mLeft; 18718 } 18719 18720 /** 18721 * Return the height of your view. 18722 * 18723 * @return The height of your view, in pixels. 18724 */ 18725 @ViewDebug.ExportedProperty(category = "layout") getHeight()18726 public final int getHeight() { 18727 return mBottom - mTop; 18728 } 18729 18730 /** 18731 * Return the visible drawing bounds of your view. Fills in the output 18732 * rectangle with the values from getScrollX(), getScrollY(), 18733 * getWidth(), and getHeight(). These bounds do not account for any 18734 * transformation properties currently set on the view, such as 18735 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 18736 * 18737 * @param outRect The (scrolled) drawing bounds of the view. 18738 */ getDrawingRect(Rect outRect)18739 public void getDrawingRect(Rect outRect) { 18740 outRect.left = mScrollX; 18741 outRect.top = mScrollY; 18742 outRect.right = mScrollX + (mRight - mLeft); 18743 outRect.bottom = mScrollY + (mBottom - mTop); 18744 } 18745 18746 /** 18747 * Like {@link #getMeasuredWidthAndState()}, but only returns the 18748 * raw width component (that is the result is masked by 18749 * {@link #MEASURED_SIZE_MASK}). 18750 * 18751 * @return The raw measured width of this view. 18752 */ getMeasuredWidth()18753 public final int getMeasuredWidth() { 18754 return mMeasuredWidth & MEASURED_SIZE_MASK; 18755 } 18756 18757 /** 18758 * Return the full width measurement information for this view as computed 18759 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 18760 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 18761 * This should be used during measurement and layout calculations only. Use 18762 * {@link #getWidth()} to see how wide a view is after layout. 18763 * 18764 * @return The measured width of this view as a bit mask. 18765 */ 18766 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 18767 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 18768 name = "MEASURED_STATE_TOO_SMALL"), 18769 }) getMeasuredWidthAndState()18770 public final int getMeasuredWidthAndState() { 18771 return mMeasuredWidth; 18772 } 18773 18774 /** 18775 * Like {@link #getMeasuredHeightAndState()}, but only returns the 18776 * raw height component (that is the result is masked by 18777 * {@link #MEASURED_SIZE_MASK}). 18778 * 18779 * @return The raw measured height of this view. 18780 */ getMeasuredHeight()18781 public final int getMeasuredHeight() { 18782 return mMeasuredHeight & MEASURED_SIZE_MASK; 18783 } 18784 18785 /** 18786 * Return the full height measurement information for this view as computed 18787 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 18788 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 18789 * This should be used during measurement and layout calculations only. Use 18790 * {@link #getHeight()} to see how high a view is after layout. 18791 * 18792 * @return The measured height of this view as a bit mask. 18793 */ 18794 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 18795 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 18796 name = "MEASURED_STATE_TOO_SMALL"), 18797 }) getMeasuredHeightAndState()18798 public final int getMeasuredHeightAndState() { 18799 return mMeasuredHeight; 18800 } 18801 18802 /** 18803 * Return only the state bits of {@link #getMeasuredWidthAndState()} 18804 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 18805 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 18806 * and the height component is at the shifted bits 18807 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 18808 */ getMeasuredState()18809 public final int getMeasuredState() { 18810 return (mMeasuredWidth&MEASURED_STATE_MASK) 18811 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 18812 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 18813 } 18814 18815 /** 18816 * The transform matrix of this view, which is calculated based on the current 18817 * rotation, scale, and pivot properties. 18818 * 18819 * @see #getRotation() 18820 * @see #getScaleX() 18821 * @see #getScaleY() 18822 * @see #getPivotX() 18823 * @see #getPivotY() 18824 * @return The current transform matrix for the view 18825 */ getMatrix()18826 public Matrix getMatrix() { 18827 ensureTransformationInfo(); 18828 final Matrix matrix = mTransformationInfo.mMatrix; 18829 mRenderNode.getMatrix(matrix); 18830 return matrix; 18831 } 18832 18833 /** 18834 * Returns true if the transform matrix is the identity matrix. 18835 * Recomputes the matrix if necessary. 18836 * 18837 * @return True if the transform matrix is the identity matrix, false otherwise. 18838 * @hide 18839 */ 18840 @UnsupportedAppUsage hasIdentityMatrix()18841 public final boolean hasIdentityMatrix() { 18842 return mRenderNode.hasIdentityMatrix(); 18843 } 18844 18845 @UnsupportedAppUsage ensureTransformationInfo()18846 void ensureTransformationInfo() { 18847 if (mTransformationInfo == null) { 18848 mTransformationInfo = new TransformationInfo(); 18849 } 18850 } 18851 18852 /** 18853 * Utility method to retrieve the inverse of the current mMatrix property. 18854 * We cache the matrix to avoid recalculating it when transform properties 18855 * have not changed. 18856 * 18857 * @return The inverse of the current matrix of this view. 18858 * @hide 18859 */ 18860 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getInverseMatrix()18861 public final Matrix getInverseMatrix() { 18862 ensureTransformationInfo(); 18863 if (mTransformationInfo.mInverseMatrix == null) { 18864 mTransformationInfo.mInverseMatrix = new Matrix(); 18865 } 18866 final Matrix matrix = mTransformationInfo.mInverseMatrix; 18867 mRenderNode.getInverseMatrix(matrix); 18868 return matrix; 18869 } 18870 18871 /** 18872 * Gets the distance along the Z axis from the camera to this view. 18873 * 18874 * @see #setCameraDistance(float) 18875 * 18876 * @return The distance along the Z axis. 18877 */ getCameraDistance()18878 public float getCameraDistance() { 18879 final float dpi = mResources.getDisplayMetrics().densityDpi; 18880 return mRenderNode.getCameraDistance() * dpi; 18881 } 18882 18883 /** 18884 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 18885 * views are drawn) from the camera to this view. The camera's distance 18886 * affects 3D transformations, for instance rotations around the X and Y 18887 * axis. If the rotationX or rotationY properties are changed and this view is 18888 * large (more than half the size of the screen), it is recommended to always 18889 * use a camera distance that's greater than the height (X axis rotation) or 18890 * the width (Y axis rotation) of this view.</p> 18891 * 18892 * <p>The distance of the camera from the view plane can have an affect on the 18893 * perspective distortion of the view when it is rotated around the x or y axis. 18894 * For example, a large distance will result in a large viewing angle, and there 18895 * will not be much perspective distortion of the view as it rotates. A short 18896 * distance may cause much more perspective distortion upon rotation, and can 18897 * also result in some drawing artifacts if the rotated view ends up partially 18898 * behind the camera (which is why the recommendation is to use a distance at 18899 * least as far as the size of the view, if the view is to be rotated.)</p> 18900 * 18901 * <p>The distance is expressed in "depth pixels." The default distance depends 18902 * on the screen density. For instance, on a medium density display, the 18903 * default distance is 1280. On a high density display, the default distance 18904 * is 1920.</p> 18905 * 18906 * <p>If you want to specify a distance that leads to visually consistent 18907 * results across various densities, use the following formula:</p> 18908 * <pre> 18909 * float scale = context.getResources().getDisplayMetrics().density; 18910 * view.setCameraDistance(distance * scale); 18911 * </pre> 18912 * 18913 * <p>The density scale factor of a high density display is 1.5, 18914 * and 1920 = 1280 * 1.5.</p> 18915 * 18916 * @param distance The distance in "depth pixels", if negative the opposite 18917 * value is used 18918 * 18919 * @see #setRotationX(float) 18920 * @see #setRotationY(float) 18921 */ setCameraDistance(float distance)18922 public void setCameraDistance(float distance) { 18923 final float dpi = mResources.getDisplayMetrics().densityDpi; 18924 18925 invalidateViewProperty(true, false); 18926 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 18927 invalidateViewProperty(false, false); 18928 18929 invalidateParentIfNeededAndWasQuickRejected(); 18930 } 18931 18932 /** 18933 * The degrees that the view is rotated around the pivot point. 18934 * 18935 * @see #setRotation(float) 18936 * @see #getPivotX() 18937 * @see #getPivotY() 18938 * 18939 * @return The degrees of rotation. 18940 */ 18941 @ViewDebug.ExportedProperty(category = "drawing") 18942 @InspectableProperty getRotation()18943 public float getRotation() { 18944 return mRenderNode.getRotationZ(); 18945 } 18946 18947 /** 18948 * Sets the degrees that the view is rotated around the pivot point. Increasing values 18949 * result in clockwise rotation. 18950 * 18951 * @param rotation The degrees of rotation. 18952 * 18953 * @see #getRotation() 18954 * @see #getPivotX() 18955 * @see #getPivotY() 18956 * @see #setRotationX(float) 18957 * @see #setRotationY(float) 18958 * 18959 * @attr ref android.R.styleable#View_rotation 18960 */ 18961 @RemotableViewMethod setRotation(float rotation)18962 public void setRotation(float rotation) { 18963 if (rotation != getRotation()) { 18964 // Double-invalidation is necessary to capture view's old and new areas 18965 invalidateViewProperty(true, false); 18966 mRenderNode.setRotationZ(rotation); 18967 invalidateViewProperty(false, true); 18968 18969 invalidateParentIfNeededAndWasQuickRejected(); 18970 notifySubtreeAccessibilityStateChangedIfNeeded(); 18971 } 18972 } 18973 18974 /** 18975 * The degrees that the view is rotated around the vertical axis through the pivot point. 18976 * 18977 * @see #getPivotX() 18978 * @see #getPivotY() 18979 * @see #setRotationY(float) 18980 * 18981 * @return The degrees of Y rotation. 18982 */ 18983 @ViewDebug.ExportedProperty(category = "drawing") 18984 @InspectableProperty getRotationY()18985 public float getRotationY() { 18986 return mRenderNode.getRotationY(); 18987 } 18988 18989 /** 18990 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 18991 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 18992 * down the y axis. 18993 * 18994 * When rotating large views, it is recommended to adjust the camera distance 18995 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 18996 * 18997 * @param rotationY The degrees of Y rotation. 18998 * 18999 * @see #getRotationY() 19000 * @see #getPivotX() 19001 * @see #getPivotY() 19002 * @see #setRotation(float) 19003 * @see #setRotationX(float) 19004 * @see #setCameraDistance(float) 19005 * 19006 * @attr ref android.R.styleable#View_rotationY 19007 */ 19008 @RemotableViewMethod setRotationY(float rotationY)19009 public void setRotationY(float rotationY) { 19010 if (rotationY != getRotationY()) { 19011 invalidateViewProperty(true, false); 19012 mRenderNode.setRotationY(rotationY); 19013 invalidateViewProperty(false, true); 19014 19015 invalidateParentIfNeededAndWasQuickRejected(); 19016 notifySubtreeAccessibilityStateChangedIfNeeded(); 19017 } 19018 } 19019 19020 /** 19021 * The degrees that the view is rotated around the horizontal axis through the pivot point. 19022 * 19023 * @see #getPivotX() 19024 * @see #getPivotY() 19025 * @see #setRotationX(float) 19026 * 19027 * @return The degrees of X rotation. 19028 */ 19029 @ViewDebug.ExportedProperty(category = "drawing") 19030 @InspectableProperty getRotationX()19031 public float getRotationX() { 19032 return mRenderNode.getRotationX(); 19033 } 19034 19035 /** 19036 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 19037 * Increasing values result in clockwise rotation from the viewpoint of looking down the 19038 * x axis. 19039 * 19040 * When rotating large views, it is recommended to adjust the camera distance 19041 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 19042 * 19043 * @param rotationX The degrees of X rotation. 19044 * 19045 * @see #getRotationX() 19046 * @see #getPivotX() 19047 * @see #getPivotY() 19048 * @see #setRotation(float) 19049 * @see #setRotationY(float) 19050 * @see #setCameraDistance(float) 19051 * 19052 * @attr ref android.R.styleable#View_rotationX 19053 */ 19054 @RemotableViewMethod setRotationX(float rotationX)19055 public void setRotationX(float rotationX) { 19056 if (rotationX != getRotationX()) { 19057 invalidateViewProperty(true, false); 19058 mRenderNode.setRotationX(rotationX); 19059 invalidateViewProperty(false, true); 19060 19061 invalidateParentIfNeededAndWasQuickRejected(); 19062 notifySubtreeAccessibilityStateChangedIfNeeded(); 19063 } 19064 } 19065 19066 /** 19067 * The amount that the view is scaled in x around the pivot point, as a proportion of 19068 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 19069 * 19070 * <p>By default, this is 1.0f. 19071 * 19072 * @see #getPivotX() 19073 * @see #getPivotY() 19074 * @return The scaling factor. 19075 */ 19076 @ViewDebug.ExportedProperty(category = "drawing") 19077 @InspectableProperty getScaleX()19078 public float getScaleX() { 19079 return mRenderNode.getScaleX(); 19080 } 19081 19082 /** 19083 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 19084 * the view's unscaled width. A value of 1 means that no scaling is applied. 19085 * 19086 * @param scaleX The scaling factor. 19087 * @see #getPivotX() 19088 * @see #getPivotY() 19089 * 19090 * @attr ref android.R.styleable#View_scaleX 19091 */ 19092 @RemotableViewMethod setScaleX(float scaleX)19093 public void setScaleX(float scaleX) { 19094 if (scaleX != getScaleX()) { 19095 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 19096 invalidateViewProperty(true, false); 19097 mRenderNode.setScaleX(scaleX); 19098 invalidateViewProperty(false, true); 19099 19100 invalidateParentIfNeededAndWasQuickRejected(); 19101 notifySubtreeAccessibilityStateChangedIfNeeded(); 19102 } 19103 } 19104 19105 /** 19106 * The amount that the view is scaled in y around the pivot point, as a proportion of 19107 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 19108 * 19109 * <p>By default, this is 1.0f. 19110 * 19111 * @see #getPivotX() 19112 * @see #getPivotY() 19113 * @return The scaling factor. 19114 */ 19115 @ViewDebug.ExportedProperty(category = "drawing") 19116 @InspectableProperty getScaleY()19117 public float getScaleY() { 19118 return mRenderNode.getScaleY(); 19119 } 19120 19121 /** 19122 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 19123 * the view's unscaled width. A value of 1 means that no scaling is applied. 19124 * 19125 * @param scaleY The scaling factor. 19126 * @see #getPivotX() 19127 * @see #getPivotY() 19128 * 19129 * @attr ref android.R.styleable#View_scaleY 19130 */ 19131 @RemotableViewMethod setScaleY(float scaleY)19132 public void setScaleY(float scaleY) { 19133 if (scaleY != getScaleY()) { 19134 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 19135 invalidateViewProperty(true, false); 19136 mRenderNode.setScaleY(scaleY); 19137 invalidateViewProperty(false, true); 19138 19139 invalidateParentIfNeededAndWasQuickRejected(); 19140 notifySubtreeAccessibilityStateChangedIfNeeded(); 19141 } 19142 } 19143 19144 /** 19145 * The x location of the point around which the view is {@link #setRotation(float) rotated} 19146 * and {@link #setScaleX(float) scaled}. 19147 * 19148 * @see #getRotation() 19149 * @see #getScaleX() 19150 * @see #getScaleY() 19151 * @see #getPivotY() 19152 * @return The x location of the pivot point. 19153 * 19154 * @attr ref android.R.styleable#View_transformPivotX 19155 */ 19156 @ViewDebug.ExportedProperty(category = "drawing") 19157 @InspectableProperty(name = "transformPivotX") getPivotX()19158 public float getPivotX() { 19159 return mRenderNode.getPivotX(); 19160 } 19161 19162 /** 19163 * Sets the x location of the point around which the view is 19164 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 19165 * By default, the pivot point is centered on the object. 19166 * Setting this property disables this behavior and causes the view to use only the 19167 * explicitly set pivotX and pivotY values. 19168 * 19169 * @param pivotX The x location of the pivot point. 19170 * @see #getRotation() 19171 * @see #getScaleX() 19172 * @see #getScaleY() 19173 * @see #getPivotY() 19174 * 19175 * @attr ref android.R.styleable#View_transformPivotX 19176 */ 19177 @RemotableViewMethod setPivotX(float pivotX)19178 public void setPivotX(float pivotX) { 19179 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 19180 invalidateViewProperty(true, false); 19181 mRenderNode.setPivotX(pivotX); 19182 invalidateViewProperty(false, true); 19183 19184 invalidateParentIfNeededAndWasQuickRejected(); 19185 } 19186 } 19187 19188 /** 19189 * The y location of the point around which the view is {@link #setRotation(float) rotated} 19190 * and {@link #setScaleY(float) scaled}. 19191 * 19192 * @see #getRotation() 19193 * @see #getScaleX() 19194 * @see #getScaleY() 19195 * @see #getPivotY() 19196 * @return The y location of the pivot point. 19197 * 19198 * @attr ref android.R.styleable#View_transformPivotY 19199 */ 19200 @ViewDebug.ExportedProperty(category = "drawing") 19201 @InspectableProperty(name = "transformPivotY") getPivotY()19202 public float getPivotY() { 19203 return mRenderNode.getPivotY(); 19204 } 19205 19206 /** 19207 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 19208 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 19209 * Setting this property disables this behavior and causes the view to use only the 19210 * explicitly set pivotX and pivotY values. 19211 * 19212 * @param pivotY The y location of the pivot point. 19213 * @see #getRotation() 19214 * @see #getScaleX() 19215 * @see #getScaleY() 19216 * @see #getPivotY() 19217 * 19218 * @attr ref android.R.styleable#View_transformPivotY 19219 */ 19220 @RemotableViewMethod setPivotY(float pivotY)19221 public void setPivotY(float pivotY) { 19222 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 19223 invalidateViewProperty(true, false); 19224 mRenderNode.setPivotY(pivotY); 19225 invalidateViewProperty(false, true); 19226 19227 invalidateParentIfNeededAndWasQuickRejected(); 19228 } 19229 } 19230 19231 /** 19232 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 19233 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 19234 * of the view. 19235 * 19236 * @return True if a pivot has been set, false if the default pivot is being used 19237 */ isPivotSet()19238 public boolean isPivotSet() { 19239 return mRenderNode.isPivotExplicitlySet(); 19240 } 19241 19242 /** 19243 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 19244 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 19245 * and the pivot used for rotation will return to default of being centered on the view. 19246 */ resetPivot()19247 public void resetPivot() { 19248 if (mRenderNode.resetPivot()) { 19249 invalidateViewProperty(false, false); 19250 } 19251 } 19252 19253 /** 19254 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 19255 * completely transparent and 1 means the view is completely opaque. 19256 * 19257 * <p>By default this is 1.0f. 19258 * @return The opacity of the view. 19259 */ 19260 @ViewDebug.ExportedProperty(category = "drawing") 19261 @InspectableProperty getAlpha()19262 public float getAlpha() { 19263 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 19264 } 19265 19266 /** 19267 * Sets the behavior for overlapping rendering for this view (see {@link 19268 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 19269 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 19270 * providing the value which is then used internally. That is, when {@link 19271 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 19272 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 19273 * instead. 19274 * 19275 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 19276 * instead of that returned by {@link #hasOverlappingRendering()}. 19277 * 19278 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 19279 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)19280 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 19281 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 19282 if (hasOverlappingRendering) { 19283 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 19284 } else { 19285 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 19286 } 19287 } 19288 19289 /** 19290 * Returns the value for overlapping rendering that is used internally. This is either 19291 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 19292 * the return value of {@link #hasOverlappingRendering()}, otherwise. 19293 * 19294 * @return The value for overlapping rendering being used internally. 19295 */ getHasOverlappingRendering()19296 public final boolean getHasOverlappingRendering() { 19297 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 19298 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 19299 hasOverlappingRendering(); 19300 } 19301 19302 /** 19303 * Returns whether this View has content which overlaps. 19304 * 19305 * <p>This function, intended to be overridden by specific View types, is an optimization when 19306 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 19307 * an offscreen buffer and then composited into place, which can be expensive. If the view has 19308 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 19309 * directly. An example of overlapping rendering is a TextView with a background image, such as 19310 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 19311 * ImageView with only the foreground image. The default implementation returns true; subclasses 19312 * should override if they have cases which can be optimized.</p> 19313 * 19314 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 19315 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 19316 * 19317 * @return true if the content in this view might overlap, false otherwise. 19318 */ 19319 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()19320 public boolean hasOverlappingRendering() { 19321 return true; 19322 } 19323 19324 /** 19325 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 19326 * completely transparent and 1 means the view is completely opaque. 19327 * 19328 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 19329 * can have significant performance implications, especially for large views. It is best to use 19330 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 19331 * 19332 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 19333 * strongly recommended for performance reasons to either override 19334 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 19335 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 19336 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 19337 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 19338 * of rendering cost, even for simple or small views. Starting with 19339 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 19340 * applied to the view at the rendering level.</p> 19341 * 19342 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 19343 * responsible for applying the opacity itself.</p> 19344 * 19345 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 19346 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 19347 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 19348 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 19349 * 19350 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 19351 * value will clip a View to its bounds, unless the View returns <code>false</code> from 19352 * {@link #hasOverlappingRendering}.</p> 19353 * 19354 * @param alpha The opacity of the view. 19355 * 19356 * @see #hasOverlappingRendering() 19357 * @see #setLayerType(int, android.graphics.Paint) 19358 * 19359 * @attr ref android.R.styleable#View_alpha 19360 */ 19361 @RemotableViewMethod setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)19362 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 19363 ensureTransformationInfo(); 19364 if (mTransformationInfo.mAlpha != alpha) { 19365 setAlphaInternal(alpha); 19366 if (onSetAlpha((int) (alpha * 255))) { 19367 mPrivateFlags |= PFLAG_ALPHA_SET; 19368 // subclass is handling alpha - don't optimize rendering cache invalidation 19369 invalidateParentCaches(); 19370 invalidate(true); 19371 } else { 19372 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19373 invalidateViewProperty(true, false); 19374 mRenderNode.setAlpha(getFinalAlpha()); 19375 } 19376 } 19377 } 19378 19379 /** 19380 * Faster version of setAlpha() which performs the same steps except there are 19381 * no calls to invalidate(). The caller of this function should perform proper invalidation 19382 * on the parent and this object. The return value indicates whether the subclass handles 19383 * alpha (the return value for onSetAlpha()). 19384 * 19385 * @param alpha The new value for the alpha property 19386 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 19387 * the new value for the alpha property is different from the old value 19388 */ 19389 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)19390 boolean setAlphaNoInvalidation(float alpha) { 19391 ensureTransformationInfo(); 19392 if (mTransformationInfo.mAlpha != alpha) { 19393 setAlphaInternal(alpha); 19394 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 19395 if (subclassHandlesAlpha) { 19396 mPrivateFlags |= PFLAG_ALPHA_SET; 19397 return true; 19398 } else { 19399 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19400 mRenderNode.setAlpha(getFinalAlpha()); 19401 } 19402 } 19403 return false; 19404 } 19405 setAlphaInternal(float alpha)19406 void setAlphaInternal(float alpha) { 19407 float oldAlpha = mTransformationInfo.mAlpha; 19408 mTransformationInfo.mAlpha = alpha; 19409 // Report visibility changes, which can affect children, to accessibility 19410 if ((alpha == 0) ^ (oldAlpha == 0)) { 19411 notifySubtreeAccessibilityStateChangedIfNeeded(); 19412 } 19413 } 19414 19415 /** 19416 * This property is intended only for use by the Fade transition, which animates it 19417 * to produce a visual translucency that does not side-effect (or get affected by) 19418 * the real alpha property. This value is composited with the other alpha value 19419 * (and the AlphaAnimation value, when that is present) to produce a final visual 19420 * translucency result, which is what is passed into the DisplayList. 19421 */ setTransitionAlpha(float alpha)19422 public void setTransitionAlpha(float alpha) { 19423 ensureTransformationInfo(); 19424 if (mTransformationInfo.mTransitionAlpha != alpha) { 19425 mTransformationInfo.mTransitionAlpha = alpha; 19426 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19427 invalidateViewProperty(true, false); 19428 mRenderNode.setAlpha(getFinalAlpha()); 19429 } 19430 } 19431 19432 /** 19433 * Calculates the visual alpha of this view, which is a combination of the actual 19434 * alpha value and the transitionAlpha value (if set). 19435 */ getFinalAlpha()19436 private float getFinalAlpha() { 19437 if (mTransformationInfo != null) { 19438 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 19439 } 19440 return 1; 19441 } 19442 19443 /** 19444 * This property is intended only for use by the Fade transition, which animates 19445 * it to produce a visual translucency that does not side-effect (or get affected 19446 * by) the real alpha property. This value is composited with the other alpha 19447 * value (and the AlphaAnimation value, when that is present) to produce a final 19448 * visual translucency result, which is what is passed into the DisplayList. 19449 */ 19450 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()19451 public float getTransitionAlpha() { 19452 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 19453 } 19454 19455 /** 19456 * Sets whether or not to allow force dark to apply to this view. 19457 * 19458 * Setting this to false will disable the auto-dark feature on everything this view 19459 * draws, including any descendants. 19460 * 19461 * Setting this to true will allow this view to be automatically made dark, however 19462 * a value of 'true' will not override any 'false' value in its parent chain nor will 19463 * it prevent any 'false' in any of its children. 19464 * 19465 * The default behavior of force dark is also influenced by the Theme's 19466 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 19467 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 19468 * 19469 * @param allow Whether or not to allow force dark. 19470 */ setForceDarkAllowed(boolean allow)19471 public void setForceDarkAllowed(boolean allow) { 19472 if (mRenderNode.setForceDarkAllowed(allow)) { 19473 // Currently toggling force-dark requires a new display list push to apply 19474 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 19475 invalidate(); 19476 } 19477 } 19478 19479 /** 19480 * See {@link #setForceDarkAllowed(boolean)} 19481 * 19482 * @return true if force dark is allowed (default), false if it is disabled 19483 */ 19484 @ViewDebug.ExportedProperty(category = "drawing") 19485 @InspectableProperty isForceDarkAllowed()19486 public boolean isForceDarkAllowed() { 19487 return mRenderNode.isForceDarkAllowed(); 19488 } 19489 19490 /** 19491 * Top position of this view relative to its parent. 19492 * 19493 * @return The top of this view, in pixels. 19494 */ 19495 @ViewDebug.CapturedViewProperty getTop()19496 public final int getTop() { 19497 return mTop; 19498 } 19499 19500 /** 19501 * Sets the top position of this view relative to its parent. This method is meant to be called 19502 * by the layout system and should not generally be called otherwise, because the property 19503 * may be changed at any time by the layout. 19504 * 19505 * @param top The top of this view, in pixels. 19506 */ setTop(int top)19507 public final void setTop(int top) { 19508 if (top != mTop) { 19509 final boolean matrixIsIdentity = hasIdentityMatrix(); 19510 if (matrixIsIdentity) { 19511 if (mAttachInfo != null) { 19512 int minTop; 19513 int yLoc; 19514 if (top < mTop) { 19515 minTop = top; 19516 yLoc = top - mTop; 19517 } else { 19518 minTop = mTop; 19519 yLoc = 0; 19520 } 19521 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 19522 } 19523 } else { 19524 // Double-invalidation is necessary to capture view's old and new areas 19525 invalidate(true); 19526 } 19527 19528 int width = mRight - mLeft; 19529 int oldHeight = mBottom - mTop; 19530 19531 mTop = top; 19532 mRenderNode.setTop(mTop); 19533 19534 sizeChange(width, mBottom - mTop, width, oldHeight); 19535 19536 if (!matrixIsIdentity) { 19537 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19538 invalidate(true); 19539 } 19540 mBackgroundSizeChanged = true; 19541 mDefaultFocusHighlightSizeChanged = true; 19542 if (mForegroundInfo != null) { 19543 mForegroundInfo.mBoundsChanged = true; 19544 } 19545 invalidateParentIfNeeded(); 19546 } 19547 } 19548 19549 /** 19550 * Bottom position of this view relative to its parent. 19551 * 19552 * @return The bottom of this view, in pixels. 19553 */ 19554 @ViewDebug.CapturedViewProperty getBottom()19555 public final int getBottom() { 19556 return mBottom; 19557 } 19558 19559 /** 19560 * True if this view has changed since the last time being drawn. 19561 * 19562 * @return The dirty state of this view. 19563 */ isDirty()19564 public boolean isDirty() { 19565 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 19566 } 19567 19568 /** 19569 * Sets the bottom position of this view relative to its parent. This method is meant to be 19570 * called by the layout system and should not generally be called otherwise, because the 19571 * property may be changed at any time by the layout. 19572 * 19573 * @param bottom The bottom of this view, in pixels. 19574 */ setBottom(int bottom)19575 public final void setBottom(int bottom) { 19576 if (bottom != mBottom) { 19577 final boolean matrixIsIdentity = hasIdentityMatrix(); 19578 if (matrixIsIdentity) { 19579 if (mAttachInfo != null) { 19580 int maxBottom; 19581 if (bottom < mBottom) { 19582 maxBottom = mBottom; 19583 } else { 19584 maxBottom = bottom; 19585 } 19586 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 19587 } 19588 } else { 19589 // Double-invalidation is necessary to capture view's old and new areas 19590 invalidate(true); 19591 } 19592 19593 int width = mRight - mLeft; 19594 int oldHeight = mBottom - mTop; 19595 19596 mBottom = bottom; 19597 mRenderNode.setBottom(mBottom); 19598 19599 sizeChange(width, mBottom - mTop, width, oldHeight); 19600 19601 if (!matrixIsIdentity) { 19602 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19603 invalidate(true); 19604 } 19605 mBackgroundSizeChanged = true; 19606 mDefaultFocusHighlightSizeChanged = true; 19607 if (mForegroundInfo != null) { 19608 mForegroundInfo.mBoundsChanged = true; 19609 } 19610 invalidateParentIfNeeded(); 19611 } 19612 } 19613 19614 /** 19615 * Left position of this view relative to its parent. 19616 * 19617 * @return The left edge of this view, in pixels. 19618 */ 19619 @ViewDebug.CapturedViewProperty getLeft()19620 public final int getLeft() { 19621 return mLeft; 19622 } 19623 19624 /** 19625 * Sets the left position of this view relative to its parent. This method is meant to be called 19626 * by the layout system and should not generally be called otherwise, because the property 19627 * may be changed at any time by the layout. 19628 * 19629 * @param left The left of this view, in pixels. 19630 */ setLeft(int left)19631 public final void setLeft(int left) { 19632 if (left != mLeft) { 19633 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 19634 final boolean matrixIsIdentity = hasIdentityMatrix(); 19635 if (matrixIsIdentity) { 19636 if (mAttachInfo != null) { 19637 int minLeft; 19638 int xLoc; 19639 if (left < mLeft) { 19640 minLeft = left; 19641 xLoc = left - mLeft; 19642 } else { 19643 minLeft = mLeft; 19644 xLoc = 0; 19645 } 19646 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 19647 } 19648 } else { 19649 // Double-invalidation is necessary to capture view's old and new areas 19650 invalidate(true); 19651 } 19652 19653 int oldWidth = mRight - mLeft; 19654 int height = mBottom - mTop; 19655 19656 mLeft = left; 19657 mRenderNode.setLeft(left); 19658 19659 sizeChange(mRight - mLeft, height, oldWidth, height); 19660 19661 if (!matrixIsIdentity) { 19662 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19663 invalidate(true); 19664 } 19665 mBackgroundSizeChanged = true; 19666 mDefaultFocusHighlightSizeChanged = true; 19667 if (mForegroundInfo != null) { 19668 mForegroundInfo.mBoundsChanged = true; 19669 } 19670 invalidateParentIfNeeded(); 19671 } 19672 } 19673 19674 /** 19675 * Right position of this view relative to its parent. 19676 * 19677 * @return The right edge of this view, in pixels. 19678 */ 19679 @ViewDebug.CapturedViewProperty getRight()19680 public final int getRight() { 19681 return mRight; 19682 } 19683 19684 /** 19685 * Sets the right position of this view relative to its parent. This method is meant to be called 19686 * by the layout system and should not generally be called otherwise, because the property 19687 * may be changed at any time by the layout. 19688 * 19689 * @param right The right of this view, in pixels. 19690 */ setRight(int right)19691 public final void setRight(int right) { 19692 if (right != mRight) { 19693 final boolean matrixIsIdentity = hasIdentityMatrix(); 19694 if (matrixIsIdentity) { 19695 if (mAttachInfo != null) { 19696 int maxRight; 19697 if (right < mRight) { 19698 maxRight = mRight; 19699 } else { 19700 maxRight = right; 19701 } 19702 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 19703 } 19704 } else { 19705 // Double-invalidation is necessary to capture view's old and new areas 19706 invalidate(true); 19707 } 19708 19709 int oldWidth = mRight - mLeft; 19710 int height = mBottom - mTop; 19711 19712 mRight = right; 19713 mRenderNode.setRight(mRight); 19714 19715 sizeChange(mRight - mLeft, height, oldWidth, height); 19716 19717 if (!matrixIsIdentity) { 19718 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19719 invalidate(true); 19720 } 19721 mBackgroundSizeChanged = true; 19722 mDefaultFocusHighlightSizeChanged = true; 19723 if (mForegroundInfo != null) { 19724 mForegroundInfo.mBoundsChanged = true; 19725 } 19726 invalidateParentIfNeeded(); 19727 } 19728 } 19729 sanitizeFloatPropertyValue(float value, String propertyName)19730 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 19731 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 19732 } 19733 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)19734 private static float sanitizeFloatPropertyValue(float value, String propertyName, 19735 float min, float max) { 19736 // The expected "nothing bad happened" path 19737 if (value >= min && value <= max) return value; 19738 19739 if (value < min || value == Float.NEGATIVE_INFINITY) { 19740 if (sThrowOnInvalidFloatProperties) { 19741 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 19742 + value + ", the value must be >= " + min); 19743 } 19744 return min; 19745 } 19746 19747 if (value > max || value == Float.POSITIVE_INFINITY) { 19748 if (sThrowOnInvalidFloatProperties) { 19749 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 19750 + value + ", the value must be <= " + max); 19751 } 19752 return max; 19753 } 19754 19755 if (Float.isNaN(value)) { 19756 if (sThrowOnInvalidFloatProperties) { 19757 throw new IllegalArgumentException( 19758 "Cannot set '" + propertyName + "' to Float.NaN"); 19759 } 19760 return 0; // Unclear which direction this NaN went so... 0? 19761 } 19762 19763 // Shouldn't be possible to reach this. 19764 throw new IllegalStateException("How do you get here?? " + value); 19765 } 19766 19767 /** 19768 * The visual x position of this view, in pixels. This is equivalent to the 19769 * {@link #setTranslationX(float) translationX} property plus the current 19770 * {@link #getLeft() left} property. 19771 * 19772 * @return The visual x position of this view, in pixels. 19773 */ 19774 @ViewDebug.ExportedProperty(category = "drawing") getX()19775 public float getX() { 19776 return mLeft + getTranslationX(); 19777 } 19778 19779 /** 19780 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 19781 * {@link #setTranslationX(float) translationX} property to be the difference between 19782 * the x value passed in and the current {@link #getLeft() left} property. 19783 * 19784 * @param x The visual x position of this view, in pixels. 19785 */ setX(float x)19786 public void setX(float x) { 19787 setTranslationX(x - mLeft); 19788 } 19789 19790 /** 19791 * The visual y position of this view, in pixels. This is equivalent to the 19792 * {@link #setTranslationY(float) translationY} property plus the current 19793 * {@link #getTop() top} property. 19794 * 19795 * @return The visual y position of this view, in pixels. 19796 */ 19797 @ViewDebug.ExportedProperty(category = "drawing") getY()19798 public float getY() { 19799 return mTop + getTranslationY(); 19800 } 19801 19802 /** 19803 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 19804 * {@link #setTranslationY(float) translationY} property to be the difference between 19805 * the y value passed in and the current {@link #getTop() top} property. 19806 * 19807 * @param y The visual y position of this view, in pixels. 19808 */ setY(float y)19809 public void setY(float y) { 19810 setTranslationY(y - mTop); 19811 } 19812 19813 /** 19814 * The visual z position of this view, in pixels. This is equivalent to the 19815 * {@link #setTranslationZ(float) translationZ} property plus the current 19816 * {@link #getElevation() elevation} property. 19817 * 19818 * @return The visual z position of this view, in pixels. 19819 */ 19820 @ViewDebug.ExportedProperty(category = "drawing") getZ()19821 public float getZ() { 19822 return getElevation() + getTranslationZ(); 19823 } 19824 19825 /** 19826 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 19827 * {@link #setTranslationZ(float) translationZ} property to be the difference between 19828 * the z value passed in and the current {@link #getElevation() elevation} property. 19829 * 19830 * @param z The visual z position of this view, in pixels. 19831 */ setZ(float z)19832 public void setZ(float z) { 19833 setTranslationZ(z - getElevation()); 19834 } 19835 19836 /** 19837 * The base elevation of this view relative to its parent, in pixels. 19838 * 19839 * @return The base depth position of the view, in pixels. 19840 */ 19841 @ViewDebug.ExportedProperty(category = "drawing") 19842 @InspectableProperty getElevation()19843 public float getElevation() { 19844 return mRenderNode.getElevation(); 19845 } 19846 19847 /** 19848 * Sets the base elevation of this view, in pixels. 19849 * 19850 * @attr ref android.R.styleable#View_elevation 19851 */ 19852 @RemotableViewMethod setElevation(float elevation)19853 public void setElevation(float elevation) { 19854 if (elevation != getElevation()) { 19855 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 19856 invalidateViewProperty(true, false); 19857 mRenderNode.setElevation(elevation); 19858 invalidateViewProperty(false, true); 19859 19860 invalidateParentIfNeededAndWasQuickRejected(); 19861 } 19862 } 19863 19864 /** 19865 * The horizontal location of this view relative to its {@link #getLeft() left} position. 19866 * This position is post-layout, in addition to wherever the object's 19867 * layout placed it. 19868 * 19869 * @return The horizontal position of this view relative to its left position, in pixels. 19870 */ 19871 @ViewDebug.ExportedProperty(category = "drawing") 19872 @InspectableProperty getTranslationX()19873 public float getTranslationX() { 19874 return mRenderNode.getTranslationX(); 19875 } 19876 19877 /** 19878 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 19879 * This effectively positions the object post-layout, in addition to wherever the object's 19880 * layout placed it. 19881 * 19882 * @param translationX The horizontal position of this view relative to its left position, 19883 * in pixels. 19884 * 19885 * @attr ref android.R.styleable#View_translationX 19886 */ 19887 @RemotableViewMethod setTranslationX(float translationX)19888 public void setTranslationX(float translationX) { 19889 if (translationX != getTranslationX()) { 19890 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 19891 invalidateViewProperty(true, false); 19892 mRenderNode.setTranslationX(translationX); 19893 invalidateViewProperty(false, true); 19894 19895 invalidateParentIfNeededAndWasQuickRejected(); 19896 notifySubtreeAccessibilityStateChangedIfNeeded(); 19897 } 19898 } 19899 19900 /** 19901 * The vertical location of this view relative to its {@link #getTop() top} position. 19902 * This position is post-layout, in addition to wherever the object's 19903 * layout placed it. 19904 * 19905 * @return The vertical position of this view relative to its top position, 19906 * in pixels. 19907 */ 19908 @ViewDebug.ExportedProperty(category = "drawing") 19909 @InspectableProperty getTranslationY()19910 public float getTranslationY() { 19911 return mRenderNode.getTranslationY(); 19912 } 19913 19914 /** 19915 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 19916 * This effectively positions the object post-layout, in addition to wherever the object's 19917 * layout placed it. 19918 * 19919 * @param translationY The vertical position of this view relative to its top position, 19920 * in pixels. 19921 * 19922 * @attr ref android.R.styleable#View_translationY 19923 */ 19924 @RemotableViewMethod setTranslationY(float translationY)19925 public void setTranslationY(float translationY) { 19926 if (translationY != getTranslationY()) { 19927 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 19928 invalidateViewProperty(true, false); 19929 mRenderNode.setTranslationY(translationY); 19930 invalidateViewProperty(false, true); 19931 19932 invalidateParentIfNeededAndWasQuickRejected(); 19933 notifySubtreeAccessibilityStateChangedIfNeeded(); 19934 } 19935 } 19936 19937 /** 19938 * The depth location of this view relative to its {@link #getElevation() elevation}. 19939 * 19940 * @return The depth of this view relative to its elevation. 19941 */ 19942 @ViewDebug.ExportedProperty(category = "drawing") 19943 @InspectableProperty getTranslationZ()19944 public float getTranslationZ() { 19945 return mRenderNode.getTranslationZ(); 19946 } 19947 19948 /** 19949 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 19950 * 19951 * @attr ref android.R.styleable#View_translationZ 19952 */ 19953 @RemotableViewMethod setTranslationZ(float translationZ)19954 public void setTranslationZ(float translationZ) { 19955 if (translationZ != getTranslationZ()) { 19956 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 19957 invalidateViewProperty(true, false); 19958 mRenderNode.setTranslationZ(translationZ); 19959 invalidateViewProperty(false, true); 19960 19961 invalidateParentIfNeededAndWasQuickRejected(); 19962 } 19963 } 19964 19965 /** 19966 * Changes the transformation matrix on the view. This is used in animation frameworks, 19967 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 19968 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 19969 * Application developers should use transformation methods like {@link #setRotation(float)}, 19970 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 19971 * and {@link #setTranslationY(float)} (float)}} instead. 19972 * 19973 * @param matrix The matrix, null indicates that the matrix should be cleared. 19974 * @see #getAnimationMatrix() 19975 */ setAnimationMatrix(@ullable Matrix matrix)19976 public void setAnimationMatrix(@Nullable Matrix matrix) { 19977 invalidateViewProperty(true, false); 19978 mRenderNode.setAnimationMatrix(matrix); 19979 invalidateViewProperty(false, true); 19980 19981 invalidateParentIfNeededAndWasQuickRejected(); 19982 } 19983 19984 /** 19985 * Return the current transformation matrix of the view. This is used in animation frameworks, 19986 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 19987 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 19988 * Application developers should use transformation methods like {@link #setRotation(float)}, 19989 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 19990 * and {@link #setTranslationY(float)} (float)}} instead. 19991 * 19992 * @return the Matrix, null indicates there is no transformation 19993 * @see #setAnimationMatrix(Matrix) 19994 */ 19995 @Nullable getAnimationMatrix()19996 public Matrix getAnimationMatrix() { 19997 return mRenderNode.getAnimationMatrix(); 19998 } 19999 20000 /** 20001 * Returns the current StateListAnimator if exists. 20002 * 20003 * @return StateListAnimator or null if it does not exists 20004 * @see #setStateListAnimator(android.animation.StateListAnimator) 20005 */ 20006 @InspectableProperty getStateListAnimator()20007 public StateListAnimator getStateListAnimator() { 20008 return mStateListAnimator; 20009 } 20010 20011 /** 20012 * Attaches the provided StateListAnimator to this View. 20013 * <p> 20014 * Any previously attached StateListAnimator will be detached. 20015 * 20016 * @param stateListAnimator The StateListAnimator to update the view 20017 * @see android.animation.StateListAnimator 20018 */ setStateListAnimator(StateListAnimator stateListAnimator)20019 public void setStateListAnimator(StateListAnimator stateListAnimator) { 20020 if (mStateListAnimator == stateListAnimator) { 20021 return; 20022 } 20023 if (mStateListAnimator != null) { 20024 mStateListAnimator.setTarget(null); 20025 } 20026 mStateListAnimator = stateListAnimator; 20027 if (stateListAnimator != null) { 20028 stateListAnimator.setTarget(this); 20029 if (isAttachedToWindow()) { 20030 stateListAnimator.setState(getDrawableState()); 20031 } 20032 } 20033 } 20034 20035 /** 20036 * Returns whether the Outline should be used to clip the contents of the View. 20037 * <p> 20038 * Note that this flag will only be respected if the View's Outline returns true from 20039 * {@link Outline#canClip()}. 20040 * 20041 * @see #setOutlineProvider(ViewOutlineProvider) 20042 * @see #setClipToOutline(boolean) 20043 */ getClipToOutline()20044 public final boolean getClipToOutline() { 20045 return mRenderNode.getClipToOutline(); 20046 } 20047 20048 /** 20049 * Sets whether the View's Outline should be used to clip the contents of the View. 20050 * <p> 20051 * Only a single non-rectangular clip can be applied on a View at any time. 20052 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 20053 * circular reveal} animation take priority over Outline clipping, and 20054 * child Outline clipping takes priority over Outline clipping done by a 20055 * parent. 20056 * <p> 20057 * Note that this flag will only be respected if the View's Outline returns true from 20058 * {@link Outline#canClip()}. 20059 * 20060 * @see #setOutlineProvider(ViewOutlineProvider) 20061 * @see #getClipToOutline() 20062 * 20063 * @attr ref android.R.styleable#View_clipToOutline 20064 */ 20065 @RemotableViewMethod setClipToOutline(boolean clipToOutline)20066 public void setClipToOutline(boolean clipToOutline) { 20067 damageInParent(); 20068 if (getClipToOutline() != clipToOutline) { 20069 mRenderNode.setClipToOutline(clipToOutline); 20070 } 20071 } 20072 20073 // correspond to the enum values of View_outlineProvider 20074 private static final int PROVIDER_BACKGROUND = 0; 20075 private static final int PROVIDER_NONE = 1; 20076 private static final int PROVIDER_BOUNDS = 2; 20077 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)20078 private void setOutlineProviderFromAttribute(int providerInt) { 20079 switch (providerInt) { 20080 case PROVIDER_BACKGROUND: 20081 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 20082 break; 20083 case PROVIDER_NONE: 20084 setOutlineProvider(null); 20085 break; 20086 case PROVIDER_BOUNDS: 20087 setOutlineProvider(ViewOutlineProvider.BOUNDS); 20088 break; 20089 case PROVIDER_PADDED_BOUNDS: 20090 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 20091 break; 20092 } 20093 } 20094 20095 /** 20096 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 20097 * the shape of the shadow it casts, and enables outline clipping. 20098 * <p> 20099 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 20100 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 20101 * outline provider with this method allows this behavior to be overridden. 20102 * <p> 20103 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 20104 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 20105 * <p> 20106 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 20107 * 20108 * @see #setClipToOutline(boolean) 20109 * @see #getClipToOutline() 20110 * @see #getOutlineProvider() 20111 */ setOutlineProvider(ViewOutlineProvider provider)20112 public void setOutlineProvider(ViewOutlineProvider provider) { 20113 if (mOutlineProvider != provider) { 20114 mOutlineProvider = provider; 20115 invalidateOutline(); 20116 } 20117 } 20118 20119 /** 20120 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 20121 * that defines the shape of the shadow it casts, and enables outline clipping. 20122 * 20123 * @see #setOutlineProvider(ViewOutlineProvider) 20124 */ 20125 @InspectableProperty getOutlineProvider()20126 public ViewOutlineProvider getOutlineProvider() { 20127 return mOutlineProvider; 20128 } 20129 20130 /** 20131 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 20132 * 20133 * @see #setOutlineProvider(ViewOutlineProvider) 20134 */ invalidateOutline()20135 public void invalidateOutline() { 20136 rebuildOutline(); 20137 20138 notifySubtreeAccessibilityStateChangedIfNeeded(); 20139 invalidateViewProperty(false, false); 20140 } 20141 20142 /** 20143 * Internal version of {@link #invalidateOutline()} which invalidates the 20144 * outline without invalidating the view itself. This is intended to be called from 20145 * within methods in the View class itself which are the result of the view being 20146 * invalidated already. For example, when we are drawing the background of a View, 20147 * we invalidate the outline in case it changed in the meantime, but we do not 20148 * need to invalidate the view because we're already drawing the background as part 20149 * of drawing the view in response to an earlier invalidation of the view. 20150 */ rebuildOutline()20151 private void rebuildOutline() { 20152 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 20153 if (mAttachInfo == null) return; 20154 20155 if (mOutlineProvider == null) { 20156 // no provider, remove outline 20157 mRenderNode.setOutline(null); 20158 } else { 20159 final Outline outline = mAttachInfo.mTmpOutline; 20160 outline.setEmpty(); 20161 outline.setAlpha(1.0f); 20162 20163 mOutlineProvider.getOutline(this, outline); 20164 mRenderNode.setOutline(outline); 20165 } 20166 } 20167 20168 /** 20169 * HierarchyViewer only 20170 * 20171 * @hide 20172 */ 20173 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()20174 public boolean hasShadow() { 20175 return mRenderNode.hasShadow(); 20176 } 20177 20178 /** 20179 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 20180 * elevation value. 20181 * <p> 20182 * By default the shadow color is black. Generally, this color will be opaque so the intensity 20183 * of the shadow is consistent between different views with different colors. 20184 * <p> 20185 * The opacity of the final spot shadow is a function of the shadow caster height, the 20186 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 20187 * {@link android.R.attr#spotShadowAlpha} theme attribute. 20188 * 20189 * @attr ref android.R.styleable#View_outlineSpotShadowColor 20190 * @param color The color this View will cast for its elevation spot shadow. 20191 */ setOutlineSpotShadowColor(@olorInt int color)20192 public void setOutlineSpotShadowColor(@ColorInt int color) { 20193 if (mRenderNode.setSpotShadowColor(color)) { 20194 invalidateViewProperty(true, true); 20195 } 20196 } 20197 20198 /** 20199 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 20200 * was set 20201 */ 20202 @InspectableProperty getOutlineSpotShadowColor()20203 public @ColorInt int getOutlineSpotShadowColor() { 20204 return mRenderNode.getSpotShadowColor(); 20205 } 20206 20207 /** 20208 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 20209 * elevation value. 20210 * <p> 20211 * By default the shadow color is black. Generally, this color will be opaque so the intensity 20212 * of the shadow is consistent between different views with different colors. 20213 * <p> 20214 * The opacity of the final ambient shadow is a function of the shadow caster height, the 20215 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 20216 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 20217 * 20218 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 20219 * @param color The color this View will cast for its elevation shadow. 20220 */ setOutlineAmbientShadowColor(@olorInt int color)20221 public void setOutlineAmbientShadowColor(@ColorInt int color) { 20222 if (mRenderNode.setAmbientShadowColor(color)) { 20223 invalidateViewProperty(true, true); 20224 } 20225 } 20226 20227 /** 20228 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 20229 * nothing was set 20230 */ 20231 @InspectableProperty getOutlineAmbientShadowColor()20232 public @ColorInt int getOutlineAmbientShadowColor() { 20233 return mRenderNode.getAmbientShadowColor(); 20234 } 20235 20236 20237 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)20238 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 20239 mRenderNode.setRevealClip(shouldClip, x, y, radius); 20240 invalidateViewProperty(false, false); 20241 } 20242 20243 /** 20244 * Hit rectangle in parent's coordinates 20245 * 20246 * @param outRect The hit rectangle of the view. 20247 */ getHitRect(Rect outRect)20248 public void getHitRect(Rect outRect) { 20249 if (hasIdentityMatrix() || mAttachInfo == null) { 20250 outRect.set(mLeft, mTop, mRight, mBottom); 20251 } else { 20252 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 20253 tmpRect.set(0, 0, getWidth(), getHeight()); 20254 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 20255 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 20256 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 20257 } 20258 } 20259 20260 /** 20261 * Determines whether the given point, in local coordinates is inside the view. 20262 */ pointInView(float localX, float localY)20263 /*package*/ final boolean pointInView(float localX, float localY) { 20264 return pointInView(localX, localY, 0); 20265 } 20266 20267 /** 20268 * Utility method to determine whether the given point, in local coordinates, 20269 * is inside the view, where the area of the view is expanded by the slop factor. 20270 * This method is called while processing touch-move events to determine if the event 20271 * is still within the view. 20272 * 20273 * @hide 20274 */ 20275 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)20276 public boolean pointInView(float localX, float localY, float slop) { 20277 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 20278 localY < ((mBottom - mTop) + slop); 20279 } 20280 20281 /** 20282 * When a view has focus and the user navigates away from it, the next view is searched for 20283 * starting from the rectangle filled in by this method. 20284 * 20285 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 20286 * of the view. However, if your view maintains some idea of internal selection, 20287 * such as a cursor, or a selected row or column, you should override this method and 20288 * fill in a more specific rectangle. 20289 * 20290 * @param r The rectangle to fill in, in this view's coordinates. 20291 */ getFocusedRect(Rect r)20292 public void getFocusedRect(Rect r) { 20293 getDrawingRect(r); 20294 } 20295 20296 /** 20297 * Sets {@code r} to the coordinates of the non-clipped area of this view in 20298 * the coordinate space of the view's root view. Sets {@code globalOffset} 20299 * to the offset of the view's x and y coordinates from the coordinate space 20300 * origin, which is the top left corner of the root view irrespective of 20301 * screen decorations and system UI elements. 20302 * 20303 * <p>To convert {@code r} to coordinates relative to the top left corner of 20304 * this view (without taking view rotations into account), offset {@code r} 20305 * by the inverse values of 20306 * {@code globalOffset}—{@code r.offset(-globalOffset.x, 20307 * -globalOffset.y)}—which is equivalent to calling 20308 * {@link #getLocalVisibleRect(Rect) getLocalVisibleRect(Rect)}. 20309 * 20310 * <p><b>Note:</b> Do not use this method to determine the size of a window 20311 * in multi-window mode; use 20312 * {@link WindowManager#getCurrentWindowMetrics()}. 20313 * 20314 * @param r If the method returns true, contains the coordinates of the 20315 * visible portion of this view in the coordinate space of the view's 20316 * root view. If the method returns false, the contents of {@code r} 20317 * are undefined. 20318 * @param globalOffset If the method returns true, contains the offset of 20319 * the x and y coordinates of this view from the top left corner of the 20320 * view's root view. If the method returns false, the contents of 20321 * {@code globalOffset} are undefined. The argument can be null (see 20322 * {@link #getGlobalVisibleRect(Rect) getGlobalVisibleRect(Rect)}. 20323 * @return true if at least part of the view is visible within the root 20324 * view; false if the view is completely clipped or translated out of 20325 * the visible area of the root view. 20326 * 20327 * @see #getLocalVisibleRect(Rect) 20328 */ getGlobalVisibleRect(Rect r, Point globalOffset)20329 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 20330 int width = mRight - mLeft; 20331 int height = mBottom - mTop; 20332 if (width > 0 && height > 0) { 20333 r.set(0, 0, width, height); 20334 if (globalOffset != null) { 20335 globalOffset.set(-mScrollX, -mScrollY); 20336 } 20337 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 20338 } 20339 return false; 20340 } 20341 20342 /** 20343 * Sets {@code r} to the coordinates of the non-clipped area of this view in 20344 * the coordinate space of the view's root view. 20345 * 20346 * <p>See {@link #getGlobalVisibleRect(Rect, Point) 20347 * getGlobalVisibleRect(Rect, Point)} for more information. 20348 * 20349 * @param r If the method returns true, contains the coordinates of the 20350 * visible portion of this view in the coordinate space of the view's 20351 * root view. If the method returns false, the contents of {@code r} 20352 * are undefined. 20353 * @return true if at least part of the view is visible within the root 20354 * view; otherwise false. 20355 */ getGlobalVisibleRect(Rect r)20356 public final boolean getGlobalVisibleRect(Rect r) { 20357 return getGlobalVisibleRect(r, null); 20358 } 20359 20360 /** 20361 * Sets {@code r} to the coordinates of the non-clipped area of this view 20362 * relative to the top left corner of the view. 20363 * 20364 * <p>If the view is clipped on the left or top, the left and top 20365 * coordinates are offset from 0 by the clipped amount. For example, if the 20366 * view is off screen 50px on the left and 30px at the top, the left and top 20367 * coordinates are 50 and 30 respectively. 20368 * 20369 * <p>If the view is clipped on the right or bottom, the right and bottom 20370 * coordinates are reduced by the clipped amount. For example, if the view 20371 * is off screen 40px on the right and 20px at the bottom, the right 20372 * coordinate is the view width - 40, and the bottom coordinate is the view 20373 * height - 20. 20374 * 20375 * @param r If the method returns true, contains the coordinates of the 20376 * visible portion of this view relative to the top left corner of the 20377 * view. If the method returns false, the contents of {@code r} are 20378 * undefined. 20379 * @return true if at least part of the view is visible; false if the view 20380 * is completely clipped or translated out of the visible area. 20381 * 20382 * @see #getGlobalVisibleRect(Rect, Point) 20383 */ getLocalVisibleRect(Rect r)20384 public final boolean getLocalVisibleRect(Rect r) { 20385 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 20386 if (getGlobalVisibleRect(r, offset)) { 20387 r.offset(-offset.x, -offset.y); // make r local 20388 return true; 20389 } 20390 return false; 20391 } 20392 20393 /** 20394 * Offset this view's vertical location by the specified number of pixels. 20395 * 20396 * @param offset the number of pixels to offset the view by 20397 */ offsetTopAndBottom(int offset)20398 public void offsetTopAndBottom(int offset) { 20399 if (offset != 0) { 20400 final boolean matrixIsIdentity = hasIdentityMatrix(); 20401 if (matrixIsIdentity) { 20402 if (isHardwareAccelerated()) { 20403 invalidateViewProperty(false, false); 20404 } else { 20405 final ViewParent p = mParent; 20406 if (p != null && mAttachInfo != null) { 20407 final Rect r = mAttachInfo.mTmpInvalRect; 20408 int minTop; 20409 int maxBottom; 20410 int yLoc; 20411 if (offset < 0) { 20412 minTop = mTop + offset; 20413 maxBottom = mBottom; 20414 yLoc = offset; 20415 } else { 20416 minTop = mTop; 20417 maxBottom = mBottom + offset; 20418 yLoc = 0; 20419 } 20420 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 20421 p.invalidateChild(this, r); 20422 } 20423 } 20424 } else { 20425 invalidateViewProperty(false, false); 20426 } 20427 20428 mTop += offset; 20429 mBottom += offset; 20430 mRenderNode.offsetTopAndBottom(offset); 20431 if (isHardwareAccelerated()) { 20432 invalidateViewProperty(false, false); 20433 invalidateParentIfNeededAndWasQuickRejected(); 20434 } else { 20435 if (!matrixIsIdentity) { 20436 invalidateViewProperty(false, true); 20437 } 20438 invalidateParentIfNeeded(); 20439 } 20440 notifySubtreeAccessibilityStateChangedIfNeeded(); 20441 } 20442 } 20443 20444 /** 20445 * Offset this view's horizontal location by the specified amount of pixels. 20446 * 20447 * @param offset the number of pixels to offset the view by 20448 */ offsetLeftAndRight(int offset)20449 public void offsetLeftAndRight(int offset) { 20450 if (offset != 0) { 20451 final boolean matrixIsIdentity = hasIdentityMatrix(); 20452 if (matrixIsIdentity) { 20453 if (isHardwareAccelerated()) { 20454 invalidateViewProperty(false, false); 20455 } else { 20456 final ViewParent p = mParent; 20457 if (p != null && mAttachInfo != null) { 20458 final Rect r = mAttachInfo.mTmpInvalRect; 20459 int minLeft; 20460 int maxRight; 20461 if (offset < 0) { 20462 minLeft = mLeft + offset; 20463 maxRight = mRight; 20464 } else { 20465 minLeft = mLeft; 20466 maxRight = mRight + offset; 20467 } 20468 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 20469 p.invalidateChild(this, r); 20470 } 20471 } 20472 } else { 20473 invalidateViewProperty(false, false); 20474 } 20475 20476 mLeft += offset; 20477 mRight += offset; 20478 mRenderNode.offsetLeftAndRight(offset); 20479 if (isHardwareAccelerated()) { 20480 invalidateViewProperty(false, false); 20481 invalidateParentIfNeededAndWasQuickRejected(); 20482 } else { 20483 if (!matrixIsIdentity) { 20484 invalidateViewProperty(false, true); 20485 } 20486 invalidateParentIfNeeded(); 20487 } 20488 notifySubtreeAccessibilityStateChangedIfNeeded(); 20489 } 20490 } 20491 20492 /** 20493 * Get the LayoutParams associated with this view. All views should have 20494 * layout parameters. These supply parameters to the <i>parent</i> of this 20495 * view specifying how it should be arranged. There are many subclasses of 20496 * ViewGroup.LayoutParams, and these correspond to the different subclasses 20497 * of ViewGroup that are responsible for arranging their children. 20498 * 20499 * This method may return null if this View is not attached to a parent 20500 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 20501 * was not invoked successfully. When a View is attached to a parent 20502 * ViewGroup, this method must not return null. 20503 * 20504 * @return The LayoutParams associated with this view, or null if no 20505 * parameters have been set yet 20506 */ 20507 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()20508 public ViewGroup.LayoutParams getLayoutParams() { 20509 return mLayoutParams; 20510 } 20511 20512 /** 20513 * Set the layout parameters associated with this view. These supply 20514 * parameters to the <i>parent</i> of this view specifying how it should be 20515 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 20516 * correspond to the different subclasses of ViewGroup that are responsible 20517 * for arranging their children. 20518 * 20519 * @param params The layout parameters for this view, cannot be null 20520 */ setLayoutParams(ViewGroup.LayoutParams params)20521 public void setLayoutParams(ViewGroup.LayoutParams params) { 20522 if (params == null) { 20523 throw new NullPointerException("Layout parameters cannot be null"); 20524 } 20525 mLayoutParams = params; 20526 resolveLayoutParams(); 20527 if (mParent instanceof ViewGroup) { 20528 ((ViewGroup) mParent).onSetLayoutParams(this, params); 20529 } 20530 requestLayout(); 20531 } 20532 20533 /** 20534 * Resolve the layout parameters depending on the resolved layout direction 20535 * 20536 * @hide 20537 */ resolveLayoutParams()20538 public void resolveLayoutParams() { 20539 if (mLayoutParams != null) { 20540 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 20541 } 20542 } 20543 20544 /** 20545 * Set the scrolled position of your view. This will cause a call to 20546 * {@link #onScrollChanged(int, int, int, int)} and the view will be 20547 * invalidated. 20548 * @param x the x position to scroll to 20549 * @param y the y position to scroll to 20550 */ scrollTo(int x, int y)20551 public void scrollTo(int x, int y) { 20552 if (mScrollX != x || mScrollY != y) { 20553 int oldX = mScrollX; 20554 int oldY = mScrollY; 20555 mScrollX = x; 20556 mScrollY = y; 20557 invalidateParentCaches(); 20558 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 20559 if (!awakenScrollBars()) { 20560 postInvalidateOnAnimation(); 20561 } 20562 } 20563 } 20564 20565 /** 20566 * Move the scrolled position of your view. This will cause a call to 20567 * {@link #onScrollChanged(int, int, int, int)} and the view will be 20568 * invalidated. 20569 * @param x the amount of pixels to scroll by horizontally 20570 * @param y the amount of pixels to scroll by vertically 20571 */ scrollBy(int x, int y)20572 public void scrollBy(int x, int y) { 20573 scrollTo(mScrollX + x, mScrollY + y); 20574 } 20575 20576 /** 20577 * <p>Trigger the scrollbars to draw. When invoked this method starts an 20578 * animation to fade the scrollbars out after a default delay. If a subclass 20579 * provides animated scrolling, the start delay should equal the duration 20580 * of the scrolling animation.</p> 20581 * 20582 * <p>The animation starts only if at least one of the scrollbars is 20583 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 20584 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 20585 * this method returns true, and false otherwise. If the animation is 20586 * started, this method calls {@link #invalidate()}; in that case the 20587 * caller should not call {@link #invalidate()}.</p> 20588 * 20589 * <p>This method should be invoked every time a subclass directly updates 20590 * the scroll parameters.</p> 20591 * 20592 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 20593 * and {@link #scrollTo(int, int)}.</p> 20594 * 20595 * @return true if the animation is played, false otherwise 20596 * 20597 * @see #awakenScrollBars(int) 20598 * @see #scrollBy(int, int) 20599 * @see #scrollTo(int, int) 20600 * @see #isHorizontalScrollBarEnabled() 20601 * @see #isVerticalScrollBarEnabled() 20602 * @see #setHorizontalScrollBarEnabled(boolean) 20603 * @see #setVerticalScrollBarEnabled(boolean) 20604 */ awakenScrollBars()20605 protected boolean awakenScrollBars() { 20606 return mScrollCache != null && 20607 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 20608 } 20609 20610 /** 20611 * Trigger the scrollbars to draw. 20612 * This method differs from awakenScrollBars() only in its default duration. 20613 * initialAwakenScrollBars() will show the scroll bars for longer than 20614 * usual to give the user more of a chance to notice them. 20615 * 20616 * @return true if the animation is played, false otherwise. 20617 */ initialAwakenScrollBars()20618 private boolean initialAwakenScrollBars() { 20619 return mScrollCache != null && 20620 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 20621 } 20622 20623 /** 20624 * <p> 20625 * Trigger the scrollbars to draw. When invoked this method starts an 20626 * animation to fade the scrollbars out after a fixed delay. If a subclass 20627 * provides animated scrolling, the start delay should equal the duration of 20628 * the scrolling animation. 20629 * </p> 20630 * 20631 * <p> 20632 * The animation starts only if at least one of the scrollbars is enabled, 20633 * as specified by {@link #isHorizontalScrollBarEnabled()} and 20634 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 20635 * this method returns true, and false otherwise. If the animation is 20636 * started, this method calls {@link #invalidate()}; in that case the caller 20637 * should not call {@link #invalidate()}. 20638 * </p> 20639 * 20640 * <p> 20641 * This method should be invoked every time a subclass directly updates the 20642 * scroll parameters. 20643 * </p> 20644 * 20645 * @param startDelay the delay, in milliseconds, after which the animation 20646 * should start; when the delay is 0, the animation starts 20647 * immediately 20648 * @return true if the animation is played, false otherwise 20649 * 20650 * @see #scrollBy(int, int) 20651 * @see #scrollTo(int, int) 20652 * @see #isHorizontalScrollBarEnabled() 20653 * @see #isVerticalScrollBarEnabled() 20654 * @see #setHorizontalScrollBarEnabled(boolean) 20655 * @see #setVerticalScrollBarEnabled(boolean) 20656 */ awakenScrollBars(int startDelay)20657 protected boolean awakenScrollBars(int startDelay) { 20658 return awakenScrollBars(startDelay, true); 20659 } 20660 20661 /** 20662 * <p> 20663 * Trigger the scrollbars to draw. When invoked this method starts an 20664 * animation to fade the scrollbars out after a fixed delay. If a subclass 20665 * provides animated scrolling, the start delay should equal the duration of 20666 * the scrolling animation. 20667 * </p> 20668 * 20669 * <p> 20670 * The animation starts only if at least one of the scrollbars is enabled, 20671 * as specified by {@link #isHorizontalScrollBarEnabled()} and 20672 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 20673 * this method returns true, and false otherwise. If the animation is 20674 * started, this method calls {@link #invalidate()} if the invalidate parameter 20675 * is set to true; in that case the caller 20676 * should not call {@link #invalidate()}. 20677 * </p> 20678 * 20679 * <p> 20680 * This method should be invoked every time a subclass directly updates the 20681 * scroll parameters. 20682 * </p> 20683 * 20684 * @param startDelay the delay, in milliseconds, after which the animation 20685 * should start; when the delay is 0, the animation starts 20686 * immediately 20687 * 20688 * @param invalidate Whether this method should call invalidate 20689 * 20690 * @return true if the animation is played, false otherwise 20691 * 20692 * @see #scrollBy(int, int) 20693 * @see #scrollTo(int, int) 20694 * @see #isHorizontalScrollBarEnabled() 20695 * @see #isVerticalScrollBarEnabled() 20696 * @see #setHorizontalScrollBarEnabled(boolean) 20697 * @see #setVerticalScrollBarEnabled(boolean) 20698 */ awakenScrollBars(int startDelay, boolean invalidate)20699 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 20700 final ScrollabilityCache scrollCache = mScrollCache; 20701 20702 if (scrollCache == null || !scrollCache.fadeScrollBars) { 20703 return false; 20704 } 20705 20706 if (scrollCache.scrollBar == null) { 20707 scrollCache.scrollBar = new ScrollBarDrawable(); 20708 scrollCache.scrollBar.setState(getDrawableState()); 20709 scrollCache.scrollBar.setCallback(this); 20710 } 20711 20712 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 20713 20714 if (invalidate) { 20715 // Invalidate to show the scrollbars 20716 postInvalidateOnAnimation(); 20717 } 20718 20719 if (scrollCache.state == ScrollabilityCache.OFF) { 20720 // FIXME: this is copied from WindowManagerService. 20721 // We should get this value from the system when it 20722 // is possible to do so. 20723 final int KEY_REPEAT_FIRST_DELAY = 750; 20724 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 20725 } 20726 20727 // Tell mScrollCache when we should start fading. This may 20728 // extend the fade start time if one was already scheduled 20729 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 20730 scrollCache.fadeStartTime = fadeStartTime; 20731 scrollCache.state = ScrollabilityCache.ON; 20732 20733 // Schedule our fader to run, unscheduling any old ones first 20734 if (mAttachInfo != null) { 20735 mAttachInfo.mHandler.removeCallbacks(scrollCache); 20736 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 20737 } 20738 20739 return true; 20740 } 20741 20742 return false; 20743 } 20744 20745 /** 20746 * Do not invalidate views which are not visible and which are not running an animation. They 20747 * will not get drawn and they should not set dirty flags as if they will be drawn 20748 */ skipInvalidate()20749 private boolean skipInvalidate() { 20750 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 20751 (!(mParent instanceof ViewGroup) || 20752 !((ViewGroup) mParent).isViewTransitioning(this)); 20753 } 20754 20755 /** 20756 * Mark the area defined by dirty as needing to be drawn. If the view is 20757 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 20758 * point in the future. 20759 * <p> 20760 * This must be called from a UI thread. To call from a non-UI thread, call 20761 * {@link #postInvalidate()}. 20762 * <p> 20763 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 20764 * {@code dirty}. 20765 * 20766 * @param dirty the rectangle representing the bounds of the dirty region 20767 * 20768 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 20769 * the importance of the dirty rectangle. In API 21 the given rectangle is 20770 * ignored entirely in favor of an internally-calculated area instead. 20771 * Because of this, clients are encouraged to just call {@link #invalidate()}. 20772 */ 20773 @Deprecated invalidate(Rect dirty)20774 public void invalidate(Rect dirty) { 20775 final int scrollX = mScrollX; 20776 final int scrollY = mScrollY; 20777 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 20778 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 20779 } 20780 20781 /** 20782 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 20783 * coordinates of the dirty rect are relative to the view. If the view is 20784 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 20785 * point in the future. 20786 * <p> 20787 * This must be called from a UI thread. To call from a non-UI thread, call 20788 * {@link #postInvalidate()}. 20789 * 20790 * @param l the left position of the dirty region 20791 * @param t the top position of the dirty region 20792 * @param r the right position of the dirty region 20793 * @param b the bottom position of the dirty region 20794 * 20795 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 20796 * the importance of the dirty rectangle. In API 21 the given rectangle is 20797 * ignored entirely in favor of an internally-calculated area instead. 20798 * Because of this, clients are encouraged to just call {@link #invalidate()}. 20799 */ 20800 @Deprecated invalidate(int l, int t, int r, int b)20801 public void invalidate(int l, int t, int r, int b) { 20802 final int scrollX = mScrollX; 20803 final int scrollY = mScrollY; 20804 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 20805 } 20806 20807 /** 20808 * Invalidate the whole view. If the view is visible, 20809 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 20810 * the future. 20811 * <p> 20812 * This must be called from a UI thread. To call from a non-UI thread, call 20813 * {@link #postInvalidate()}. 20814 */ invalidate()20815 public void invalidate() { 20816 invalidate(true); 20817 } 20818 20819 /** 20820 * This is where the invalidate() work actually happens. A full invalidate() 20821 * causes the drawing cache to be invalidated, but this function can be 20822 * called with invalidateCache set to false to skip that invalidation step 20823 * for cases that do not need it (for example, a component that remains at 20824 * the same dimensions with the same content). 20825 * 20826 * @param invalidateCache Whether the drawing cache for this view should be 20827 * invalidated as well. This is usually true for a full 20828 * invalidate, but may be set to false if the View's contents or 20829 * dimensions have not changed. 20830 * @hide 20831 */ 20832 @UnsupportedAppUsage invalidate(boolean invalidateCache)20833 public void invalidate(boolean invalidateCache) { 20834 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 20835 } 20836 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)20837 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 20838 boolean fullInvalidate) { 20839 if (mGhostView != null) { 20840 mGhostView.invalidate(true); 20841 return; 20842 } 20843 20844 if (skipInvalidate()) { 20845 return; 20846 } 20847 20848 // Reset content capture caches 20849 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 20850 mContentCaptureSessionCached = false; 20851 20852 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 20853 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 20854 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 20855 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 20856 if (fullInvalidate) { 20857 mLastIsOpaque = isOpaque(); 20858 mPrivateFlags &= ~PFLAG_DRAWN; 20859 } 20860 20861 mPrivateFlags |= PFLAG_DIRTY; 20862 20863 if (invalidateCache) { 20864 mPrivateFlags |= PFLAG_INVALIDATED; 20865 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 20866 } 20867 20868 // Propagate the damage rectangle to the parent view. 20869 final AttachInfo ai = mAttachInfo; 20870 final ViewParent p = mParent; 20871 if (p != null && ai != null && l < r && t < b) { 20872 final Rect damage = ai.mTmpInvalRect; 20873 damage.set(l, t, r, b); 20874 p.invalidateChild(this, damage); 20875 } 20876 20877 // Damage the entire projection receiver, if necessary. 20878 if (mBackground != null && mBackground.isProjected()) { 20879 final View receiver = getProjectionReceiver(); 20880 if (receiver != null) { 20881 receiver.damageInParent(); 20882 } 20883 } 20884 } 20885 } 20886 20887 /** 20888 * @return this view's projection receiver, or {@code null} if none exists 20889 */ getProjectionReceiver()20890 private View getProjectionReceiver() { 20891 ViewParent p = getParent(); 20892 while (p != null && p instanceof View) { 20893 final View v = (View) p; 20894 if (v.isProjectionReceiver()) { 20895 return v; 20896 } 20897 p = p.getParent(); 20898 } 20899 20900 return null; 20901 } 20902 20903 /** 20904 * @return whether the view is a projection receiver 20905 */ isProjectionReceiver()20906 private boolean isProjectionReceiver() { 20907 return mBackground != null; 20908 } 20909 20910 /** 20911 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 20912 * set any flags or handle all of the cases handled by the default invalidation methods. 20913 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 20914 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 20915 * walk up the hierarchy, transforming the dirty rect as necessary. 20916 * 20917 * The method also handles normal invalidation logic if display list properties are not 20918 * being used in this view. The invalidateParent and forceRedraw flags are used by that 20919 * backup approach, to handle these cases used in the various property-setting methods. 20920 * 20921 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 20922 * are not being used in this view 20923 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 20924 * list properties are not being used in this view 20925 */ 20926 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)20927 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 20928 if (!isHardwareAccelerated() 20929 || !mRenderNode.hasDisplayList() 20930 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 20931 if (invalidateParent) { 20932 invalidateParentCaches(); 20933 } 20934 if (forceRedraw) { 20935 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 20936 } 20937 invalidate(false); 20938 } else { 20939 damageInParent(); 20940 } 20941 mPrivateFlags4 |= PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; 20942 } 20943 20944 /** 20945 * Tells the parent view to damage this view's bounds. 20946 * 20947 * @hide 20948 */ damageInParent()20949 protected void damageInParent() { 20950 if (mParent != null && mAttachInfo != null) { 20951 mParent.onDescendantInvalidated(this, this); 20952 } 20953 } 20954 20955 /** 20956 * Used to indicate that the parent of this view should clear its caches. This functionality 20957 * is used to force the parent to rebuild its display list (when hardware-accelerated), 20958 * which is necessary when various parent-managed properties of the view change, such as 20959 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 20960 * clears the parent caches and does not causes an invalidate event. 20961 * 20962 * @hide 20963 */ 20964 @UnsupportedAppUsage invalidateParentCaches()20965 protected void invalidateParentCaches() { 20966 if (mParent instanceof View) { 20967 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 20968 } 20969 } 20970 20971 /** 20972 * Used to indicate that the parent of this view should be invalidated. This functionality 20973 * is used to force the parent to rebuild its display list (when hardware-accelerated), 20974 * which is necessary when various parent-managed properties of the view change, such as 20975 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 20976 * an invalidation event to the parent. 20977 * 20978 * @hide 20979 */ 20980 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) invalidateParentIfNeeded()20981 protected void invalidateParentIfNeeded() { 20982 if (isHardwareAccelerated() && mParent instanceof View) { 20983 ((View) mParent).invalidate(true); 20984 } 20985 } 20986 20987 /** 20988 * @hide 20989 */ invalidateParentIfNeededAndWasQuickRejected()20990 protected void invalidateParentIfNeededAndWasQuickRejected() { 20991 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 20992 // View was rejected last time it was drawn by its parent; this may have changed 20993 invalidateParentIfNeeded(); 20994 } 20995 } 20996 20997 /** 20998 * Indicates whether this View is opaque. An opaque View guarantees that it will 20999 * draw all the pixels overlapping its bounds using a fully opaque color. 21000 * 21001 * Subclasses of View should override this method whenever possible to indicate 21002 * whether an instance is opaque. Opaque Views are treated in a special way by 21003 * the View hierarchy, possibly allowing it to perform optimizations during 21004 * invalidate/draw passes. 21005 * 21006 * @return True if this View is guaranteed to be fully opaque, false otherwise. 21007 */ 21008 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()21009 public boolean isOpaque() { 21010 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 21011 getFinalAlpha() >= 1.0f; 21012 } 21013 21014 /** 21015 * @hide 21016 */ 21017 @UnsupportedAppUsage computeOpaqueFlags()21018 protected void computeOpaqueFlags() { 21019 // Opaque if: 21020 // - Has a background 21021 // - Background is opaque 21022 // - Doesn't have scrollbars or scrollbars overlay 21023 21024 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 21025 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 21026 } else { 21027 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 21028 } 21029 21030 final int flags = mViewFlags; 21031 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 21032 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 21033 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 21034 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 21035 } else { 21036 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 21037 } 21038 } 21039 21040 /** 21041 * @hide 21042 */ hasOpaqueScrollbars()21043 protected boolean hasOpaqueScrollbars() { 21044 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 21045 } 21046 21047 /** 21048 * @return A handler associated with the thread running the View. This 21049 * handler can be used to pump events in the UI events queue. 21050 */ getHandler()21051 public Handler getHandler() { 21052 final AttachInfo attachInfo = mAttachInfo; 21053 if (attachInfo != null) { 21054 return attachInfo.mHandler; 21055 } 21056 return null; 21057 } 21058 21059 /** 21060 * Returns the queue of runnable for this view. 21061 * 21062 * @return the queue of runnables for this view 21063 */ getRunQueue()21064 private HandlerActionQueue getRunQueue() { 21065 if (mRunQueue == null) { 21066 mRunQueue = new HandlerActionQueue(); 21067 } 21068 return mRunQueue; 21069 } 21070 21071 /** 21072 * Gets the view root associated with the View. 21073 * @return The view root, or null if none. 21074 * @hide 21075 */ 21076 @UnsupportedAppUsage getViewRootImpl()21077 public ViewRootImpl getViewRootImpl() { 21078 if (mAttachInfo != null) { 21079 return mAttachInfo.mViewRootImpl; 21080 } 21081 return null; 21082 } 21083 21084 /** 21085 * @hide 21086 */ 21087 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getThreadedRenderer()21088 public ThreadedRenderer getThreadedRenderer() { 21089 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 21090 } 21091 21092 /** 21093 * <p>Causes the Runnable to be added to the message queue. 21094 * The runnable will be run on the user interface thread.</p> 21095 * 21096 * @param action The Runnable that will be executed. 21097 * 21098 * @return Returns true if the Runnable was successfully placed in to the 21099 * message queue. Returns false on failure, usually because the 21100 * looper processing the message queue is exiting. 21101 * 21102 * @see #postDelayed 21103 * @see #removeCallbacks 21104 */ post(Runnable action)21105 public boolean post(Runnable action) { 21106 final AttachInfo attachInfo = mAttachInfo; 21107 if (attachInfo != null) { 21108 return attachInfo.mHandler.post(action); 21109 } 21110 21111 // Postpone the runnable until we know on which thread it needs to run. 21112 // Assume that the runnable will be successfully placed after attach. 21113 getRunQueue().post(action); 21114 return true; 21115 } 21116 21117 /** 21118 * <p>Causes the Runnable to be added to the message queue, to be run 21119 * after the specified amount of time elapses. 21120 * The runnable will be run on the user interface thread.</p> 21121 * 21122 * @param action The Runnable that will be executed. 21123 * @param delayMillis The delay (in milliseconds) until the Runnable 21124 * will be executed. 21125 * 21126 * @return true if the Runnable was successfully placed in to the 21127 * message queue. Returns false on failure, usually because the 21128 * looper processing the message queue is exiting. Note that a 21129 * result of true does not mean the Runnable will be processed -- 21130 * if the looper is quit before the delivery time of the message 21131 * occurs then the message will be dropped. 21132 * 21133 * @see #post 21134 * @see #removeCallbacks 21135 */ postDelayed(Runnable action, long delayMillis)21136 public boolean postDelayed(Runnable action, long delayMillis) { 21137 final AttachInfo attachInfo = mAttachInfo; 21138 if (attachInfo != null) { 21139 return attachInfo.mHandler.postDelayed(action, delayMillis); 21140 } 21141 21142 // Postpone the runnable until we know on which thread it needs to run. 21143 // Assume that the runnable will be successfully placed after attach. 21144 getRunQueue().postDelayed(action, delayMillis); 21145 return true; 21146 } 21147 21148 /** 21149 * <p>Causes the Runnable to execute on the next animation time step. 21150 * The runnable will be run on the user interface thread.</p> 21151 * 21152 * @param action The Runnable that will be executed. 21153 * 21154 * @see #postOnAnimationDelayed 21155 * @see #removeCallbacks 21156 */ postOnAnimation(Runnable action)21157 public void postOnAnimation(Runnable action) { 21158 final AttachInfo attachInfo = mAttachInfo; 21159 if (attachInfo != null) { 21160 attachInfo.mViewRootImpl.mChoreographer.postCallback( 21161 Choreographer.CALLBACK_ANIMATION, action, null); 21162 } else { 21163 // Postpone the runnable until we know 21164 // on which thread it needs to run. 21165 getRunQueue().post(action); 21166 } 21167 } 21168 21169 /** 21170 * <p>Causes the Runnable to execute on the next animation time step, 21171 * after the specified amount of time elapses. 21172 * The runnable will be run on the user interface thread.</p> 21173 * 21174 * @param action The Runnable that will be executed. 21175 * @param delayMillis The delay (in milliseconds) until the Runnable 21176 * will be executed. 21177 * 21178 * @see #postOnAnimation 21179 * @see #removeCallbacks 21180 */ postOnAnimationDelayed(Runnable action, long delayMillis)21181 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 21182 final AttachInfo attachInfo = mAttachInfo; 21183 if (attachInfo != null) { 21184 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 21185 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 21186 } else { 21187 // Postpone the runnable until we know 21188 // on which thread it needs to run. 21189 getRunQueue().postDelayed(action, delayMillis); 21190 } 21191 } 21192 21193 /** 21194 * <p>Removes the specified Runnable from the message queue.</p> 21195 * 21196 * @param action The Runnable to remove from the message handling queue 21197 * 21198 * @return true if this view could ask the Handler to remove the Runnable, 21199 * false otherwise. When the returned value is true, the Runnable 21200 * may or may not have been actually removed from the message queue 21201 * (for instance, if the Runnable was not in the queue already.) 21202 * 21203 * @see #post 21204 * @see #postDelayed 21205 * @see #postOnAnimation 21206 * @see #postOnAnimationDelayed 21207 */ removeCallbacks(Runnable action)21208 public boolean removeCallbacks(Runnable action) { 21209 if (action != null) { 21210 final AttachInfo attachInfo = mAttachInfo; 21211 if (attachInfo != null) { 21212 attachInfo.mHandler.removeCallbacks(action); 21213 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 21214 Choreographer.CALLBACK_ANIMATION, action, null); 21215 } 21216 getRunQueue().removeCallbacks(action); 21217 } 21218 return true; 21219 } 21220 21221 /** 21222 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 21223 * Use this to invalidate the View from a non-UI thread.</p> 21224 * 21225 * <p>This method can be invoked from outside of the UI thread 21226 * only when this View is attached to a window.</p> 21227 * 21228 * @see #invalidate() 21229 * @see #postInvalidateDelayed(long) 21230 */ postInvalidate()21231 public void postInvalidate() { 21232 postInvalidateDelayed(0); 21233 } 21234 21235 /** 21236 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 21237 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 21238 * 21239 * <p>This method can be invoked from outside of the UI thread 21240 * only when this View is attached to a window.</p> 21241 * 21242 * @param left The left coordinate of the rectangle to invalidate. 21243 * @param top The top coordinate of the rectangle to invalidate. 21244 * @param right The right coordinate of the rectangle to invalidate. 21245 * @param bottom The bottom coordinate of the rectangle to invalidate. 21246 * 21247 * @see #invalidate(int, int, int, int) 21248 * @see #invalidate(Rect) 21249 * @see #postInvalidateDelayed(long, int, int, int, int) 21250 */ postInvalidate(int left, int top, int right, int bottom)21251 public void postInvalidate(int left, int top, int right, int bottom) { 21252 postInvalidateDelayed(0, left, top, right, bottom); 21253 } 21254 21255 /** 21256 * <p>Cause an invalidate to happen on a subsequent cycle through the event 21257 * loop. Waits for the specified amount of time.</p> 21258 * 21259 * <p>This method can be invoked from outside of the UI thread 21260 * only when this View is attached to a window.</p> 21261 * 21262 * @param delayMilliseconds the duration in milliseconds to delay the 21263 * invalidation by 21264 * 21265 * @see #invalidate() 21266 * @see #postInvalidate() 21267 */ postInvalidateDelayed(long delayMilliseconds)21268 public void postInvalidateDelayed(long delayMilliseconds) { 21269 // We try only with the AttachInfo because there's no point in invalidating 21270 // if we are not attached to our window 21271 final AttachInfo attachInfo = mAttachInfo; 21272 if (attachInfo != null) { 21273 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 21274 } 21275 } 21276 21277 /** 21278 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 21279 * through the event loop. Waits for the specified amount of time.</p> 21280 * 21281 * <p>This method can be invoked from outside of the UI thread 21282 * only when this View is attached to a window.</p> 21283 * 21284 * @param delayMilliseconds the duration in milliseconds to delay the 21285 * invalidation by 21286 * @param left The left coordinate of the rectangle to invalidate. 21287 * @param top The top coordinate of the rectangle to invalidate. 21288 * @param right The right coordinate of the rectangle to invalidate. 21289 * @param bottom The bottom coordinate of the rectangle to invalidate. 21290 * 21291 * @see #invalidate(int, int, int, int) 21292 * @see #invalidate(Rect) 21293 * @see #postInvalidate(int, int, int, int) 21294 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)21295 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 21296 int right, int bottom) { 21297 21298 // We try only with the AttachInfo because there's no point in invalidating 21299 // if we are not attached to our window 21300 final AttachInfo attachInfo = mAttachInfo; 21301 if (attachInfo != null) { 21302 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 21303 info.target = this; 21304 info.left = left; 21305 info.top = top; 21306 info.right = right; 21307 info.bottom = bottom; 21308 21309 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 21310 } 21311 } 21312 21313 /** 21314 * <p>Cause an invalidate to happen on the next animation time step, typically the 21315 * next display frame.</p> 21316 * 21317 * <p>This method can be invoked from outside of the UI thread 21318 * only when this View is attached to a window.</p> 21319 * 21320 * @see #invalidate() 21321 */ postInvalidateOnAnimation()21322 public void postInvalidateOnAnimation() { 21323 // We try only with the AttachInfo because there's no point in invalidating 21324 // if we are not attached to our window 21325 final AttachInfo attachInfo = mAttachInfo; 21326 if (attachInfo != null) { 21327 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 21328 } 21329 } 21330 21331 /** 21332 * <p>Cause an invalidate of the specified area to happen on the next animation 21333 * time step, typically the next display frame.</p> 21334 * 21335 * <p>This method can be invoked from outside of the UI thread 21336 * only when this View is attached to a window.</p> 21337 * 21338 * @param left The left coordinate of the rectangle to invalidate. 21339 * @param top The top coordinate of the rectangle to invalidate. 21340 * @param right The right coordinate of the rectangle to invalidate. 21341 * @param bottom The bottom coordinate of the rectangle to invalidate. 21342 * 21343 * @see #invalidate(int, int, int, int) 21344 * @see #invalidate(Rect) 21345 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)21346 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 21347 // We try only with the AttachInfo because there's no point in invalidating 21348 // if we are not attached to our window 21349 final AttachInfo attachInfo = mAttachInfo; 21350 if (attachInfo != null) { 21351 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 21352 info.target = this; 21353 info.left = left; 21354 info.top = top; 21355 info.right = right; 21356 info.bottom = bottom; 21357 21358 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 21359 } 21360 } 21361 21362 /** 21363 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 21364 * This event is sent at most once every 21365 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 21366 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)21367 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 21368 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 21369 AccessibilityEvent event = 21370 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 21371 event.setScrollDeltaX(dx); 21372 event.setScrollDeltaY(dy); 21373 sendAccessibilityEventUnchecked(event); 21374 } 21375 } 21376 21377 /** 21378 * Called by a parent to request that a child update its values for mScrollX 21379 * and mScrollY if necessary. This will typically be done if the child is 21380 * animating a scroll using a {@link android.widget.Scroller Scroller} 21381 * object. 21382 */ computeScroll()21383 public void computeScroll() { 21384 } 21385 21386 /** 21387 * <p>Indicate whether the horizontal edges are faded when the view is 21388 * scrolled horizontally.</p> 21389 * 21390 * @return true if the horizontal edges should are faded on scroll, false 21391 * otherwise 21392 * 21393 * @see #setHorizontalFadingEdgeEnabled(boolean) 21394 * 21395 * @attr ref android.R.styleable#View_requiresFadingEdge 21396 */ isHorizontalFadingEdgeEnabled()21397 public boolean isHorizontalFadingEdgeEnabled() { 21398 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 21399 } 21400 21401 /** 21402 * <p>Define whether the horizontal edges should be faded when this view 21403 * is scrolled horizontally.</p> 21404 * 21405 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 21406 * be faded when the view is scrolled 21407 * horizontally 21408 * 21409 * @see #isHorizontalFadingEdgeEnabled() 21410 * 21411 * @attr ref android.R.styleable#View_requiresFadingEdge 21412 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)21413 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 21414 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 21415 if (horizontalFadingEdgeEnabled) { 21416 initScrollCache(); 21417 } 21418 21419 mViewFlags ^= FADING_EDGE_HORIZONTAL; 21420 } 21421 } 21422 21423 /** 21424 * <p>Indicate whether the vertical edges are faded when the view is 21425 * scrolled horizontally.</p> 21426 * 21427 * @return true if the vertical edges should are faded on scroll, false 21428 * otherwise 21429 * 21430 * @see #setVerticalFadingEdgeEnabled(boolean) 21431 * 21432 * @attr ref android.R.styleable#View_requiresFadingEdge 21433 */ isVerticalFadingEdgeEnabled()21434 public boolean isVerticalFadingEdgeEnabled() { 21435 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 21436 } 21437 21438 /** 21439 * <p>Define whether the vertical edges should be faded when this view 21440 * is scrolled vertically.</p> 21441 * 21442 * @param verticalFadingEdgeEnabled true if the vertical edges should 21443 * be faded when the view is scrolled 21444 * vertically 21445 * 21446 * @see #isVerticalFadingEdgeEnabled() 21447 * 21448 * @attr ref android.R.styleable#View_requiresFadingEdge 21449 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)21450 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 21451 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 21452 if (verticalFadingEdgeEnabled) { 21453 initScrollCache(); 21454 } 21455 21456 mViewFlags ^= FADING_EDGE_VERTICAL; 21457 } 21458 } 21459 21460 /** 21461 * Get the fading edge flags, used for inspection. 21462 * 21463 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 21464 * or {@link #FADING_EDGE_HORIZONTAL} 21465 * @hide 21466 */ 21467 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 21468 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 21469 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 21470 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 21471 }) getFadingEdge()21472 public int getFadingEdge() { 21473 return mViewFlags & FADING_EDGE_MASK; 21474 } 21475 21476 /** 21477 * Get the fading edge length, used for inspection 21478 * 21479 * @return The fading edge length or 0 21480 * @hide 21481 */ 21482 @InspectableProperty getFadingEdgeLength()21483 public int getFadingEdgeLength() { 21484 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 21485 return mScrollCache.fadingEdgeLength; 21486 } 21487 return 0; 21488 } 21489 21490 /** 21491 * Returns the strength, or intensity, of the top faded edge. The strength is 21492 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21493 * returns 0.0 or 1.0 but no value in between. 21494 * 21495 * Subclasses should override this method to provide a smoother fade transition 21496 * when scrolling occurs. 21497 * 21498 * @return the intensity of the top fade as a float between 0.0f and 1.0f 21499 */ getTopFadingEdgeStrength()21500 protected float getTopFadingEdgeStrength() { 21501 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 21502 } 21503 21504 /** 21505 * Returns the strength, or intensity, of the bottom faded edge. The strength is 21506 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21507 * returns 0.0 or 1.0 but no value in between. 21508 * 21509 * Subclasses should override this method to provide a smoother fade transition 21510 * when scrolling occurs. 21511 * 21512 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 21513 */ getBottomFadingEdgeStrength()21514 protected float getBottomFadingEdgeStrength() { 21515 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 21516 computeVerticalScrollRange() ? 1.0f : 0.0f; 21517 } 21518 21519 /** 21520 * Returns the strength, or intensity, of the left faded edge. The strength is 21521 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21522 * returns 0.0 or 1.0 but no value in between. 21523 * 21524 * Subclasses should override this method to provide a smoother fade transition 21525 * when scrolling occurs. 21526 * 21527 * @return the intensity of the left fade as a float between 0.0f and 1.0f 21528 */ getLeftFadingEdgeStrength()21529 protected float getLeftFadingEdgeStrength() { 21530 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 21531 } 21532 21533 /** 21534 * Returns the strength, or intensity, of the right faded edge. The strength is 21535 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21536 * returns 0.0 or 1.0 but no value in between. 21537 * 21538 * Subclasses should override this method to provide a smoother fade transition 21539 * when scrolling occurs. 21540 * 21541 * @return the intensity of the right fade as a float between 0.0f and 1.0f 21542 */ getRightFadingEdgeStrength()21543 protected float getRightFadingEdgeStrength() { 21544 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 21545 computeHorizontalScrollRange() ? 1.0f : 0.0f; 21546 } 21547 21548 /** 21549 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 21550 * scrollbar is not drawn by default.</p> 21551 * 21552 * @return true if the horizontal scrollbar should be painted, false 21553 * otherwise 21554 * 21555 * @see #setHorizontalScrollBarEnabled(boolean) 21556 */ isHorizontalScrollBarEnabled()21557 public boolean isHorizontalScrollBarEnabled() { 21558 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 21559 } 21560 21561 /** 21562 * <p>Define whether the horizontal scrollbar should be drawn or not. The 21563 * scrollbar is not drawn by default.</p> 21564 * 21565 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 21566 * be painted 21567 * 21568 * @see #isHorizontalScrollBarEnabled() 21569 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)21570 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 21571 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 21572 mViewFlags ^= SCROLLBARS_HORIZONTAL; 21573 computeOpaqueFlags(); 21574 resolvePadding(); 21575 } 21576 } 21577 21578 /** 21579 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 21580 * scrollbar is not drawn by default.</p> 21581 * 21582 * @return true if the vertical scrollbar should be painted, false 21583 * otherwise 21584 * 21585 * @see #setVerticalScrollBarEnabled(boolean) 21586 */ isVerticalScrollBarEnabled()21587 public boolean isVerticalScrollBarEnabled() { 21588 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 21589 } 21590 21591 /** 21592 * <p>Define whether the vertical scrollbar should be drawn or not. The 21593 * scrollbar is not drawn by default.</p> 21594 * 21595 * @param verticalScrollBarEnabled true if the vertical scrollbar should 21596 * be painted 21597 * 21598 * @see #isVerticalScrollBarEnabled() 21599 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)21600 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 21601 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 21602 mViewFlags ^= SCROLLBARS_VERTICAL; 21603 computeOpaqueFlags(); 21604 resolvePadding(); 21605 } 21606 } 21607 21608 /** 21609 * @hide 21610 */ 21611 @UnsupportedAppUsage recomputePadding()21612 protected void recomputePadding() { 21613 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 21614 } 21615 21616 /** 21617 * Define whether scrollbars will fade when the view is not scrolling. 21618 * 21619 * @param fadeScrollbars whether to enable fading 21620 * 21621 * @attr ref android.R.styleable#View_fadeScrollbars 21622 */ setScrollbarFadingEnabled(boolean fadeScrollbars)21623 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 21624 initScrollCache(); 21625 final ScrollabilityCache scrollabilityCache = mScrollCache; 21626 scrollabilityCache.fadeScrollBars = fadeScrollbars; 21627 if (fadeScrollbars) { 21628 scrollabilityCache.state = ScrollabilityCache.OFF; 21629 } else { 21630 scrollabilityCache.state = ScrollabilityCache.ON; 21631 } 21632 } 21633 21634 /** 21635 * 21636 * Returns true if scrollbars will fade when this view is not scrolling 21637 * 21638 * @return true if scrollbar fading is enabled 21639 * 21640 * @attr ref android.R.styleable#View_fadeScrollbars 21641 */ isScrollbarFadingEnabled()21642 public boolean isScrollbarFadingEnabled() { 21643 return mScrollCache != null && mScrollCache.fadeScrollBars; 21644 } 21645 21646 /** 21647 * 21648 * Returns the delay before scrollbars fade. 21649 * 21650 * @return the delay before scrollbars fade 21651 * 21652 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 21653 */ 21654 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()21655 public int getScrollBarDefaultDelayBeforeFade() { 21656 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 21657 mScrollCache.scrollBarDefaultDelayBeforeFade; 21658 } 21659 21660 /** 21661 * Define the delay before scrollbars fade. 21662 * 21663 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 21664 * 21665 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 21666 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)21667 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 21668 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 21669 } 21670 21671 /** 21672 * 21673 * Returns the scrollbar fade duration. 21674 * 21675 * @return the scrollbar fade duration, in milliseconds 21676 * 21677 * @attr ref android.R.styleable#View_scrollbarFadeDuration 21678 */ 21679 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()21680 public int getScrollBarFadeDuration() { 21681 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 21682 mScrollCache.scrollBarFadeDuration; 21683 } 21684 21685 /** 21686 * Define the scrollbar fade duration. 21687 * 21688 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 21689 * 21690 * @attr ref android.R.styleable#View_scrollbarFadeDuration 21691 */ setScrollBarFadeDuration(int scrollBarFadeDuration)21692 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 21693 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 21694 } 21695 21696 /** 21697 * 21698 * Returns the scrollbar size. 21699 * 21700 * @return the scrollbar size 21701 * 21702 * @attr ref android.R.styleable#View_scrollbarSize 21703 */ 21704 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()21705 public int getScrollBarSize() { 21706 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 21707 mScrollCache.scrollBarSize; 21708 } 21709 21710 /** 21711 * Define the scrollbar size. 21712 * 21713 * @param scrollBarSize - the scrollbar size 21714 * 21715 * @attr ref android.R.styleable#View_scrollbarSize 21716 */ setScrollBarSize(int scrollBarSize)21717 public void setScrollBarSize(int scrollBarSize) { 21718 getScrollCache().scrollBarSize = scrollBarSize; 21719 } 21720 21721 /** 21722 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 21723 * inset. When inset, they add to the padding of the view. And the scrollbars 21724 * can be drawn inside the padding area or on the edge of the view. For example, 21725 * if a view has a background drawable and you want to draw the scrollbars 21726 * inside the padding specified by the drawable, you can use 21727 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 21728 * appear at the edge of the view, ignoring the padding, then you can use 21729 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 21730 * @param style the style of the scrollbars. Should be one of 21731 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 21732 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 21733 * @see #SCROLLBARS_INSIDE_OVERLAY 21734 * @see #SCROLLBARS_INSIDE_INSET 21735 * @see #SCROLLBARS_OUTSIDE_OVERLAY 21736 * @see #SCROLLBARS_OUTSIDE_INSET 21737 * 21738 * @attr ref android.R.styleable#View_scrollbarStyle 21739 */ setScrollBarStyle(@crollBarStyle int style)21740 public void setScrollBarStyle(@ScrollBarStyle int style) { 21741 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 21742 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 21743 computeOpaqueFlags(); 21744 resolvePadding(); 21745 } 21746 } 21747 21748 /** 21749 * <p>Returns the current scrollbar style.</p> 21750 * @return the current scrollbar style 21751 * @see #SCROLLBARS_INSIDE_OVERLAY 21752 * @see #SCROLLBARS_INSIDE_INSET 21753 * @see #SCROLLBARS_OUTSIDE_OVERLAY 21754 * @see #SCROLLBARS_OUTSIDE_INSET 21755 * 21756 * @attr ref android.R.styleable#View_scrollbarStyle 21757 */ 21758 @ViewDebug.ExportedProperty(mapping = { 21759 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 21760 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 21761 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 21762 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 21763 }) 21764 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 21765 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 21766 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 21767 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 21768 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 21769 }) 21770 @ScrollBarStyle getScrollBarStyle()21771 public int getScrollBarStyle() { 21772 return mViewFlags & SCROLLBARS_STYLE_MASK; 21773 } 21774 21775 /** 21776 * <p>Compute the horizontal range that the horizontal scrollbar 21777 * represents.</p> 21778 * 21779 * <p>The range is expressed in arbitrary units that must be the same as the 21780 * units used by {@link #computeHorizontalScrollExtent()} and 21781 * {@link #computeHorizontalScrollOffset()}.</p> 21782 * 21783 * <p>The default range is the drawing width of this view.</p> 21784 * 21785 * @return the total horizontal range represented by the horizontal 21786 * scrollbar 21787 * 21788 * @see #computeHorizontalScrollExtent() 21789 * @see #computeHorizontalScrollOffset() 21790 */ computeHorizontalScrollRange()21791 protected int computeHorizontalScrollRange() { 21792 return getWidth(); 21793 } 21794 21795 /** 21796 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 21797 * within the horizontal range. This value is used to compute the position 21798 * of the thumb within the scrollbar's track.</p> 21799 * 21800 * <p>The range is expressed in arbitrary units that must be the same as the 21801 * units used by {@link #computeHorizontalScrollRange()} and 21802 * {@link #computeHorizontalScrollExtent()}.</p> 21803 * 21804 * <p>The default offset is the scroll offset of this view.</p> 21805 * 21806 * @return the horizontal offset of the scrollbar's thumb 21807 * 21808 * @see #computeHorizontalScrollRange() 21809 * @see #computeHorizontalScrollExtent() 21810 */ computeHorizontalScrollOffset()21811 protected int computeHorizontalScrollOffset() { 21812 return mScrollX; 21813 } 21814 21815 /** 21816 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 21817 * within the horizontal range. This value is used to compute the length 21818 * of the thumb within the scrollbar's track.</p> 21819 * 21820 * <p>The range is expressed in arbitrary units that must be the same as the 21821 * units used by {@link #computeHorizontalScrollRange()} and 21822 * {@link #computeHorizontalScrollOffset()}.</p> 21823 * 21824 * <p>The default extent is the drawing width of this view.</p> 21825 * 21826 * @return the horizontal extent of the scrollbar's thumb 21827 * 21828 * @see #computeHorizontalScrollRange() 21829 * @see #computeHorizontalScrollOffset() 21830 */ computeHorizontalScrollExtent()21831 protected int computeHorizontalScrollExtent() { 21832 return getWidth(); 21833 } 21834 21835 /** 21836 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 21837 * 21838 * <p>The range is expressed in arbitrary units that must be the same as the 21839 * units used by {@link #computeVerticalScrollExtent()} and 21840 * {@link #computeVerticalScrollOffset()}.</p> 21841 * 21842 * @return the total vertical range represented by the vertical scrollbar 21843 * 21844 * <p>The default range is the drawing height of this view.</p> 21845 * 21846 * @see #computeVerticalScrollExtent() 21847 * @see #computeVerticalScrollOffset() 21848 */ computeVerticalScrollRange()21849 protected int computeVerticalScrollRange() { 21850 return getHeight(); 21851 } 21852 21853 /** 21854 * <p>Compute the vertical offset of the vertical scrollbar's thumb 21855 * within the horizontal range. This value is used to compute the position 21856 * of the thumb within the scrollbar's track.</p> 21857 * 21858 * <p>The range is expressed in arbitrary units that must be the same as the 21859 * units used by {@link #computeVerticalScrollRange()} and 21860 * {@link #computeVerticalScrollExtent()}.</p> 21861 * 21862 * <p>The default offset is the scroll offset of this view.</p> 21863 * 21864 * @return the vertical offset of the scrollbar's thumb 21865 * 21866 * @see #computeVerticalScrollRange() 21867 * @see #computeVerticalScrollExtent() 21868 */ computeVerticalScrollOffset()21869 protected int computeVerticalScrollOffset() { 21870 return mScrollY; 21871 } 21872 21873 /** 21874 * <p>Compute the vertical extent of the vertical scrollbar's thumb 21875 * within the vertical range. This value is used to compute the length 21876 * of the thumb within the scrollbar's track.</p> 21877 * 21878 * <p>The range is expressed in arbitrary units that must be the same as the 21879 * units used by {@link #computeVerticalScrollRange()} and 21880 * {@link #computeVerticalScrollOffset()}.</p> 21881 * 21882 * <p>The default extent is the drawing height of this view.</p> 21883 * 21884 * @return the vertical extent of the scrollbar's thumb 21885 * 21886 * @see #computeVerticalScrollRange() 21887 * @see #computeVerticalScrollOffset() 21888 */ computeVerticalScrollExtent()21889 protected int computeVerticalScrollExtent() { 21890 return getHeight(); 21891 } 21892 21893 /** 21894 * Check if this view can be scrolled horizontally in a certain direction. 21895 * 21896 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 21897 * in response to user input or not. 21898 * 21899 * @param direction Negative to check scrolling left, positive to check scrolling right. 21900 * @return true if this view can be scrolled in the specified direction, false otherwise. 21901 */ canScrollHorizontally(int direction)21902 public boolean canScrollHorizontally(int direction) { 21903 final int offset = computeHorizontalScrollOffset(); 21904 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 21905 if (range == 0) return false; 21906 if (direction < 0) { 21907 return offset > 0; 21908 } else { 21909 return offset < range - 1; 21910 } 21911 } 21912 21913 /** 21914 * Check if this view can be scrolled vertically in a certain direction. 21915 * 21916 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 21917 * in response to user input or not. 21918 * 21919 * @param direction Negative to check scrolling up, positive to check scrolling down. 21920 * @return true if this view can be scrolled in the specified direction, false otherwise. 21921 */ canScrollVertically(int direction)21922 public boolean canScrollVertically(int direction) { 21923 final int offset = computeVerticalScrollOffset(); 21924 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 21925 if (range == 0) return false; 21926 if (direction < 0) { 21927 return offset > 0; 21928 } else { 21929 return offset < range - 1; 21930 } 21931 } 21932 getScrollIndicatorBounds(@onNull Rect out)21933 void getScrollIndicatorBounds(@NonNull Rect out) { 21934 out.left = mScrollX; 21935 out.right = mScrollX + mRight - mLeft; 21936 out.top = mScrollY; 21937 out.bottom = mScrollY + mBottom - mTop; 21938 } 21939 onDrawScrollIndicators(@onNull Canvas c)21940 private void onDrawScrollIndicators(@NonNull Canvas c) { 21941 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 21942 // No scroll indicators enabled. 21943 return; 21944 } 21945 21946 final Drawable dr = mScrollIndicatorDrawable; 21947 if (dr == null) { 21948 // Scroll indicators aren't supported here. 21949 return; 21950 } 21951 21952 if (mAttachInfo == null) { 21953 // View is not attached. 21954 return; 21955 } 21956 21957 final int h = dr.getIntrinsicHeight(); 21958 final int w = dr.getIntrinsicWidth(); 21959 final Rect rect = mAttachInfo.mTmpInvalRect; 21960 getScrollIndicatorBounds(rect); 21961 21962 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 21963 final boolean canScrollUp = canScrollVertically(-1); 21964 if (canScrollUp) { 21965 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 21966 dr.draw(c); 21967 } 21968 } 21969 21970 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 21971 final boolean canScrollDown = canScrollVertically(1); 21972 if (canScrollDown) { 21973 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 21974 dr.draw(c); 21975 } 21976 } 21977 21978 final int leftRtl; 21979 final int rightRtl; 21980 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 21981 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 21982 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 21983 } else { 21984 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 21985 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 21986 } 21987 21988 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 21989 if ((mPrivateFlags3 & leftMask) != 0) { 21990 final boolean canScrollLeft = canScrollHorizontally(-1); 21991 if (canScrollLeft) { 21992 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 21993 dr.draw(c); 21994 } 21995 } 21996 21997 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 21998 if ((mPrivateFlags3 & rightMask) != 0) { 21999 final boolean canScrollRight = canScrollHorizontally(1); 22000 if (canScrollRight) { 22001 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 22002 dr.draw(c); 22003 } 22004 } 22005 } 22006 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)22007 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 22008 @Nullable Rect touchBounds) { 22009 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 22010 if (bounds == null) { 22011 return; 22012 } 22013 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 22014 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 22015 && !isVerticalScrollBarHidden(); 22016 final int size = getHorizontalScrollbarHeight(); 22017 final int verticalScrollBarGap = drawVerticalScrollBar ? 22018 getVerticalScrollbarWidth() : 0; 22019 final int width = mRight - mLeft; 22020 final int height = mBottom - mTop; 22021 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 22022 bounds.left = mScrollX + (mPaddingLeft & inside); 22023 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 22024 bounds.bottom = bounds.top + size; 22025 22026 if (touchBounds == null) { 22027 return; 22028 } 22029 if (touchBounds != bounds) { 22030 touchBounds.set(bounds); 22031 } 22032 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 22033 if (touchBounds.height() < minTouchTarget) { 22034 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 22035 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 22036 touchBounds.top = touchBounds.bottom - minTouchTarget; 22037 } 22038 if (touchBounds.width() < minTouchTarget) { 22039 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 22040 touchBounds.left -= adjust; 22041 touchBounds.right = touchBounds.left + minTouchTarget; 22042 } 22043 } 22044 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)22045 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 22046 if (mRoundScrollbarRenderer == null) { 22047 getStraightVerticalScrollBarBounds(bounds, touchBounds); 22048 } else { 22049 mRoundScrollbarRenderer.getRoundVerticalScrollBarBounds( 22050 bounds != null ? bounds : touchBounds); 22051 } 22052 } 22053 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)22054 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 22055 @Nullable Rect touchBounds) { 22056 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 22057 if (bounds == null) { 22058 return; 22059 } 22060 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 22061 final int size = getVerticalScrollbarWidth(); 22062 int verticalScrollbarPosition = mVerticalScrollbarPosition; 22063 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 22064 verticalScrollbarPosition = isLayoutRtl() ? 22065 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 22066 } 22067 final int width = mRight - mLeft; 22068 final int height = mBottom - mTop; 22069 switch (verticalScrollbarPosition) { 22070 default: 22071 case SCROLLBAR_POSITION_RIGHT: 22072 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 22073 break; 22074 case SCROLLBAR_POSITION_LEFT: 22075 bounds.left = mScrollX + (mUserPaddingLeft & inside); 22076 break; 22077 } 22078 bounds.top = mScrollY + (mPaddingTop & inside); 22079 bounds.right = bounds.left + size; 22080 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 22081 22082 if (touchBounds == null) { 22083 return; 22084 } 22085 if (touchBounds != bounds) { 22086 touchBounds.set(bounds); 22087 } 22088 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 22089 if (touchBounds.width() < minTouchTarget) { 22090 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 22091 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 22092 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 22093 touchBounds.left = touchBounds.right - minTouchTarget; 22094 } else { 22095 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 22096 touchBounds.right = touchBounds.left + minTouchTarget; 22097 } 22098 } 22099 if (touchBounds.height() < minTouchTarget) { 22100 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 22101 touchBounds.top -= adjust; 22102 touchBounds.bottom = touchBounds.top + minTouchTarget; 22103 } 22104 } 22105 22106 /** 22107 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 22108 * scrollbars are painted only if they have been awakened first.</p> 22109 * 22110 * @param canvas the canvas on which to draw the scrollbars 22111 * 22112 * @see #awakenScrollBars(int) 22113 */ onDrawScrollBars(@onNull Canvas canvas)22114 protected final void onDrawScrollBars(@NonNull Canvas canvas) { 22115 // scrollbars are drawn only when the animation is running 22116 final ScrollabilityCache cache = mScrollCache; 22117 22118 if (cache != null) { 22119 22120 int state = cache.state; 22121 22122 if (state == ScrollabilityCache.OFF) { 22123 return; 22124 } 22125 22126 boolean invalidate = false; 22127 22128 if (state == ScrollabilityCache.FADING) { 22129 // We're fading -- get our fade interpolation 22130 if (cache.interpolatorValues == null) { 22131 cache.interpolatorValues = new float[1]; 22132 } 22133 22134 float[] values = cache.interpolatorValues; 22135 22136 // Stops the animation if we're done 22137 if (cache.scrollBarInterpolator.timeToValues(values) == 22138 Interpolator.Result.FREEZE_END) { 22139 cache.state = ScrollabilityCache.OFF; 22140 } else { 22141 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 22142 } 22143 22144 // This will make the scroll bars inval themselves after 22145 // drawing. We only want this when we're fading so that 22146 // we prevent excessive redraws 22147 invalidate = true; 22148 } else { 22149 // We're just on -- but we may have been fading before so 22150 // reset alpha 22151 cache.scrollBar.mutate().setAlpha(255); 22152 } 22153 22154 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 22155 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 22156 && !isVerticalScrollBarHidden(); 22157 22158 // Fork out the scroll bar drawing for round wearable devices. 22159 if (mRoundScrollbarRenderer != null) { 22160 if (drawVerticalScrollBar) { 22161 final Rect bounds = cache.mScrollBarBounds; 22162 getVerticalScrollBarBounds(bounds, null); 22163 boolean shouldDrawScrollbarAtLeft = 22164 (mVerticalScrollbarPosition == SCROLLBAR_POSITION_LEFT) 22165 || (mVerticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT 22166 && isLayoutRtl()); 22167 22168 mRoundScrollbarRenderer.drawRoundScrollbars( 22169 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds, 22170 shouldDrawScrollbarAtLeft); 22171 if (invalidate) { 22172 invalidate(); 22173 } 22174 } 22175 // Do not draw horizontal scroll bars for round wearable devices. 22176 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 22177 final ScrollBarDrawable scrollBar = cache.scrollBar; 22178 22179 if (drawHorizontalScrollBar) { 22180 scrollBar.setParameters(computeHorizontalScrollRange(), 22181 computeHorizontalScrollOffset(), 22182 computeHorizontalScrollExtent(), false); 22183 final Rect bounds = cache.mScrollBarBounds; 22184 getHorizontalScrollBarBounds(bounds, null); 22185 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 22186 bounds.right, bounds.bottom); 22187 if (invalidate) { 22188 invalidate(bounds); 22189 } 22190 } 22191 22192 if (drawVerticalScrollBar) { 22193 scrollBar.setParameters(computeVerticalScrollRange(), 22194 computeVerticalScrollOffset(), 22195 computeVerticalScrollExtent(), true); 22196 final Rect bounds = cache.mScrollBarBounds; 22197 getVerticalScrollBarBounds(bounds, null); 22198 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 22199 bounds.right, bounds.bottom); 22200 if (invalidate) { 22201 invalidate(bounds); 22202 } 22203 } 22204 } 22205 } 22206 } 22207 22208 /** 22209 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 22210 * FastScroller is visible. 22211 * @return whether to temporarily hide the vertical scrollbar 22212 * @hide 22213 */ isVerticalScrollBarHidden()22214 protected boolean isVerticalScrollBarHidden() { 22215 return false; 22216 } 22217 22218 /** 22219 * <p>Draw the horizontal scrollbar if 22220 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 22221 * 22222 * @param canvas the canvas on which to draw the scrollbar 22223 * @param scrollBar the scrollbar's drawable 22224 * 22225 * @see #isHorizontalScrollBarEnabled() 22226 * @see #computeHorizontalScrollRange() 22227 * @see #computeHorizontalScrollExtent() 22228 * @see #computeHorizontalScrollOffset() 22229 * @hide 22230 */ 22231 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDrawHorizontalScrollBar(@onNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)22232 protected void onDrawHorizontalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, 22233 int l, int t, int r, int b) { 22234 scrollBar.setBounds(l, t, r, b); 22235 scrollBar.draw(canvas); 22236 } 22237 22238 /** 22239 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 22240 * returns true.</p> 22241 * 22242 * @param canvas the canvas on which to draw the scrollbar 22243 * @param scrollBar the scrollbar's drawable 22244 * 22245 * @see #isVerticalScrollBarEnabled() 22246 * @see #computeVerticalScrollRange() 22247 * @see #computeVerticalScrollExtent() 22248 * @see #computeVerticalScrollOffset() 22249 * @hide 22250 */ 22251 @UnsupportedAppUsage onDrawVerticalScrollBar(@onNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)22252 protected void onDrawVerticalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, 22253 int l, int t, int r, int b) { 22254 scrollBar.setBounds(l, t, r, b); 22255 scrollBar.draw(canvas); 22256 } 22257 22258 /** 22259 * Implement this to do your drawing. 22260 * 22261 * @param canvas the canvas on which the background will be drawn 22262 */ onDraw(@onNull Canvas canvas)22263 protected void onDraw(@NonNull Canvas canvas) { 22264 } 22265 22266 /* 22267 * Caller is responsible for calling requestLayout if necessary. 22268 * (This allows addViewInLayout to not request a new layout.) 22269 */ 22270 @UnsupportedAppUsage assignParent(ViewParent parent)22271 void assignParent(ViewParent parent) { 22272 if (mParent == null) { 22273 mParent = parent; 22274 } else if (parent == null) { 22275 mParent = null; 22276 } else { 22277 throw new RuntimeException("view " + this + " being added, but" 22278 + " it already has a parent"); 22279 } 22280 } 22281 22282 /** 22283 * This is called when the view is attached to a window. At this point it 22284 * has a Surface and will start drawing. Note that this function is 22285 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 22286 * however it may be called any time before the first onDraw -- including 22287 * before or after {@link #onMeasure(int, int)}. 22288 * 22289 * @see #onDetachedFromWindow() 22290 */ 22291 @CallSuper onAttachedToWindow()22292 protected void onAttachedToWindow() { 22293 if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 22294 mParent.requestTransparentRegion(this); 22295 } 22296 22297 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 22298 22299 jumpDrawablesToCurrentState(); 22300 22301 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 22302 resetSubtreeAccessibilityStateChanged(); 22303 22304 // rebuild, since Outline not maintained while View is detached 22305 rebuildOutline(); 22306 22307 if (isFocused()) { 22308 notifyFocusChangeToImeFocusController(true /* hasFocus */); 22309 } 22310 22311 if (sTraceLayoutSteps) { 22312 setTraversalTracingEnabled(true); 22313 } 22314 if (sTraceRequestLayoutClass != null 22315 && sTraceRequestLayoutClass.equals(getClass().getSimpleName())) { 22316 setRelayoutTracingEnabled(true); 22317 } 22318 } 22319 22320 /** 22321 * Resolve all RTL related properties. 22322 * 22323 * @return true if resolution of RTL properties has been done 22324 * 22325 * @hide 22326 */ resolveRtlPropertiesIfNeeded()22327 public boolean resolveRtlPropertiesIfNeeded() { 22328 if (!needRtlPropertiesResolution()) return false; 22329 22330 // Order is important here: LayoutDirection MUST be resolved first 22331 if (!isLayoutDirectionResolved()) { 22332 resolveLayoutDirection(); 22333 resolveLayoutParams(); 22334 } 22335 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 22336 if (!isTextDirectionResolved()) { 22337 resolveTextDirection(); 22338 } 22339 if (!isTextAlignmentResolved()) { 22340 resolveTextAlignment(); 22341 } 22342 // Should resolve Drawables before Padding because we need the layout direction of the 22343 // Drawable to correctly resolve Padding. 22344 if (!areDrawablesResolved()) { 22345 resolveDrawables(); 22346 } 22347 if (!isPaddingResolved()) { 22348 resolvePadding(); 22349 } 22350 onRtlPropertiesChanged(getLayoutDirection()); 22351 return true; 22352 } 22353 22354 /** 22355 * Reset resolution of all RTL related properties. 22356 * 22357 * @hide 22358 */ 22359 @TestApi resetRtlProperties()22360 public void resetRtlProperties() { 22361 resetResolvedLayoutDirection(); 22362 resetResolvedTextDirection(); 22363 resetResolvedTextAlignment(); 22364 resetResolvedPadding(); 22365 resetResolvedDrawables(); 22366 } 22367 22368 /** 22369 * @see #onScreenStateChanged(int) 22370 */ dispatchScreenStateChanged(int screenState)22371 void dispatchScreenStateChanged(int screenState) { 22372 onScreenStateChanged(screenState); 22373 } 22374 22375 /** 22376 * This method is called whenever the state of the screen this view is 22377 * attached to changes. A state change will usually occurs when the screen 22378 * turns on or off (whether it happens automatically or the user does it 22379 * manually.) 22380 * 22381 * @param screenState The new state of the screen. Can be either 22382 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 22383 */ onScreenStateChanged(int screenState)22384 public void onScreenStateChanged(int screenState) { 22385 } 22386 22387 /** 22388 * @see #onMovedToDisplay(int, Configuration) 22389 */ dispatchMovedToDisplay(Display display, Configuration config)22390 void dispatchMovedToDisplay(Display display, Configuration config) { 22391 mAttachInfo.mDisplay = display; 22392 mAttachInfo.mDisplayState = display.getState(); 22393 onMovedToDisplay(display.getDisplayId(), config); 22394 } 22395 22396 /** 22397 * Called by the system when the hosting activity is moved from one display to another without 22398 * recreation. This means that the activity is declared to handle all changes to configuration 22399 * that happened when it was switched to another display, so it wasn't destroyed and created 22400 * again. 22401 * 22402 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 22403 * applied configuration actually changed. It is up to app developer to choose whether to handle 22404 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 22405 * call. 22406 * 22407 * <p>Use this callback to track changes to the displays if some functionality relies on an 22408 * association with some display properties. 22409 * 22410 * @param displayId The id of the display to which the view was moved. 22411 * @param config Configuration of the resources on new display after move. 22412 * 22413 * @see #onConfigurationChanged(Configuration) 22414 * @hide 22415 */ onMovedToDisplay(int displayId, Configuration config)22416 public void onMovedToDisplay(int displayId, Configuration config) { 22417 } 22418 22419 /** 22420 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 22421 */ 22422 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hasRtlSupport()22423 private boolean hasRtlSupport() { 22424 return mContext.getApplicationInfo().hasRtlSupport(); 22425 } 22426 22427 /** 22428 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 22429 * RTL not supported) 22430 */ isRtlCompatibilityMode()22431 private boolean isRtlCompatibilityMode() { 22432 return !hasRtlSupport(); 22433 } 22434 22435 /** 22436 * @return true if RTL properties need resolution. 22437 * 22438 */ needRtlPropertiesResolution()22439 private boolean needRtlPropertiesResolution() { 22440 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 22441 } 22442 22443 /** 22444 * Called when any RTL property (layout direction or text direction or text alignment) has 22445 * been changed. 22446 * 22447 * Subclasses need to override this method to take care of cached information that depends on the 22448 * resolved layout direction, or to inform child views that inherit their layout direction. 22449 * 22450 * The default implementation does nothing. 22451 * 22452 * @param layoutDirection the direction of the layout 22453 * 22454 * @see #LAYOUT_DIRECTION_LTR 22455 * @see #LAYOUT_DIRECTION_RTL 22456 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)22457 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 22458 } 22459 22460 /** 22461 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 22462 * that the parent directionality can and will be resolved before its children. 22463 * 22464 * @return true if resolution has been done, false otherwise. 22465 * 22466 * @hide 22467 */ resolveLayoutDirection()22468 public boolean resolveLayoutDirection() { 22469 // Clear any previous layout direction resolution 22470 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 22471 22472 if (hasRtlSupport()) { 22473 // Set resolved depending on layout direction 22474 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 22475 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 22476 case LAYOUT_DIRECTION_INHERIT: 22477 // We cannot resolve yet. LTR is by default and let the resolution happen again 22478 // later to get the correct resolved value 22479 if (!canResolveLayoutDirection()) return false; 22480 22481 // Parent has not yet resolved, LTR is still the default 22482 try { 22483 if (!mParent.isLayoutDirectionResolved()) return false; 22484 22485 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 22486 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 22487 } 22488 } catch (AbstractMethodError e) { 22489 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22490 " does not fully implement ViewParent", e); 22491 } 22492 break; 22493 case LAYOUT_DIRECTION_RTL: 22494 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 22495 break; 22496 case LAYOUT_DIRECTION_LOCALE: 22497 if((LAYOUT_DIRECTION_RTL == 22498 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 22499 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 22500 } 22501 break; 22502 default: 22503 // Nothing to do, LTR by default 22504 } 22505 } 22506 22507 // Set to resolved 22508 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 22509 return true; 22510 } 22511 22512 /** 22513 * Check if layout direction resolution can be done. 22514 * 22515 * @return true if layout direction resolution can be done otherwise return false. 22516 */ canResolveLayoutDirection()22517 public boolean canResolveLayoutDirection() { 22518 switch (getRawLayoutDirection()) { 22519 case LAYOUT_DIRECTION_INHERIT: 22520 if (mParent != null) { 22521 try { 22522 return mParent.canResolveLayoutDirection(); 22523 } catch (AbstractMethodError e) { 22524 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22525 " does not fully implement ViewParent", e); 22526 } 22527 } 22528 return false; 22529 22530 default: 22531 return true; 22532 } 22533 } 22534 22535 /** 22536 * Reset the resolved layout direction. Layout direction will be resolved during a call to 22537 * {@link #onMeasure(int, int)}. 22538 * 22539 * @hide 22540 */ 22541 @TestApi resetResolvedLayoutDirection()22542 public void resetResolvedLayoutDirection() { 22543 // Reset the current resolved bits 22544 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 22545 } 22546 22547 /** 22548 * @return true if the layout direction is inherited. 22549 * 22550 * @hide 22551 */ isLayoutDirectionInherited()22552 public boolean isLayoutDirectionInherited() { 22553 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 22554 } 22555 22556 /** 22557 * @return true if layout direction has been resolved. 22558 */ isLayoutDirectionResolved()22559 public boolean isLayoutDirectionResolved() { 22560 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 22561 } 22562 22563 /** 22564 * Return if padding has been resolved 22565 * 22566 * @hide 22567 */ 22568 @UnsupportedAppUsage isPaddingResolved()22569 boolean isPaddingResolved() { 22570 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 22571 } 22572 22573 /** 22574 * Resolves padding depending on layout direction, if applicable, and 22575 * recomputes internal padding values to adjust for scroll bars. 22576 * 22577 * @hide 22578 */ 22579 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolvePadding()22580 public void resolvePadding() { 22581 final int resolvedLayoutDirection = getLayoutDirection(); 22582 22583 if (!isRtlCompatibilityMode()) { 22584 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 22585 // If start / end padding are defined, they will be resolved (hence overriding) to 22586 // left / right or right / left depending on the resolved layout direction. 22587 // If start / end padding are not defined, use the left / right ones. 22588 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 22589 Rect padding = sThreadLocal.get(); 22590 if (padding == null) { 22591 padding = new Rect(); 22592 sThreadLocal.set(padding); 22593 } 22594 mBackground.getPadding(padding); 22595 if (!mLeftPaddingDefined) { 22596 mUserPaddingLeftInitial = padding.left; 22597 } 22598 if (!mRightPaddingDefined) { 22599 mUserPaddingRightInitial = padding.right; 22600 } 22601 } 22602 switch (resolvedLayoutDirection) { 22603 case LAYOUT_DIRECTION_RTL: 22604 if (mUserPaddingStart != UNDEFINED_PADDING) { 22605 mUserPaddingRight = mUserPaddingStart; 22606 } else { 22607 mUserPaddingRight = mUserPaddingRightInitial; 22608 } 22609 if (mUserPaddingEnd != UNDEFINED_PADDING) { 22610 mUserPaddingLeft = mUserPaddingEnd; 22611 } else { 22612 mUserPaddingLeft = mUserPaddingLeftInitial; 22613 } 22614 break; 22615 case LAYOUT_DIRECTION_LTR: 22616 default: 22617 if (mUserPaddingStart != UNDEFINED_PADDING) { 22618 mUserPaddingLeft = mUserPaddingStart; 22619 } else { 22620 mUserPaddingLeft = mUserPaddingLeftInitial; 22621 } 22622 if (mUserPaddingEnd != UNDEFINED_PADDING) { 22623 mUserPaddingRight = mUserPaddingEnd; 22624 } else { 22625 mUserPaddingRight = mUserPaddingRightInitial; 22626 } 22627 } 22628 22629 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 22630 } 22631 22632 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 22633 onRtlPropertiesChanged(resolvedLayoutDirection); 22634 22635 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 22636 } 22637 22638 /** 22639 * Reset the resolved layout direction. 22640 * 22641 * @hide 22642 */ 22643 @TestApi resetResolvedPadding()22644 public void resetResolvedPadding() { 22645 resetResolvedPaddingInternal(); 22646 } 22647 22648 /** 22649 * Used when we only want to reset *this* view's padding and not trigger overrides 22650 * in ViewGroup that reset children too. 22651 */ resetResolvedPaddingInternal()22652 void resetResolvedPaddingInternal() { 22653 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 22654 } 22655 22656 /** 22657 * This is called when the view is detached from a window. At this point it 22658 * no longer has a surface for drawing. 22659 * 22660 * @see #onAttachedToWindow() 22661 */ 22662 @CallSuper onDetachedFromWindow()22663 protected void onDetachedFromWindow() { 22664 } 22665 22666 /** 22667 * This is a framework-internal mirror of onDetachedFromWindow() that's called 22668 * after onDetachedFromWindow(). 22669 * 22670 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 22671 * The super method should be called at the end of the overridden method to ensure 22672 * subclasses are destroyed first 22673 * 22674 * @hide 22675 */ 22676 @CallSuper 22677 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()22678 protected void onDetachedFromWindowInternal() { 22679 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 22680 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 22681 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 22682 22683 removeUnsetPressCallback(); 22684 removeLongPressCallback(); 22685 removePerformClickCallback(); 22686 clearAccessibilityThrottles(); 22687 stopNestedScroll(); 22688 22689 // Anything that started animating right before detach should already 22690 // be in its final state when re-attached. 22691 jumpDrawablesToCurrentState(); 22692 22693 destroyDrawingCache(); 22694 22695 cleanupDraw(); 22696 mCurrentAnimation = null; 22697 22698 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 22699 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 22700 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 22701 hideTooltip(); 22702 } 22703 22704 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 22705 22706 if (mBackgroundRenderNode != null) { 22707 mBackgroundRenderNode.forceEndAnimators(); 22708 } 22709 mRenderNode.forceEndAnimators(); 22710 } 22711 cleanupDraw()22712 private void cleanupDraw() { 22713 resetDisplayList(); 22714 if (mAttachInfo != null) { 22715 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 22716 } 22717 } 22718 invalidateInheritedLayoutMode(int layoutModeOfRoot)22719 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 22720 } 22721 22722 /** 22723 * @return The number of times this view has been attached to a window 22724 */ getWindowAttachCount()22725 protected int getWindowAttachCount() { 22726 return mWindowAttachCount; 22727 } 22728 22729 /** 22730 * Retrieve a unique token identifying the window this view is attached to. 22731 * @return Return the window's token for use in 22732 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 22733 * This token maybe null if this view is not attached to a window. 22734 * @see #isAttachedToWindow() for current window attach state 22735 * @see OnAttachStateChangeListener to listen to window attach/detach state changes 22736 */ getWindowToken()22737 public IBinder getWindowToken() { 22738 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 22739 } 22740 22741 /** 22742 * Retrieve the {@link WindowId} for the window this view is 22743 * currently attached to. 22744 */ getWindowId()22745 public WindowId getWindowId() { 22746 AttachInfo ai = mAttachInfo; 22747 if (ai == null) { 22748 return null; 22749 } 22750 if (ai.mWindowId == null) { 22751 try { 22752 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 22753 if (ai.mIWindowId != null) { 22754 ai.mWindowId = new WindowId(ai.mIWindowId); 22755 } 22756 } catch (RemoteException e) { 22757 } 22758 } 22759 return ai.mWindowId; 22760 } 22761 22762 /** 22763 * Retrieve a unique token identifying the top-level "real" window of 22764 * the window that this view is attached to. That is, this is like 22765 * {@link #getWindowToken}, except if the window this view in is a panel 22766 * window (attached to another containing window), then the token of 22767 * the containing window is returned instead. 22768 * 22769 * @return Returns the associated window token, either 22770 * {@link #getWindowToken()} or the containing window's token. 22771 */ getApplicationWindowToken()22772 public IBinder getApplicationWindowToken() { 22773 AttachInfo ai = mAttachInfo; 22774 if (ai != null) { 22775 IBinder appWindowToken = ai.mPanelParentWindowToken; 22776 if (appWindowToken == null) { 22777 appWindowToken = ai.mWindowToken; 22778 } 22779 return appWindowToken; 22780 } 22781 return null; 22782 } 22783 22784 /** 22785 * Gets the logical display to which the view's window has been attached. 22786 * 22787 * @return The logical display, or null if the view is not currently attached to a window. 22788 */ getDisplay()22789 public Display getDisplay() { 22790 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 22791 } 22792 22793 /** 22794 * Retrieve private session object this view hierarchy is using to 22795 * communicate with the window manager. 22796 * @return the session object to communicate with the window manager 22797 */ 22798 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()22799 /*package*/ IWindowSession getWindowSession() { 22800 return mAttachInfo != null ? mAttachInfo.mSession : null; 22801 } 22802 22803 /** 22804 * Return the window this view is currently attached to. 22805 * @hide 22806 */ getWindow()22807 protected IWindow getWindow() { 22808 return mAttachInfo != null ? mAttachInfo.mWindow : null; 22809 } 22810 22811 /** 22812 * Return the visibility value of the least visible component passed. 22813 */ combineVisibility(int vis1, int vis2)22814 int combineVisibility(int vis1, int vis2) { 22815 // This works because VISIBLE < INVISIBLE < GONE. 22816 return Math.max(vis1, vis2); 22817 } 22818 22819 private boolean mShouldFakeFocus = false; 22820 22821 /** 22822 * Fake send a focus event after attaching to window. 22823 * See {@link android.view.ViewRootImpl#dispatchCompatFakeFocus()} for details. 22824 * @hide 22825 */ fakeFocusAfterAttachingToWindow()22826 public void fakeFocusAfterAttachingToWindow() { 22827 mShouldFakeFocus = true; 22828 } 22829 22830 /** 22831 * @param info the {@link android.view.View.AttachInfo} to associated with 22832 * this view 22833 */ 22834 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)22835 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 22836 mAttachInfo = info; 22837 if (mOverlay != null) { 22838 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 22839 } 22840 mWindowAttachCount++; 22841 // We will need to evaluate the drawable state at least once. 22842 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 22843 if (mFloatingTreeObserver != null) { 22844 info.mTreeObserver.merge(mFloatingTreeObserver); 22845 mFloatingTreeObserver = null; 22846 } 22847 22848 registerPendingFrameMetricsObservers(); 22849 22850 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 22851 mAttachInfo.mScrollContainers.add(this); 22852 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 22853 } 22854 // Transfer all pending runnables. 22855 if (mRunQueue != null) { 22856 mRunQueue.executeActions(info.mHandler); 22857 mRunQueue = null; 22858 } 22859 performCollectViewAttributes(mAttachInfo, visibility); 22860 onAttachedToWindow(); 22861 22862 ListenerInfo li = mListenerInfo; 22863 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 22864 li != null ? li.mOnAttachStateChangeListeners : null; 22865 if (listeners != null && listeners.size() > 0) { 22866 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 22867 // perform the dispatching. The iterator is a safe guard against listeners that 22868 // could mutate the list by calling the various add/remove methods. This prevents 22869 // the array from being modified while we iterate it. 22870 for (OnAttachStateChangeListener listener : listeners) { 22871 listener.onViewAttachedToWindow(this); 22872 } 22873 } 22874 22875 int vis = info.mWindowVisibility; 22876 if (vis != GONE) { 22877 onWindowVisibilityChanged(vis); 22878 if (isShown()) { 22879 // Calling onVisibilityAggregated directly here since the subtree will also 22880 // receive dispatchAttachedToWindow and this same call 22881 onVisibilityAggregated(vis == VISIBLE); 22882 } 22883 } 22884 22885 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 22886 // As all views in the subtree will already receive dispatchAttachedToWindow 22887 // traversing the subtree again here is not desired. 22888 onVisibilityChanged(this, visibility); 22889 22890 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 22891 // If nobody has evaluated the drawable state yet, then do it now. 22892 refreshDrawableState(); 22893 } 22894 needGlobalAttributesUpdate(false); 22895 22896 notifyEnterOrExitForAutoFillIfNeeded(true); 22897 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 22898 22899 if (mShouldFakeFocus) { 22900 getViewRootImpl().dispatchCompatFakeFocus(); 22901 mShouldFakeFocus = false; 22902 } 22903 } 22904 22905 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()22906 void dispatchDetachedFromWindow() { 22907 AttachInfo info = mAttachInfo; 22908 if (info != null) { 22909 int vis = info.mWindowVisibility; 22910 if (vis != GONE) { 22911 onWindowVisibilityChanged(GONE); 22912 if (isShown()) { 22913 // Invoking onVisibilityAggregated directly here since the subtree 22914 // will also receive detached from window 22915 onVisibilityAggregated(false); 22916 } else { 22917 notifyAutofillManagerViewVisibilityChanged(false); 22918 } 22919 } 22920 } 22921 22922 onDetachedFromWindow(); 22923 onDetachedFromWindowInternal(); 22924 22925 if (info != null) { 22926 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 22927 } 22928 22929 ListenerInfo li = mListenerInfo; 22930 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 22931 li != null ? li.mOnAttachStateChangeListeners : null; 22932 if (listeners != null && listeners.size() > 0) { 22933 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 22934 // perform the dispatching. The iterator is a safe guard against listeners that 22935 // could mutate the list by calling the various add/remove methods. This prevents 22936 // the array from being modified while we iterate it. 22937 for (OnAttachStateChangeListener listener : listeners) { 22938 listener.onViewDetachedFromWindow(this); 22939 } 22940 } 22941 22942 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 22943 mAttachInfo.mScrollContainers.remove(this); 22944 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 22945 } 22946 22947 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 22948 updateSensitiveViewsCountIfNeeded(false); 22949 22950 mAttachInfo = null; 22951 if (mOverlay != null) { 22952 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 22953 } 22954 22955 notifyEnterOrExitForAutoFillIfNeeded(false); 22956 22957 if (info != null && !collectPreferKeepClearRects().isEmpty()) { 22958 info.mViewRootImpl.updateKeepClearRectsForView(this); 22959 } 22960 } 22961 22962 /** 22963 * Cancel any deferred high-level input events that were previously posted to the event queue. 22964 * 22965 * <p>Many views post high-level events such as click handlers to the event queue 22966 * to run deferred in order to preserve a desired user experience - clearing visible 22967 * pressed states before executing, etc. This method will abort any events of this nature 22968 * that are currently in flight.</p> 22969 * 22970 * <p>Custom views that generate their own high-level deferred input events should override 22971 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 22972 * 22973 * <p>This will also cancel pending input events for any child views.</p> 22974 * 22975 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 22976 * This will not impact newer events posted after this call that may occur as a result of 22977 * lower-level input events still waiting in the queue. If you are trying to prevent 22978 * double-submitted events for the duration of some sort of asynchronous transaction 22979 * you should also take other steps to protect against unexpected double inputs e.g. calling 22980 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 22981 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 22982 */ cancelPendingInputEvents()22983 public final void cancelPendingInputEvents() { 22984 dispatchCancelPendingInputEvents(); 22985 } 22986 22987 /** 22988 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 22989 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 22990 */ dispatchCancelPendingInputEvents()22991 void dispatchCancelPendingInputEvents() { 22992 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 22993 onCancelPendingInputEvents(); 22994 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 22995 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 22996 " did not call through to super.onCancelPendingInputEvents()"); 22997 } 22998 } 22999 23000 /** 23001 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 23002 * a parent view. 23003 * 23004 * <p>This method is responsible for removing any pending high-level input events that were 23005 * posted to the event queue to run later. Custom view classes that post their own deferred 23006 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 23007 * {@link android.os.Handler} should override this method, call 23008 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 23009 * </p> 23010 */ onCancelPendingInputEvents()23011 public void onCancelPendingInputEvents() { 23012 removePerformClickCallback(); 23013 cancelLongPress(); 23014 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 23015 } 23016 23017 /** 23018 * Store this view hierarchy's frozen state into the given container. 23019 * 23020 * @param container The SparseArray in which to save the view's state. 23021 * 23022 * @see #restoreHierarchyState(android.util.SparseArray) 23023 * @see #dispatchSaveInstanceState(android.util.SparseArray) 23024 * @see #onSaveInstanceState() 23025 */ saveHierarchyState(SparseArray<Parcelable> container)23026 public void saveHierarchyState(SparseArray<Parcelable> container) { 23027 dispatchSaveInstanceState(container); 23028 } 23029 23030 /** 23031 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 23032 * this view and its children. May be overridden to modify how freezing happens to a 23033 * view's children; for example, some views may want to not store state for their children. 23034 * 23035 * @param container The SparseArray in which to save the view's state. 23036 * 23037 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 23038 * @see #saveHierarchyState(android.util.SparseArray) 23039 * @see #onSaveInstanceState() 23040 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)23041 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 23042 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 23043 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 23044 Parcelable state = onSaveInstanceState(); 23045 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 23046 throw new IllegalStateException( 23047 "Derived class did not call super.onSaveInstanceState()"); 23048 } 23049 if (state != null) { 23050 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 23051 // + ": " + state); 23052 container.put(mID, state); 23053 } 23054 } 23055 } 23056 23057 /** 23058 * Hook allowing a view to generate a representation of its internal state 23059 * that can later be used to create a new instance with that same state. 23060 * This state should only contain information that is not persistent or can 23061 * not be reconstructed later. For example, you will never store your 23062 * current position on screen because that will be computed again when a 23063 * new instance of the view is placed in its view hierarchy. 23064 * <p> 23065 * Some examples of things you may store here: the current cursor position 23066 * in a text view (but usually not the text itself since that is stored in a 23067 * content provider or other persistent storage), the currently selected 23068 * item in a list view. 23069 * 23070 * @return Returns a Parcelable object containing the view's current dynamic 23071 * state, or null if there is nothing interesting to save. 23072 * @see #onRestoreInstanceState(Parcelable) 23073 * @see #saveHierarchyState(SparseArray) 23074 * @see #dispatchSaveInstanceState(SparseArray) 23075 * @see #setSaveEnabled(boolean) 23076 */ 23077 @CallSuper onSaveInstanceState()23078 @Nullable protected Parcelable onSaveInstanceState() { 23079 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 23080 if (mStartActivityRequestWho != null || isAutofilled() 23081 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 23082 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 23083 23084 if (mStartActivityRequestWho != null) { 23085 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 23086 } 23087 23088 if (isAutofilled()) { 23089 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 23090 } 23091 23092 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 23093 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 23094 } 23095 23096 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 23097 state.mIsAutofilled = isAutofilled(); 23098 state.mHideHighlight = hideAutofillHighlight(); 23099 state.mAutofillViewId = mAutofillViewId; 23100 return state; 23101 } 23102 return BaseSavedState.EMPTY_STATE; 23103 } 23104 23105 /** 23106 * Restore this view hierarchy's frozen state from the given container. 23107 * 23108 * @param container The SparseArray which holds previously frozen states. 23109 * 23110 * @see #saveHierarchyState(android.util.SparseArray) 23111 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 23112 * @see #onRestoreInstanceState(android.os.Parcelable) 23113 */ restoreHierarchyState(SparseArray<Parcelable> container)23114 public void restoreHierarchyState(SparseArray<Parcelable> container) { 23115 dispatchRestoreInstanceState(container); 23116 } 23117 23118 /** 23119 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 23120 * state for this view and its children. May be overridden to modify how restoring 23121 * happens to a view's children; for example, some views may want to not store state 23122 * for their children. 23123 * 23124 * @param container The SparseArray which holds previously saved state. 23125 * 23126 * @see #dispatchSaveInstanceState(android.util.SparseArray) 23127 * @see #restoreHierarchyState(android.util.SparseArray) 23128 * @see #onRestoreInstanceState(android.os.Parcelable) 23129 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)23130 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 23131 if (mID != NO_ID) { 23132 Parcelable state = container.get(mID); 23133 if (state != null) { 23134 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 23135 // + ": " + state); 23136 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 23137 onRestoreInstanceState(state); 23138 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 23139 throw new IllegalStateException( 23140 "Derived class did not call super.onRestoreInstanceState()"); 23141 } 23142 } 23143 } 23144 } 23145 23146 /** 23147 * Hook allowing a view to re-apply a representation of its internal state that had previously 23148 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 23149 * null state. 23150 * 23151 * @param state The frozen state that had previously been returned by 23152 * {@link #onSaveInstanceState}. 23153 * 23154 * @see #onSaveInstanceState() 23155 * @see #restoreHierarchyState(android.util.SparseArray) 23156 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 23157 */ 23158 @CallSuper onRestoreInstanceState(Parcelable state)23159 protected void onRestoreInstanceState(Parcelable state) { 23160 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 23161 if (state != null && !(state instanceof AbsSavedState)) { 23162 throw new IllegalArgumentException("Wrong state class, expecting View State but " 23163 + "received " + state.getClass().toString() + " instead. This usually happens " 23164 + "when two views of different type have the same id in the same hierarchy. " 23165 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 23166 + "other views do not use the same id."); 23167 } 23168 if (state != null && state instanceof BaseSavedState) { 23169 BaseSavedState baseState = (BaseSavedState) state; 23170 23171 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 23172 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 23173 } 23174 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 23175 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 23176 } 23177 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 23178 // It can happen that views have the same view id and the restoration path will not 23179 // be able to distinguish between them. The autofill id needs to be unique though. 23180 // Hence prevent the same autofill view id from being restored multiple times. 23181 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 23182 23183 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 23184 // Ignore when view already set it through setAutofillId(); 23185 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 23186 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 23187 + "to " + baseState.mAutofillViewId + " because view explicitly set" 23188 + " it to " + mAutofillId); 23189 } 23190 } else { 23191 mAutofillViewId = baseState.mAutofillViewId; 23192 mAutofillId = null; // will be set on demand by getAutofillId() 23193 } 23194 } 23195 } 23196 } 23197 23198 /** 23199 * <p>Return the time at which the drawing of the view hierarchy started.</p> 23200 * 23201 * @return the drawing start time in milliseconds 23202 */ getDrawingTime()23203 public long getDrawingTime() { 23204 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 23205 } 23206 23207 /** 23208 * <p>Enables or disables the duplication of the parent's state into this view. When 23209 * duplication is enabled, this view gets its drawable state from its parent rather 23210 * than from its own internal properties.</p> 23211 * 23212 * <p>Note: in the current implementation, setting this property to true after the 23213 * view was added to a ViewGroup might have no effect at all. This property should 23214 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 23215 * 23216 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 23217 * property is enabled, an exception will be thrown.</p> 23218 * 23219 * <p>Note: if the child view uses and updates additional states which are unknown to the 23220 * parent, these states should not be affected by this method.</p> 23221 * 23222 * @param enabled True to enable duplication of the parent's drawable state, false 23223 * to disable it. 23224 * 23225 * @see #getDrawableState() 23226 * @see #isDuplicateParentStateEnabled() 23227 */ setDuplicateParentStateEnabled(boolean enabled)23228 public void setDuplicateParentStateEnabled(boolean enabled) { 23229 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 23230 } 23231 23232 /** 23233 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 23234 * 23235 * @return True if this view's drawable state is duplicated from the parent, 23236 * false otherwise 23237 * 23238 * @see #getDrawableState() 23239 * @see #setDuplicateParentStateEnabled(boolean) 23240 */ 23241 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()23242 public boolean isDuplicateParentStateEnabled() { 23243 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 23244 } 23245 23246 /** 23247 * <p>Specifies the type of layer backing this view. The layer can be 23248 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 23249 * {@link #LAYER_TYPE_HARDWARE}.</p> 23250 * 23251 * <p>A layer is associated with an optional {@link android.graphics.Paint} 23252 * instance that controls how the layer is composed on screen. The following 23253 * properties of the paint are taken into account when composing the layer:</p> 23254 * <ul> 23255 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 23256 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 23257 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 23258 * </ul> 23259 * 23260 * <p>If this view has an alpha value set to < 1.0 by calling 23261 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 23262 * by this view's alpha value.</p> 23263 * 23264 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 23265 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 23266 * for more information on when and how to use layers.</p> 23267 * 23268 * @param layerType The type of layer to use with this view, must be one of 23269 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 23270 * {@link #LAYER_TYPE_HARDWARE} 23271 * @param paint The paint used to compose the layer. This argument is optional 23272 * and can be null. It is ignored when the layer type is 23273 * {@link #LAYER_TYPE_NONE} 23274 * 23275 * @see #getLayerType() 23276 * @see #LAYER_TYPE_NONE 23277 * @see #LAYER_TYPE_SOFTWARE 23278 * @see #LAYER_TYPE_HARDWARE 23279 * @see #setAlpha(float) 23280 * 23281 * @attr ref android.R.styleable#View_layerType 23282 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)23283 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 23284 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 23285 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 23286 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 23287 } 23288 23289 boolean typeChanged = mRenderNode.setLayerType(layerType); 23290 23291 if (!typeChanged) { 23292 setLayerPaint(paint); 23293 return; 23294 } 23295 23296 if (layerType != LAYER_TYPE_SOFTWARE) { 23297 // Destroy any previous software drawing cache if present 23298 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 23299 // drawing cache created in View#draw when drawing to a SW canvas. 23300 destroyDrawingCache(); 23301 } 23302 23303 mLayerType = layerType; 23304 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 23305 mRenderNode.setLayerPaint(mLayerPaint); 23306 23307 // draw() behaves differently if we are on a layer, so we need to 23308 // invalidate() here 23309 invalidateParentCaches(); 23310 invalidate(true); 23311 } 23312 23313 /** 23314 * Configure the {@link android.graphics.RenderEffect} to apply to this View. 23315 * This will apply a visual effect to the results of the View before it is drawn. For example if 23316 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 23317 * is provided, the contents will be drawn in a separate layer, then this layer will be blurred 23318 * when this View is drawn. 23319 * @param renderEffect to be applied to the View. Passing null clears the previously configured 23320 * {@link RenderEffect} 23321 */ setRenderEffect(@ullable RenderEffect renderEffect)23322 public void setRenderEffect(@Nullable RenderEffect renderEffect) { 23323 if (mRenderNode.setRenderEffect(renderEffect)) { 23324 invalidateViewProperty(true, true); 23325 } 23326 } 23327 23328 /** 23329 * Configure the {@link android.graphics.RenderEffect} to apply to the backdrop contents of this 23330 * View. This will apply a visual effect to the result of the backdrop contents of this View 23331 * before it is drawn. For example if 23332 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 23333 * is provided, the previous content behind this View will be blurred before this View is drawn. 23334 * @param renderEffect to be applied to the View. Passing null clears the previously configured 23335 * {@link RenderEffect} 23336 * @hide 23337 */ setBackdropRenderEffect(@ullable RenderEffect renderEffect)23338 public void setBackdropRenderEffect(@Nullable RenderEffect renderEffect) { 23339 if (mRenderNode.setBackdropRenderEffect(renderEffect)) { 23340 invalidateViewProperty(true, true); 23341 } 23342 } 23343 23344 /** 23345 * Updates the {@link Paint} object used with the current layer (used only if the current 23346 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 23347 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 23348 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 23349 * ensure that the view gets redrawn immediately. 23350 * 23351 * <p>A layer is associated with an optional {@link android.graphics.Paint} 23352 * instance that controls how the layer is composed on screen. The following 23353 * properties of the paint are taken into account when composing the layer:</p> 23354 * <ul> 23355 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 23356 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 23357 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 23358 * </ul> 23359 * 23360 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 23361 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 23362 * 23363 * @param paint The paint used to compose the layer. This argument is optional 23364 * and can be null. It is ignored when the layer type is 23365 * {@link #LAYER_TYPE_NONE} 23366 * 23367 * @see #setLayerType(int, android.graphics.Paint) 23368 */ setLayerPaint(@ullable Paint paint)23369 public void setLayerPaint(@Nullable Paint paint) { 23370 int layerType = getLayerType(); 23371 if (layerType != LAYER_TYPE_NONE) { 23372 mLayerPaint = paint; 23373 if (layerType == LAYER_TYPE_HARDWARE) { 23374 if (mRenderNode.setLayerPaint(paint)) { 23375 invalidateViewProperty(false, false); 23376 } 23377 } else { 23378 invalidate(); 23379 } 23380 } 23381 } 23382 23383 /** 23384 * Indicates what type of layer is currently associated with this view. By default 23385 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 23386 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 23387 * for more information on the different types of layers. 23388 * 23389 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 23390 * {@link #LAYER_TYPE_HARDWARE} 23391 * 23392 * @see #setLayerType(int, android.graphics.Paint) 23393 * @see #buildLayer() 23394 * @see #LAYER_TYPE_NONE 23395 * @see #LAYER_TYPE_SOFTWARE 23396 * @see #LAYER_TYPE_HARDWARE 23397 */ 23398 @InspectableProperty(enumMapping = { 23399 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 23400 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 23401 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 23402 }) 23403 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 23404 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 23405 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 23406 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 23407 }) 23408 @LayerType getLayerType()23409 public int getLayerType() { 23410 return mLayerType; 23411 } 23412 23413 /** 23414 * Forces this view's layer to be created and this view to be rendered 23415 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 23416 * invoking this method will have no effect. 23417 * 23418 * This method can for instance be used to render a view into its layer before 23419 * starting an animation. If this view is complex, rendering into the layer 23420 * before starting the animation will avoid skipping frames. 23421 * 23422 * @throws IllegalStateException If this view is not attached to a window 23423 * 23424 * @see #setLayerType(int, android.graphics.Paint) 23425 */ buildLayer()23426 public void buildLayer() { 23427 if (mLayerType == LAYER_TYPE_NONE) return; 23428 23429 final AttachInfo attachInfo = mAttachInfo; 23430 if (attachInfo == null) { 23431 throw new IllegalStateException("This view must be attached to a window first"); 23432 } 23433 23434 if (getWidth() == 0 || getHeight() == 0) { 23435 return; 23436 } 23437 23438 switch (mLayerType) { 23439 case LAYER_TYPE_HARDWARE: 23440 updateDisplayListIfDirty(); 23441 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 23442 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 23443 } 23444 break; 23445 case LAYER_TYPE_SOFTWARE: 23446 buildDrawingCache(true); 23447 break; 23448 } 23449 } 23450 23451 /** 23452 * Determines whether an unprocessed input event is available on the window. 23453 * 23454 * This is only a performance hint (a.k.a. the Input Hint) and may return false negative 23455 * results. Callers should not rely on availability of the input event based on the return 23456 * value of this method. 23457 * 23458 * The Input Hint functionality is experimental, and can be removed in the future OS releases. 23459 * 23460 * This method only returns nontrivial results on a View that is attached to a Window. Such View 23461 * can be acquired using `Activity.getWindow().getDecorView()`, and only after the view 23462 * hierarchy is attached (via {@link android.app.Activity#setContentView(android.view.View)}). 23463 * 23464 * In multi-window mode the View can provide the Input Hint only for the window it is attached 23465 * to. Therefore, checking input availability for the whole application would require asking 23466 * for the hint from more than one View. 23467 * 23468 * The initial implementation does not return false positives, but callers should not rely on 23469 * it: false positives may occur in future OS releases. 23470 * 23471 * @hide 23472 */ probablyHasInput()23473 public boolean probablyHasInput() { 23474 ViewRootImpl viewRootImpl = getViewRootImpl(); 23475 if (viewRootImpl == null) { 23476 return false; 23477 } 23478 return viewRootImpl.probablyHasInput(); 23479 } 23480 23481 /** 23482 * Destroys all hardware rendering resources. This method is invoked 23483 * when the system needs to reclaim resources. Upon execution of this 23484 * method, you should free any OpenGL resources created by the view. 23485 * 23486 * Note: you <strong>must</strong> call 23487 * <code>super.destroyHardwareResources()</code> when overriding 23488 * this method. 23489 * 23490 * @hide 23491 */ 23492 @CallSuper 23493 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareResources()23494 protected void destroyHardwareResources() { 23495 if (mOverlay != null) { 23496 mOverlay.getOverlayView().destroyHardwareResources(); 23497 } 23498 if (mGhostView != null) { 23499 mGhostView.destroyHardwareResources(); 23500 } 23501 } 23502 23503 /** 23504 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 23505 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 23506 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 23507 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 23508 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 23509 * null.</p> 23510 * 23511 * <p>Enabling the drawing cache is similar to 23512 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 23513 * acceleration is turned off. When hardware acceleration is turned on, enabling the 23514 * drawing cache has no effect on rendering because the system uses a different mechanism 23515 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 23516 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 23517 * for information on how to enable software and hardware layers.</p> 23518 * 23519 * <p>This API can be used to manually generate 23520 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 23521 * {@link #getDrawingCache()}.</p> 23522 * 23523 * @param enabled true to enable the drawing cache, false otherwise 23524 * 23525 * @see #isDrawingCacheEnabled() 23526 * @see #getDrawingCache() 23527 * @see #buildDrawingCache() 23528 * @see #setLayerType(int, android.graphics.Paint) 23529 * 23530 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23531 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23532 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23533 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23534 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23535 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23536 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23537 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23538 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23539 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23540 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23541 * reports or unit testing the {@link PixelCopy} API is recommended. 23542 */ 23543 @Deprecated setDrawingCacheEnabled(boolean enabled)23544 public void setDrawingCacheEnabled(boolean enabled) { 23545 mCachingFailed = false; 23546 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 23547 } 23548 23549 /** 23550 * <p>Indicates whether the drawing cache is enabled for this view.</p> 23551 * 23552 * @return true if the drawing cache is enabled 23553 * 23554 * @see #setDrawingCacheEnabled(boolean) 23555 * @see #getDrawingCache() 23556 * 23557 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23558 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23559 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23560 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23561 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23562 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23563 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23564 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23565 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23566 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23567 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23568 * reports or unit testing the {@link PixelCopy} API is recommended. 23569 */ 23570 @Deprecated 23571 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()23572 public boolean isDrawingCacheEnabled() { 23573 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 23574 } 23575 23576 /** 23577 * Debugging utility which recursively outputs the dirty state of a view and its 23578 * descendants. 23579 * 23580 * @hide 23581 */ 23582 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)23583 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 23584 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 23585 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 23586 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 23587 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 23588 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 23589 if (clear) { 23590 mPrivateFlags &= clearMask; 23591 } 23592 if (this instanceof ViewGroup) { 23593 ViewGroup parent = (ViewGroup) this; 23594 final int count = parent.getChildCount(); 23595 for (int i = 0; i < count; i++) { 23596 final View child = parent.getChildAt(i); 23597 child.outputDirtyFlags(indent + " ", clear, clearMask); 23598 } 23599 } 23600 } 23601 23602 /** 23603 * This method is used by ViewGroup to cause its children to restore or recreate their 23604 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 23605 * to recreate its own display list, which would happen if it went through the normal 23606 * draw/dispatchDraw mechanisms. 23607 * 23608 * @hide 23609 */ dispatchGetDisplayList()23610 protected void dispatchGetDisplayList() {} 23611 23612 /** 23613 * A view that is not attached or hardware accelerated cannot create a display list. 23614 * This method checks these conditions and returns the appropriate result. 23615 * 23616 * @return true if view has the ability to create a display list, false otherwise. 23617 * 23618 * @hide 23619 */ canHaveDisplayList()23620 public boolean canHaveDisplayList() { 23621 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 23622 } 23623 23624 /** 23625 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 23626 * @hide 23627 */ 23628 @NonNull 23629 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateDisplayListIfDirty()23630 public RenderNode updateDisplayListIfDirty() { 23631 final RenderNode renderNode = mRenderNode; 23632 if (!canHaveDisplayList()) { 23633 // can't populate RenderNode, don't try 23634 return renderNode; 23635 } 23636 23637 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 23638 || !renderNode.hasDisplayList() 23639 || (mRecreateDisplayList)) { 23640 // Don't need to recreate the display list, just need to tell our 23641 // children to restore/recreate theirs 23642 if (renderNode.hasDisplayList() 23643 && !mRecreateDisplayList) { 23644 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 23645 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23646 dispatchGetDisplayList(); 23647 23648 return renderNode; // no work needed 23649 } 23650 23651 // If we got here, we're recreating it. Mark it as such to ensure that 23652 // we copy in child display lists into ours in drawChild() 23653 mRecreateDisplayList = true; 23654 23655 int width = mRight - mLeft; 23656 int height = mBottom - mTop; 23657 int layerType = getLayerType(); 23658 23659 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 23660 // instead of being "stateful" like other RenderNode properties 23661 renderNode.clearStretch(); 23662 23663 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 23664 23665 try { 23666 if (layerType == LAYER_TYPE_SOFTWARE) { 23667 buildDrawingCache(true); 23668 Bitmap cache = getDrawingCache(true); 23669 if (cache != null) { 23670 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 23671 } 23672 } else { 23673 computeScroll(); 23674 23675 canvas.translate(-mScrollX, -mScrollY); 23676 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 23677 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23678 23679 mPrivateFlags4 |= PFLAG4_HAS_DRAWN; 23680 23681 // Fast path for layouts with no backgrounds 23682 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 23683 dispatchDraw(canvas); 23684 drawAutofilledHighlight(canvas); 23685 if (mOverlay != null && !mOverlay.isEmpty()) { 23686 mOverlay.getOverlayView().draw(canvas); 23687 } 23688 if (isShowingLayoutBounds()) { 23689 debugDrawFocus(canvas); 23690 } 23691 } else { 23692 draw(canvas); 23693 } 23694 } 23695 23696 // For VRR to vote the preferred frame rate 23697 if (sToolkitSetFrameRateReadOnlyFlagValue 23698 && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 23699 votePreferredFrameRate(); 23700 } 23701 } finally { 23702 renderNode.endRecording(); 23703 setDisplayListProperties(renderNode); 23704 } 23705 } else { 23706 if ((mPrivateFlags4 & PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION) 23707 == PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION) { 23708 // For VRR to vote the preferred frame rate 23709 if (sToolkitSetFrameRateReadOnlyFlagValue 23710 && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 23711 votePreferredFrameRate(); 23712 } 23713 mPrivateFlags4 &= ~PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; 23714 } 23715 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 23716 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23717 } 23718 mPrivateFlags4 &= ~PFLAG4_HAS_MOVED; 23719 mFrameContentVelocity = -1; 23720 return renderNode; 23721 } 23722 23723 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resetDisplayList()23724 private void resetDisplayList() { 23725 mRenderNode.discardDisplayList(); 23726 if (mBackgroundRenderNode != null) { 23727 mBackgroundRenderNode.discardDisplayList(); 23728 } 23729 } 23730 23731 /** 23732 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 23733 * 23734 * @return A non-scaled bitmap representing this view or null if cache is disabled. 23735 * 23736 * @see #getDrawingCache(boolean) 23737 * 23738 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23739 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23740 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23741 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23742 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23743 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23744 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23745 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23746 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23747 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23748 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23749 * reports or unit testing the {@link PixelCopy} API is recommended. 23750 */ 23751 @Deprecated getDrawingCache()23752 public Bitmap getDrawingCache() { 23753 return getDrawingCache(false); 23754 } 23755 23756 /** 23757 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 23758 * is null when caching is disabled. If caching is enabled and the cache is not ready, 23759 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 23760 * draw from the cache when the cache is enabled. To benefit from the cache, you must 23761 * request the drawing cache by calling this method and draw it on screen if the 23762 * returned bitmap is not null.</p> 23763 * 23764 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 23765 * this method will create a bitmap of the same size as this view. Because this bitmap 23766 * will be drawn scaled by the parent ViewGroup, the result on screen might show 23767 * scaling artifacts. To avoid such artifacts, you should call this method by setting 23768 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 23769 * size than the view. This implies that your application must be able to handle this 23770 * size.</p> 23771 * 23772 * @param autoScale Indicates whether the generated bitmap should be scaled based on 23773 * the current density of the screen when the application is in compatibility 23774 * mode. 23775 * 23776 * @return A bitmap representing this view or null if cache is disabled. 23777 * 23778 * @see #setDrawingCacheEnabled(boolean) 23779 * @see #isDrawingCacheEnabled() 23780 * @see #buildDrawingCache(boolean) 23781 * @see #destroyDrawingCache() 23782 * 23783 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23784 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23785 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23786 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23787 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23788 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23789 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23790 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23791 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23792 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23793 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23794 * reports or unit testing the {@link PixelCopy} API is recommended. 23795 */ 23796 @Deprecated getDrawingCache(boolean autoScale)23797 public Bitmap getDrawingCache(boolean autoScale) { 23798 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 23799 return null; 23800 } 23801 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 23802 buildDrawingCache(autoScale); 23803 } 23804 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 23805 } 23806 23807 /** 23808 * <p>Frees the resources used by the drawing cache. If you call 23809 * {@link #buildDrawingCache()} manually without calling 23810 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 23811 * should cleanup the cache with this method afterwards.</p> 23812 * 23813 * @see #setDrawingCacheEnabled(boolean) 23814 * @see #buildDrawingCache() 23815 * @see #getDrawingCache() 23816 * 23817 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23818 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23819 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23820 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23821 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23822 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23823 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23824 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23825 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23826 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23827 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23828 * reports or unit testing the {@link PixelCopy} API is recommended. 23829 */ 23830 @Deprecated destroyDrawingCache()23831 public void destroyDrawingCache() { 23832 if (mDrawingCache != null) { 23833 mDrawingCache.recycle(); 23834 mDrawingCache = null; 23835 } 23836 if (mUnscaledDrawingCache != null) { 23837 mUnscaledDrawingCache.recycle(); 23838 mUnscaledDrawingCache = null; 23839 } 23840 } 23841 23842 /** 23843 * Setting a solid background color for the drawing cache's bitmaps will improve 23844 * performance and memory usage. Note, though that this should only be used if this 23845 * view will always be drawn on top of a solid color. 23846 * 23847 * @param color The background color to use for the drawing cache's bitmap 23848 * 23849 * @see #setDrawingCacheEnabled(boolean) 23850 * @see #buildDrawingCache() 23851 * @see #getDrawingCache() 23852 * 23853 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23854 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23855 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23856 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23857 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23858 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23859 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23860 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23861 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23862 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23863 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23864 * reports or unit testing the {@link PixelCopy} API is recommended. 23865 */ 23866 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)23867 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 23868 if (color != mDrawingCacheBackgroundColor) { 23869 mDrawingCacheBackgroundColor = color; 23870 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 23871 } 23872 } 23873 23874 /** 23875 * @see #setDrawingCacheBackgroundColor(int) 23876 * 23877 * @return The background color to used for the drawing cache's bitmap 23878 * 23879 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23880 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23881 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23882 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23883 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23884 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23885 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23886 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23887 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23888 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23889 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23890 * reports or unit testing the {@link PixelCopy} API is recommended. 23891 */ 23892 @Deprecated 23893 @ColorInt getDrawingCacheBackgroundColor()23894 public int getDrawingCacheBackgroundColor() { 23895 return mDrawingCacheBackgroundColor; 23896 } 23897 23898 /** 23899 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 23900 * 23901 * @see #buildDrawingCache(boolean) 23902 * 23903 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23904 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23905 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23906 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23907 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23908 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23909 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23910 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23911 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23912 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23913 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23914 * reports or unit testing the {@link PixelCopy} API is recommended. 23915 */ 23916 @Deprecated buildDrawingCache()23917 public void buildDrawingCache() { 23918 buildDrawingCache(false); 23919 } 23920 23921 /** 23922 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 23923 * 23924 * <p>If you call {@link #buildDrawingCache()} manually without calling 23925 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 23926 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 23927 * 23928 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 23929 * this method will create a bitmap of the same size as this view. Because this bitmap 23930 * will be drawn scaled by the parent ViewGroup, the result on screen might show 23931 * scaling artifacts. To avoid such artifacts, you should call this method by setting 23932 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 23933 * size than the view. This implies that your application must be able to handle this 23934 * size.</p> 23935 * 23936 * <p>You should avoid calling this method when hardware acceleration is enabled. If 23937 * you do not need the drawing cache bitmap, calling this method will increase memory 23938 * usage and cause the view to be rendered in software once, thus negatively impacting 23939 * performance.</p> 23940 * 23941 * @see #getDrawingCache() 23942 * @see #destroyDrawingCache() 23943 * 23944 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23945 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23946 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23947 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23948 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23949 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23950 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23951 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23952 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23953 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23954 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23955 * reports or unit testing the {@link PixelCopy} API is recommended. 23956 */ 23957 @Deprecated buildDrawingCache(boolean autoScale)23958 public void buildDrawingCache(boolean autoScale) { 23959 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 23960 mDrawingCache == null : mUnscaledDrawingCache == null)) { 23961 if (Trace.isTagEnabled(TRACE_TAG_VIEW)) { 23962 Trace.traceBegin(TRACE_TAG_VIEW, 23963 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 23964 } 23965 try { 23966 buildDrawingCacheImpl(autoScale); 23967 } finally { 23968 Trace.traceEnd(TRACE_TAG_VIEW); 23969 } 23970 } 23971 } 23972 23973 /** 23974 * private, internal implementation of buildDrawingCache, used to enable tracing 23975 */ buildDrawingCacheImpl(boolean autoScale)23976 private void buildDrawingCacheImpl(boolean autoScale) { 23977 mCachingFailed = false; 23978 23979 int width = mRight - mLeft; 23980 int height = mBottom - mTop; 23981 23982 final AttachInfo attachInfo = mAttachInfo; 23983 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 23984 23985 if (autoScale && scalingRequired) { 23986 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 23987 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 23988 } 23989 23990 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 23991 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 23992 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 23993 23994 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 23995 final long drawingCacheSize = 23996 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 23997 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 23998 if (width > 0 && height > 0) { 23999 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 24000 + " too large to fit into a software layer (or drawing cache), needs " 24001 + projectedBitmapSize + " bytes, only " 24002 + drawingCacheSize + " available"); 24003 } 24004 destroyDrawingCache(); 24005 mCachingFailed = true; 24006 return; 24007 } 24008 24009 boolean clear = true; 24010 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 24011 24012 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 24013 Bitmap.Config quality; 24014 if (!opaque) { 24015 // Never pick ARGB_4444 because it looks awful 24016 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 24017 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 24018 case DRAWING_CACHE_QUALITY_AUTO: 24019 case DRAWING_CACHE_QUALITY_LOW: 24020 case DRAWING_CACHE_QUALITY_HIGH: 24021 default: 24022 quality = Bitmap.Config.ARGB_8888; 24023 break; 24024 } 24025 } else { 24026 // Optimization for translucent windows 24027 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 24028 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 24029 } 24030 24031 // Try to cleanup memory 24032 if (bitmap != null) bitmap.recycle(); 24033 24034 try { 24035 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 24036 width, height, quality); 24037 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 24038 if (autoScale) { 24039 mDrawingCache = bitmap; 24040 } else { 24041 mUnscaledDrawingCache = bitmap; 24042 } 24043 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 24044 } catch (OutOfMemoryError e) { 24045 // If there is not enough memory to create the bitmap cache, just 24046 // ignore the issue as bitmap caches are not required to draw the 24047 // view hierarchy 24048 if (autoScale) { 24049 mDrawingCache = null; 24050 } else { 24051 mUnscaledDrawingCache = null; 24052 } 24053 mCachingFailed = true; 24054 return; 24055 } 24056 24057 clear = drawingCacheBackgroundColor != 0; 24058 } 24059 24060 Canvas canvas; 24061 if (attachInfo != null) { 24062 canvas = attachInfo.mCanvas; 24063 if (canvas == null) { 24064 canvas = new Canvas(); 24065 } 24066 canvas.setBitmap(bitmap); 24067 // Temporarily clobber the cached Canvas in case one of our children 24068 // is also using a drawing cache. Without this, the children would 24069 // steal the canvas by attaching their own bitmap to it and bad, bad 24070 // thing would happen (invisible views, corrupted drawings, etc.) 24071 attachInfo.mCanvas = null; 24072 } else { 24073 // This case should hopefully never or seldom happen 24074 canvas = new Canvas(bitmap); 24075 } 24076 24077 if (clear) { 24078 bitmap.eraseColor(drawingCacheBackgroundColor); 24079 } 24080 24081 computeScroll(); 24082 final int restoreCount = canvas.save(); 24083 24084 if (autoScale && scalingRequired) { 24085 final float scale = attachInfo.mApplicationScale; 24086 canvas.scale(scale, scale); 24087 } 24088 24089 canvas.translate(-mScrollX, -mScrollY); 24090 24091 mPrivateFlags |= PFLAG_DRAWN; 24092 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 24093 mLayerType != LAYER_TYPE_NONE) { 24094 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 24095 } 24096 24097 // Fast path for layouts with no backgrounds 24098 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 24099 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24100 dispatchDraw(canvas); 24101 drawAutofilledHighlight(canvas); 24102 if (mOverlay != null && !mOverlay.isEmpty()) { 24103 mOverlay.getOverlayView().draw(canvas); 24104 } 24105 } else { 24106 draw(canvas); 24107 } 24108 24109 canvas.restoreToCount(restoreCount); 24110 canvas.setBitmap(null); 24111 24112 if (attachInfo != null) { 24113 // Restore the cached Canvas for our siblings 24114 attachInfo.mCanvas = canvas; 24115 } 24116 } 24117 24118 /** 24119 * Create a snapshot of the view into a bitmap. We should probably make 24120 * some form of this public, but should think about the API. 24121 * 24122 * @hide 24123 */ 24124 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)24125 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 24126 int width = mRight - mLeft; 24127 int height = mBottom - mTop; 24128 24129 final AttachInfo attachInfo = mAttachInfo; 24130 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 24131 width = (int) ((width * scale) + 0.5f); 24132 height = (int) ((height * scale) + 0.5f); 24133 24134 Canvas oldCanvas = null; 24135 try { 24136 Canvas canvas = canvasProvider.getCanvas(this, 24137 width > 0 ? width : 1, height > 0 ? height : 1); 24138 24139 if (attachInfo != null) { 24140 oldCanvas = attachInfo.mCanvas; 24141 // Temporarily clobber the cached Canvas in case one of our children 24142 // is also using a drawing cache. Without this, the children would 24143 // steal the canvas by attaching their own bitmap to it and bad, bad 24144 // things would happen (invisible views, corrupted drawings, etc.) 24145 attachInfo.mCanvas = null; 24146 } 24147 24148 computeScroll(); 24149 final int restoreCount = canvas.save(); 24150 canvas.scale(scale, scale); 24151 canvas.translate(-mScrollX, -mScrollY); 24152 24153 // Temporarily remove the dirty mask 24154 int flags = mPrivateFlags; 24155 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24156 24157 // Fast path for layouts with no backgrounds 24158 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 24159 dispatchDraw(canvas); 24160 drawAutofilledHighlight(canvas); 24161 if (mOverlay != null && !mOverlay.isEmpty()) { 24162 mOverlay.getOverlayView().draw(canvas); 24163 } 24164 } else { 24165 draw(canvas); 24166 } 24167 24168 mPrivateFlags = flags; 24169 canvas.restoreToCount(restoreCount); 24170 return canvasProvider.createBitmap(); 24171 } finally { 24172 if (oldCanvas != null) { 24173 attachInfo.mCanvas = oldCanvas; 24174 } 24175 } 24176 } 24177 24178 /** 24179 * Indicates whether this View is currently in edit mode. A View is usually 24180 * in edit mode when displayed within a developer tool. For instance, if 24181 * this View is being drawn by a visual user interface builder, this method 24182 * should return true. 24183 * 24184 * Subclasses should check the return value of this method to provide 24185 * different behaviors if their normal behavior might interfere with the 24186 * host environment. For instance: the class spawns a thread in its 24187 * constructor, the drawing code relies on device-specific features, etc. 24188 * 24189 * This method is usually checked in the drawing code of custom widgets. 24190 * 24191 * @return True if this View is in edit mode, false otherwise. 24192 */ isInEditMode()24193 public boolean isInEditMode() { 24194 return false; 24195 } 24196 24197 /** 24198 * If the View draws content inside its padding and enables fading edges, 24199 * it needs to support padding offsets. Padding offsets are added to the 24200 * fading edges to extend the length of the fade so that it covers pixels 24201 * drawn inside the padding. 24202 * 24203 * Subclasses of this class should override this method if they need 24204 * to draw content inside the padding. 24205 * 24206 * @return True if padding offset must be applied, false otherwise. 24207 * 24208 * @see #getLeftPaddingOffset() 24209 * @see #getRightPaddingOffset() 24210 * @see #getTopPaddingOffset() 24211 * @see #getBottomPaddingOffset() 24212 * 24213 * @since CURRENT 24214 */ isPaddingOffsetRequired()24215 protected boolean isPaddingOffsetRequired() { 24216 return false; 24217 } 24218 24219 /** 24220 * Amount by which to extend the left fading region. Called only when 24221 * {@link #isPaddingOffsetRequired()} returns true. 24222 * 24223 * @return The left padding offset in pixels. 24224 * 24225 * @see #isPaddingOffsetRequired() 24226 * 24227 * @since CURRENT 24228 */ getLeftPaddingOffset()24229 protected int getLeftPaddingOffset() { 24230 return 0; 24231 } 24232 24233 /** 24234 * Amount by which to extend the right fading region. Called only when 24235 * {@link #isPaddingOffsetRequired()} returns true. 24236 * 24237 * @return The right padding offset in pixels. 24238 * 24239 * @see #isPaddingOffsetRequired() 24240 * 24241 * @since CURRENT 24242 */ getRightPaddingOffset()24243 protected int getRightPaddingOffset() { 24244 return 0; 24245 } 24246 24247 /** 24248 * Amount by which to extend the top fading region. Called only when 24249 * {@link #isPaddingOffsetRequired()} returns true. 24250 * 24251 * @return The top padding offset in pixels. 24252 * 24253 * @see #isPaddingOffsetRequired() 24254 * 24255 * @since CURRENT 24256 */ getTopPaddingOffset()24257 protected int getTopPaddingOffset() { 24258 return 0; 24259 } 24260 24261 /** 24262 * Amount by which to extend the bottom fading region. Called only when 24263 * {@link #isPaddingOffsetRequired()} returns true. 24264 * 24265 * @return The bottom padding offset in pixels. 24266 * 24267 * @see #isPaddingOffsetRequired() 24268 * 24269 * @since CURRENT 24270 */ getBottomPaddingOffset()24271 protected int getBottomPaddingOffset() { 24272 return 0; 24273 } 24274 24275 /** 24276 * @hide 24277 * @param offsetRequired 24278 */ getFadeTop(boolean offsetRequired)24279 protected int getFadeTop(boolean offsetRequired) { 24280 int top = mPaddingTop; 24281 if (offsetRequired) top += getTopPaddingOffset(); 24282 return top; 24283 } 24284 24285 /** 24286 * @hide 24287 * @param offsetRequired 24288 */ getFadeHeight(boolean offsetRequired)24289 protected int getFadeHeight(boolean offsetRequired) { 24290 int padding = mPaddingTop; 24291 if (offsetRequired) padding += getTopPaddingOffset(); 24292 return mBottom - mTop - mPaddingBottom - padding; 24293 } 24294 24295 /** 24296 * <p>Indicates whether this view is attached to a hardware accelerated 24297 * window or not.</p> 24298 * 24299 * <p>Even if this method returns true, it does not mean that every call 24300 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 24301 * accelerated {@link android.graphics.Canvas}. For instance, if this view 24302 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 24303 * window is hardware accelerated, 24304 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 24305 * return false, and this method will return true.</p> 24306 * 24307 * @return True if the view is attached to a window and the window is 24308 * hardware accelerated; false in any other case. 24309 */ 24310 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()24311 public boolean isHardwareAccelerated() { 24312 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 24313 } 24314 24315 /** 24316 * Sets a rectangular area on this view to which the view will be clipped 24317 * when it is drawn. Setting the value to null will remove the clip bounds 24318 * and the view will draw normally, using its full bounds. 24319 * 24320 * @param clipBounds The rectangular area, in the local coordinates of 24321 * this view, to which future drawing operations will be clipped. 24322 */ setClipBounds(Rect clipBounds)24323 public void setClipBounds(Rect clipBounds) { 24324 if (clipBounds == mClipBounds 24325 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 24326 return; 24327 } 24328 if (clipBounds != null) { 24329 if (mClipBounds == null) { 24330 mClipBounds = new Rect(clipBounds); 24331 } else { 24332 mClipBounds.set(clipBounds); 24333 } 24334 } else { 24335 mClipBounds = null; 24336 } 24337 mRenderNode.setClipRect(mClipBounds); 24338 invalidateViewProperty(false, false); 24339 } 24340 24341 /** 24342 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 24343 * 24344 * @return A copy of the current clip bounds if clip bounds are set, 24345 * otherwise null. 24346 */ getClipBounds()24347 public Rect getClipBounds() { 24348 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 24349 } 24350 24351 24352 /** 24353 * Populates an output rectangle with the clip bounds of the view, 24354 * returning {@code true} if successful or {@code false} if the view's 24355 * clip bounds are {@code null}. 24356 * 24357 * @param outRect rectangle in which to place the clip bounds of the view 24358 * @return {@code true} if successful or {@code false} if the view's 24359 * clip bounds are {@code null} 24360 */ getClipBounds(Rect outRect)24361 public boolean getClipBounds(Rect outRect) { 24362 if (mClipBounds != null) { 24363 outRect.set(mClipBounds); 24364 return true; 24365 } 24366 return false; 24367 } 24368 24369 /** 24370 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 24371 * case of an active Animation being run on the view. 24372 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)24373 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 24374 Animation a, boolean scalingRequired) { 24375 Transformation invalidationTransform; 24376 final int flags = parent.mGroupFlags; 24377 final boolean initialized = a.isInitialized(); 24378 if (!initialized) { 24379 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 24380 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 24381 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 24382 onAnimationStart(); 24383 } 24384 24385 final Transformation t = parent.getChildTransformation(); 24386 boolean more = a.getTransformation(drawingTime, t, 1f); 24387 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 24388 if (parent.mInvalidationTransformation == null) { 24389 parent.mInvalidationTransformation = new Transformation(); 24390 } 24391 invalidationTransform = parent.mInvalidationTransformation; 24392 a.getTransformation(drawingTime, invalidationTransform, 1f); 24393 } else { 24394 invalidationTransform = t; 24395 } 24396 24397 if (more) { 24398 if (!a.willChangeBounds()) { 24399 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 24400 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 24401 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 24402 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 24403 // The child need to draw an animation, potentially offscreen, so 24404 // make sure we do not cancel invalidate requests 24405 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 24406 parent.invalidate(mLeft, mTop, mRight, mBottom); 24407 } 24408 } else { 24409 if (parent.mInvalidateRegion == null) { 24410 parent.mInvalidateRegion = new RectF(); 24411 } 24412 final RectF region = parent.mInvalidateRegion; 24413 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 24414 invalidationTransform); 24415 24416 // The child need to draw an animation, potentially offscreen, so 24417 // make sure we do not cancel invalidate requests 24418 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 24419 24420 final int left = mLeft + (int) region.left; 24421 final int top = mTop + (int) region.top; 24422 parent.invalidate(left, top, left + (int) (region.width() + .5f), 24423 top + (int) (region.height() + .5f)); 24424 } 24425 } 24426 return more; 24427 } 24428 24429 /** 24430 * This method is called by getDisplayList() when a display list is recorded for a View. 24431 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 24432 */ setDisplayListProperties(RenderNode renderNode)24433 void setDisplayListProperties(RenderNode renderNode) { 24434 if (renderNode != null) { 24435 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 24436 renderNode.setClipToBounds(mParent instanceof ViewGroup 24437 && ((ViewGroup) mParent).getClipChildren()); 24438 24439 float alpha = 1; 24440 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 24441 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 24442 ViewGroup parentVG = (ViewGroup) mParent; 24443 final Transformation t = parentVG.getChildTransformation(); 24444 if (parentVG.getChildStaticTransformation(this, t)) { 24445 final int transformType = t.getTransformationType(); 24446 if (transformType != Transformation.TYPE_IDENTITY) { 24447 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 24448 alpha = t.getAlpha(); 24449 } 24450 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 24451 renderNode.setStaticMatrix(t.getMatrix()); 24452 } 24453 } 24454 } 24455 } 24456 if (mTransformationInfo != null) { 24457 alpha *= getFinalAlpha(); 24458 if (alpha < 1) { 24459 final int multipliedAlpha = (int) (255 * alpha); 24460 if (onSetAlpha(multipliedAlpha)) { 24461 alpha = 1; 24462 } 24463 } 24464 renderNode.setAlpha(alpha); 24465 } else if (alpha < 1) { 24466 renderNode.setAlpha(alpha); 24467 } 24468 } 24469 } 24470 24471 /** 24472 * If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 24473 * 24474 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 24475 * HW accelerated, it can't handle drawing RenderNodes. 24476 * 24477 * @hide 24478 */ drawsWithRenderNode(@onNull Canvas canvas)24479 protected final boolean drawsWithRenderNode(@NonNull Canvas canvas) { 24480 return mAttachInfo != null 24481 && mAttachInfo.mHardwareAccelerated 24482 && canvas.isHardwareAccelerated(); 24483 } 24484 24485 /** 24486 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 24487 * 24488 * This is where the View specializes rendering behavior based on layer type, 24489 * and hardware acceleration. 24490 */ draw(@onNull Canvas canvas, ViewGroup parent, long drawingTime)24491 boolean draw(@NonNull Canvas canvas, ViewGroup parent, long drawingTime) { 24492 24493 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 24494 24495 boolean drawingWithRenderNode = drawsWithRenderNode(canvas); 24496 24497 boolean more = false; 24498 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 24499 final int parentFlags = parent.mGroupFlags; 24500 24501 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 24502 parent.getChildTransformation().clear(); 24503 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24504 } 24505 24506 Transformation transformToApply = null; 24507 boolean concatMatrix = false; 24508 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 24509 final Animation a = getAnimation(); 24510 if (a != null) { 24511 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 24512 concatMatrix = a.willChangeTransformationMatrix(); 24513 if (concatMatrix) { 24514 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 24515 } 24516 transformToApply = parent.getChildTransformation(); 24517 } else { 24518 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 24519 // No longer animating: clear out old animation matrix 24520 mRenderNode.setAnimationMatrix(null); 24521 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 24522 } 24523 if (!drawingWithRenderNode 24524 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 24525 final Transformation t = parent.getChildTransformation(); 24526 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 24527 if (hasTransform) { 24528 final int transformType = t.getTransformationType(); 24529 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 24530 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 24531 } 24532 } 24533 } 24534 24535 concatMatrix |= !childHasIdentityMatrix; 24536 24537 // Sets the flag as early as possible to allow draw() implementations 24538 // to call invalidate() successfully when doing animations 24539 mPrivateFlags |= PFLAG_DRAWN; 24540 24541 if (!concatMatrix && 24542 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 24543 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 24544 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 24545 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 24546 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 24547 return more; 24548 } 24549 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 24550 24551 if (hardwareAcceleratedCanvas) { 24552 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 24553 // retain the flag's value temporarily in the mRecreateDisplayList flag 24554 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 24555 mPrivateFlags &= ~PFLAG_INVALIDATED; 24556 } 24557 24558 RenderNode renderNode = null; 24559 Bitmap cache = null; 24560 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 24561 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 24562 if (layerType != LAYER_TYPE_NONE) { 24563 // If not drawing with RenderNode, treat HW layers as SW 24564 layerType = LAYER_TYPE_SOFTWARE; 24565 buildDrawingCache(true); 24566 } 24567 cache = getDrawingCache(true); 24568 } 24569 24570 if (drawingWithRenderNode) { 24571 // Delay getting the display list until animation-driven alpha values are 24572 // set up and possibly passed on to the view 24573 renderNode = updateDisplayListIfDirty(); 24574 if (!renderNode.hasDisplayList()) { 24575 // Uncommon, but possible. If a view is removed from the hierarchy during the call 24576 // to getDisplayList(), the display list will be marked invalid and we should not 24577 // try to use it again. 24578 renderNode = null; 24579 drawingWithRenderNode = false; 24580 } 24581 } 24582 24583 int sx = 0; 24584 int sy = 0; 24585 if (!drawingWithRenderNode) { 24586 computeScroll(); 24587 sx = mScrollX; 24588 sy = mScrollY; 24589 } 24590 24591 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 24592 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 24593 24594 int restoreTo = -1; 24595 if (!drawingWithRenderNode || transformToApply != null) { 24596 restoreTo = canvas.save(); 24597 } 24598 if (offsetForScroll) { 24599 canvas.translate(mLeft - sx, mTop - sy); 24600 } else { 24601 if (!drawingWithRenderNode) { 24602 canvas.translate(mLeft, mTop); 24603 } 24604 if (scalingRequired) { 24605 if (drawingWithRenderNode) { 24606 // TODO: Might not need this if we put everything inside the DL 24607 restoreTo = canvas.save(); 24608 } 24609 // mAttachInfo cannot be null, otherwise scalingRequired == false 24610 final float scale = 1.0f / mAttachInfo.mApplicationScale; 24611 canvas.scale(scale, scale); 24612 } 24613 } 24614 24615 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 24616 if (transformToApply != null 24617 || alpha < 1 24618 || !hasIdentityMatrix() 24619 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 24620 if (transformToApply != null || !childHasIdentityMatrix) { 24621 int transX = 0; 24622 int transY = 0; 24623 24624 if (offsetForScroll) { 24625 transX = -sx; 24626 transY = -sy; 24627 } 24628 24629 if (transformToApply != null) { 24630 if (concatMatrix) { 24631 if (drawingWithRenderNode) { 24632 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 24633 } else { 24634 // Undo the scroll translation, apply the transformation matrix, 24635 // then redo the scroll translate to get the correct result. 24636 canvas.translate(-transX, -transY); 24637 canvas.concat(transformToApply.getMatrix()); 24638 canvas.translate(transX, transY); 24639 } 24640 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24641 } 24642 24643 float transformAlpha = transformToApply.getAlpha(); 24644 if (transformAlpha < 1) { 24645 alpha *= transformAlpha; 24646 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24647 } 24648 } 24649 24650 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 24651 canvas.translate(-transX, -transY); 24652 canvas.concat(getMatrix()); 24653 canvas.translate(transX, transY); 24654 } 24655 } 24656 24657 // Deal with alpha if it is or used to be <1 24658 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 24659 if (alpha < 1) { 24660 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 24661 } else { 24662 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 24663 } 24664 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24665 if (!drawingWithDrawingCache) { 24666 final int multipliedAlpha = (int) (255 * alpha); 24667 if (!onSetAlpha(multipliedAlpha)) { 24668 if (drawingWithRenderNode) { 24669 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 24670 } else if (layerType == LAYER_TYPE_NONE) { 24671 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 24672 multipliedAlpha); 24673 } 24674 } else { 24675 // Alpha is handled by the child directly, clobber the layer's alpha 24676 mPrivateFlags |= PFLAG_ALPHA_SET; 24677 } 24678 } 24679 } 24680 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 24681 onSetAlpha(255); 24682 mPrivateFlags &= ~PFLAG_ALPHA_SET; 24683 } 24684 24685 if (!drawingWithRenderNode) { 24686 // apply clips directly, since RenderNode won't do it for this draw 24687 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 24688 if (offsetForScroll) { 24689 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 24690 } else { 24691 if (!scalingRequired || cache == null) { 24692 canvas.clipRect(0, 0, getWidth(), getHeight()); 24693 } else { 24694 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 24695 } 24696 } 24697 } 24698 24699 if (mClipBounds != null) { 24700 // clip bounds ignore scroll 24701 canvas.clipRect(mClipBounds); 24702 } 24703 } 24704 24705 if (!drawingWithDrawingCache) { 24706 if (drawingWithRenderNode) { 24707 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24708 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 24709 } else { 24710 // Fast path for layouts with no backgrounds 24711 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 24712 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24713 dispatchDraw(canvas); 24714 } else { 24715 draw(canvas); 24716 } 24717 } 24718 } else if (cache != null) { 24719 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24720 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 24721 // no layer paint, use temporary paint to draw bitmap 24722 Paint cachePaint = parent.mCachePaint; 24723 if (cachePaint == null) { 24724 cachePaint = new Paint(); 24725 cachePaint.setDither(false); 24726 parent.mCachePaint = cachePaint; 24727 } 24728 cachePaint.setAlpha((int) (alpha * 255)); 24729 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 24730 } else { 24731 // use layer paint to draw the bitmap, merging the two alphas, but also restore 24732 int layerPaintAlpha = mLayerPaint.getAlpha(); 24733 if (alpha < 1) { 24734 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 24735 } 24736 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 24737 if (alpha < 1) { 24738 mLayerPaint.setAlpha(layerPaintAlpha); 24739 } 24740 } 24741 } 24742 24743 if (restoreTo >= 0) { 24744 canvas.restoreToCount(restoreTo); 24745 } 24746 24747 if (a != null && !more) { 24748 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 24749 onSetAlpha(255); 24750 } 24751 parent.finishAnimatingView(this, a); 24752 } 24753 24754 if (more && hardwareAcceleratedCanvas) { 24755 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 24756 // alpha animations should cause the child to recreate its display list 24757 invalidate(true); 24758 } 24759 } 24760 24761 mRecreateDisplayList = false; 24762 24763 return more; 24764 } 24765 getDebugPaint()24766 static Paint getDebugPaint() { 24767 if (sDebugPaint == null) { 24768 sDebugPaint = new Paint(); 24769 sDebugPaint.setAntiAlias(false); 24770 } 24771 return sDebugPaint; 24772 } 24773 dipsToPixels(int dips)24774 final int dipsToPixels(int dips) { 24775 float scale = getContext().getResources().getDisplayMetrics().density; 24776 return (int) (dips * scale + 0.5f); 24777 } 24778 debugDrawFocus(@onNull Canvas canvas)24779 private void debugDrawFocus(@NonNull Canvas canvas) { 24780 if (isFocused()) { 24781 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 24782 final int l = mScrollX; 24783 final int r = l + mRight - mLeft; 24784 final int t = mScrollY; 24785 final int b = t + mBottom - mTop; 24786 24787 final Paint paint = getDebugPaint(); 24788 paint.setColor(DEBUG_CORNERS_COLOR); 24789 24790 // Draw squares in corners. 24791 paint.setStyle(Paint.Style.FILL); 24792 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 24793 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 24794 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 24795 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 24796 24797 // Draw big X across the view. 24798 paint.setStyle(Paint.Style.STROKE); 24799 canvas.drawLine(l, t, r, b, paint); 24800 canvas.drawLine(l, b, r, t, paint); 24801 } 24802 } 24803 24804 /** 24805 * Manually render this view (and all of its children) to the given Canvas. 24806 * The view must have already done a full layout before this function is 24807 * called. When implementing a view, implement 24808 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 24809 * If you do need to override this method, call the superclass version. 24810 * 24811 * @param canvas The Canvas to which the View is rendered. 24812 */ 24813 @CallSuper draw(@onNull Canvas canvas)24814 public void draw(@NonNull Canvas canvas) { 24815 final int privateFlags = mPrivateFlags; 24816 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 24817 24818 /* 24819 * Draw traversal performs several drawing steps which must be executed 24820 * in the appropriate order: 24821 * 24822 * 1. Draw the background 24823 * 2. If necessary, save the canvas' layers to prepare for fading 24824 * 3. Draw view's content 24825 * 4. Draw children 24826 * 5. If necessary, draw the fading edges and restore layers 24827 * 6. Draw decorations (scrollbars for instance) 24828 * 7. If necessary, draw the default focus highlight 24829 */ 24830 24831 // Step 1, draw the background, if needed 24832 int saveCount; 24833 24834 drawBackground(canvas); 24835 24836 // skip step 2 & 5 if possible (common case) 24837 final int viewFlags = mViewFlags; 24838 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 24839 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 24840 if (!verticalEdges && !horizontalEdges) { 24841 // Step 3, draw the content 24842 onDraw(canvas); 24843 24844 // Step 4, draw the children 24845 dispatchDraw(canvas); 24846 24847 drawAutofilledHighlight(canvas); 24848 24849 // Overlay is part of the content and draws beneath Foreground 24850 if (mOverlay != null && !mOverlay.isEmpty()) { 24851 mOverlay.getOverlayView().dispatchDraw(canvas); 24852 } 24853 24854 // Step 6, draw decorations (foreground, scrollbars) 24855 onDrawForeground(canvas); 24856 24857 // Step 7, draw the default focus highlight 24858 drawDefaultFocusHighlight(canvas); 24859 24860 if (isShowingLayoutBounds()) { 24861 debugDrawFocus(canvas); 24862 } 24863 24864 // we're done... 24865 return; 24866 } 24867 24868 /* 24869 * Here we do the full fledged routine... 24870 * (this is an uncommon case where speed matters less, 24871 * this is why we repeat some of the tests that have been 24872 * done above) 24873 */ 24874 24875 boolean drawTop = false; 24876 boolean drawBottom = false; 24877 boolean drawLeft = false; 24878 boolean drawRight = false; 24879 24880 float topFadeStrength = 0.0f; 24881 float bottomFadeStrength = 0.0f; 24882 float leftFadeStrength = 0.0f; 24883 float rightFadeStrength = 0.0f; 24884 24885 // Step 2, save the canvas' layers 24886 int paddingLeft = mPaddingLeft; 24887 24888 final boolean offsetRequired = isPaddingOffsetRequired(); 24889 if (offsetRequired) { 24890 paddingLeft += getLeftPaddingOffset(); 24891 } 24892 24893 int left = mScrollX + paddingLeft; 24894 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 24895 int top = mScrollY + getFadeTop(offsetRequired); 24896 int bottom = top + getFadeHeight(offsetRequired); 24897 24898 if (offsetRequired) { 24899 right += getRightPaddingOffset(); 24900 bottom += getBottomPaddingOffset(); 24901 } 24902 24903 final ScrollabilityCache scrollabilityCache = mScrollCache; 24904 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 24905 int length = (int) fadeHeight; 24906 24907 // clip the fade length if top and bottom fades overlap 24908 // overlapping fades produce odd-looking artifacts 24909 if (verticalEdges && (top + length > bottom - length)) { 24910 length = (bottom - top) / 2; 24911 } 24912 24913 // also clip horizontal fades if necessary 24914 if (horizontalEdges && (left + length > right - length)) { 24915 length = (right - left) / 2; 24916 } 24917 24918 if (verticalEdges) { 24919 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 24920 drawTop = topFadeStrength * fadeHeight > 1.0f; 24921 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 24922 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 24923 } 24924 24925 if (horizontalEdges) { 24926 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 24927 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 24928 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 24929 drawRight = rightFadeStrength * fadeHeight > 1.0f; 24930 } 24931 24932 saveCount = canvas.getSaveCount(); 24933 int topSaveCount = -1; 24934 int bottomSaveCount = -1; 24935 int leftSaveCount = -1; 24936 int rightSaveCount = -1; 24937 24938 int solidColor = getSolidColor(); 24939 if (solidColor == 0) { 24940 if (drawTop) { 24941 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 24942 } 24943 24944 if (drawBottom) { 24945 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 24946 } 24947 24948 if (drawLeft) { 24949 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 24950 } 24951 24952 if (drawRight) { 24953 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 24954 } 24955 } else { 24956 scrollabilityCache.setFadeColor(solidColor); 24957 } 24958 24959 // Step 3, draw the content 24960 onDraw(canvas); 24961 24962 // Step 4, draw the children 24963 dispatchDraw(canvas); 24964 24965 // Step 5, draw the fade effect and restore layers 24966 final Paint p = scrollabilityCache.paint; 24967 final Matrix matrix = scrollabilityCache.matrix; 24968 final Shader fade = scrollabilityCache.shader; 24969 24970 // must be restored in the reverse order that they were saved 24971 if (drawRight) { 24972 matrix.setScale(1, fadeHeight * rightFadeStrength); 24973 matrix.postRotate(90); 24974 matrix.postTranslate(right, top); 24975 fade.setLocalMatrix(matrix); 24976 p.setShader(fade); 24977 if (solidColor == 0) { 24978 canvas.restoreUnclippedLayer(rightSaveCount, p); 24979 24980 } else { 24981 canvas.drawRect(right - length, top, right, bottom, p); 24982 } 24983 } 24984 24985 if (drawLeft) { 24986 matrix.setScale(1, fadeHeight * leftFadeStrength); 24987 matrix.postRotate(-90); 24988 matrix.postTranslate(left, top); 24989 fade.setLocalMatrix(matrix); 24990 p.setShader(fade); 24991 if (solidColor == 0) { 24992 canvas.restoreUnclippedLayer(leftSaveCount, p); 24993 } else { 24994 canvas.drawRect(left, top, left + length, bottom, p); 24995 } 24996 } 24997 24998 if (drawBottom) { 24999 matrix.setScale(1, fadeHeight * bottomFadeStrength); 25000 matrix.postRotate(180); 25001 matrix.postTranslate(left, bottom); 25002 fade.setLocalMatrix(matrix); 25003 p.setShader(fade); 25004 if (solidColor == 0) { 25005 canvas.restoreUnclippedLayer(bottomSaveCount, p); 25006 } else { 25007 canvas.drawRect(left, bottom - length, right, bottom, p); 25008 } 25009 } 25010 25011 if (drawTop) { 25012 matrix.setScale(1, fadeHeight * topFadeStrength); 25013 matrix.postTranslate(left, top); 25014 fade.setLocalMatrix(matrix); 25015 p.setShader(fade); 25016 if (solidColor == 0) { 25017 canvas.restoreUnclippedLayer(topSaveCount, p); 25018 } else { 25019 canvas.drawRect(left, top, right, top + length, p); 25020 } 25021 } 25022 25023 canvas.restoreToCount(saveCount); 25024 25025 drawAutofilledHighlight(canvas); 25026 25027 // Overlay is part of the content and draws beneath Foreground 25028 if (mOverlay != null && !mOverlay.isEmpty()) { 25029 mOverlay.getOverlayView().dispatchDraw(canvas); 25030 } 25031 25032 // Step 6, draw decorations (foreground, scrollbars) 25033 onDrawForeground(canvas); 25034 25035 // Step 7, draw the default focus highlight 25036 drawDefaultFocusHighlight(canvas); 25037 25038 if (isShowingLayoutBounds()) { 25039 debugDrawFocus(canvas); 25040 } 25041 } 25042 25043 /** 25044 * Draws the background onto the specified canvas. 25045 * 25046 * @param canvas Canvas on which to draw the background 25047 */ 25048 @UnsupportedAppUsage drawBackground(@onNull Canvas canvas)25049 private void drawBackground(@NonNull Canvas canvas) { 25050 final Drawable background = mBackground; 25051 if (background == null) { 25052 return; 25053 } 25054 25055 setBackgroundBounds(); 25056 25057 // Attempt to use a display list if requested. 25058 if (canvas.isHardwareAccelerated() && mAttachInfo != null 25059 && mAttachInfo.mThreadedRenderer != null) { 25060 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 25061 25062 final RenderNode renderNode = mBackgroundRenderNode; 25063 if (renderNode != null && renderNode.hasDisplayList()) { 25064 setBackgroundRenderNodeProperties(renderNode); 25065 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 25066 return; 25067 } 25068 } 25069 25070 final int scrollX = mScrollX; 25071 final int scrollY = mScrollY; 25072 if ((scrollX | scrollY) == 0) { 25073 background.draw(canvas); 25074 } else { 25075 canvas.translate(scrollX, scrollY); 25076 background.draw(canvas); 25077 canvas.translate(-scrollX, -scrollY); 25078 } 25079 } 25080 25081 /** 25082 * Sets the correct background bounds and rebuilds the outline, if needed. 25083 * <p/> 25084 * This is called by LayoutLib. 25085 */ setBackgroundBounds()25086 void setBackgroundBounds() { 25087 if (mBackgroundSizeChanged && mBackground != null) { 25088 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 25089 mBackgroundSizeChanged = false; 25090 rebuildOutline(); 25091 } 25092 } 25093 setBackgroundRenderNodeProperties(RenderNode renderNode)25094 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 25095 renderNode.setTranslationX(mScrollX); 25096 renderNode.setTranslationY(mScrollY); 25097 } 25098 25099 /** 25100 * Creates a new display list or updates the existing display list for the 25101 * specified Drawable. 25102 * 25103 * @param drawable Drawable for which to create a display list 25104 * @param renderNode Existing RenderNode, or {@code null} 25105 * @return A valid display list for the specified drawable 25106 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)25107 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 25108 if (renderNode == null) { 25109 renderNode = RenderNode.create(drawable.getClass().getName(), 25110 new ViewAnimationHostBridge(this)); 25111 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 25112 } 25113 25114 final Rect bounds = drawable.getBounds(); 25115 final int width = bounds.width(); 25116 final int height = bounds.height(); 25117 25118 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 25119 // instead of being "stateful" like other RenderNode properties 25120 renderNode.clearStretch(); 25121 25122 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 25123 25124 // Reverse left/top translation done by drawable canvas, which will 25125 // instead be applied by rendernode's LTRB bounds below. This way, the 25126 // drawable's bounds match with its rendernode bounds and its content 25127 // will lie within those bounds in the rendernode tree. 25128 canvas.translate(-bounds.left, -bounds.top); 25129 25130 try { 25131 drawable.draw(canvas); 25132 } finally { 25133 renderNode.endRecording(); 25134 } 25135 25136 // Set up drawable properties that are view-independent. 25137 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 25138 renderNode.setProjectBackwards(drawable.isProjected()); 25139 renderNode.setProjectionReceiver(true); 25140 renderNode.setClipToBounds(false); 25141 return renderNode; 25142 } 25143 25144 /** 25145 * Returns the overlay for this view, creating it if it does not yet exist. 25146 * Adding drawables to the overlay will cause them to be displayed whenever 25147 * the view itself is redrawn. Objects in the overlay should be actively 25148 * managed: remove them when they should not be displayed anymore. The 25149 * overlay will always have the same size as its host view. 25150 * 25151 * <p>Note: Overlays do not currently work correctly with {@link 25152 * SurfaceView} or {@link TextureView}; contents in overlays for these 25153 * types of views may not display correctly.</p> 25154 * 25155 * @return The ViewOverlay object for this view. 25156 * @see ViewOverlay 25157 */ getOverlay()25158 public ViewOverlay getOverlay() { 25159 if (mOverlay == null) { 25160 mOverlay = new ViewOverlay(mContext, this); 25161 } 25162 return mOverlay; 25163 } 25164 25165 /** 25166 * Override this if your view is known to always be drawn on top of a solid color background, 25167 * and needs to draw fading edges. Returning a non-zero color enables the view system to 25168 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 25169 * should be set to 0xFF. 25170 * 25171 * @see #setVerticalFadingEdgeEnabled(boolean) 25172 * @see #setHorizontalFadingEdgeEnabled(boolean) 25173 * 25174 * @return The known solid color background for this view, or 0 if the color may vary 25175 */ 25176 @ViewDebug.ExportedProperty(category = "drawing") 25177 @InspectableProperty 25178 @ColorInt getSolidColor()25179 public int getSolidColor() { 25180 return 0; 25181 } 25182 25183 /** 25184 * Build a human readable string representation of the specified view flags. 25185 * 25186 * @param flags the view flags to convert to a string 25187 * @return a String representing the supplied flags 25188 */ printFlags(int flags)25189 private static String printFlags(int flags) { 25190 String output = ""; 25191 int numFlags = 0; 25192 if ((flags & FOCUSABLE) == FOCUSABLE) { 25193 output += "TAKES_FOCUS"; 25194 numFlags++; 25195 } 25196 25197 switch (flags & VISIBILITY_MASK) { 25198 case INVISIBLE: 25199 if (numFlags > 0) { 25200 output += " "; 25201 } 25202 output += "INVISIBLE"; 25203 // USELESS HERE numFlags++; 25204 break; 25205 case GONE: 25206 if (numFlags > 0) { 25207 output += " "; 25208 } 25209 output += "GONE"; 25210 // USELESS HERE numFlags++; 25211 break; 25212 default: 25213 break; 25214 } 25215 return output; 25216 } 25217 25218 /** 25219 * Build a human readable string representation of the specified private 25220 * view flags. 25221 * 25222 * @param privateFlags the private view flags to convert to a string 25223 * @return a String representing the supplied flags 25224 */ printPrivateFlags(int privateFlags)25225 private static String printPrivateFlags(int privateFlags) { 25226 String output = ""; 25227 int numFlags = 0; 25228 25229 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 25230 output += "WANTS_FOCUS"; 25231 numFlags++; 25232 } 25233 25234 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 25235 if (numFlags > 0) { 25236 output += " "; 25237 } 25238 output += "FOCUSED"; 25239 numFlags++; 25240 } 25241 25242 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 25243 if (numFlags > 0) { 25244 output += " "; 25245 } 25246 output += "SELECTED"; 25247 numFlags++; 25248 } 25249 25250 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 25251 if (numFlags > 0) { 25252 output += " "; 25253 } 25254 output += "IS_ROOT_NAMESPACE"; 25255 numFlags++; 25256 } 25257 25258 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 25259 if (numFlags > 0) { 25260 output += " "; 25261 } 25262 output += "HAS_BOUNDS"; 25263 numFlags++; 25264 } 25265 25266 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 25267 if (numFlags > 0) { 25268 output += " "; 25269 } 25270 output += "DRAWN"; 25271 // USELESS HERE numFlags++; 25272 } 25273 return output; 25274 } 25275 25276 /** 25277 * <p>Indicates whether or not this view's layout will be requested during 25278 * the next hierarchy layout pass.</p> 25279 * 25280 * @return true if the layout will be forced during next layout pass 25281 */ isLayoutRequested()25282 public boolean isLayoutRequested() { 25283 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 25284 } 25285 25286 /** 25287 * Return true if o is a ViewGroup that is laying out using optical bounds. 25288 * @hide 25289 */ isLayoutModeOptical(Object o)25290 public static boolean isLayoutModeOptical(Object o) { 25291 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 25292 } 25293 25294 /** 25295 * Enable measure/layout debugging on traces. 25296 * 25297 * @see Trace 25298 * @hide 25299 */ setTraceLayoutSteps(boolean traceLayoutSteps)25300 public static void setTraceLayoutSteps(boolean traceLayoutSteps) { 25301 sTraceLayoutSteps = traceLayoutSteps; 25302 } 25303 25304 /** 25305 * Enable request layout tracing classes with {@code s} simple name. 25306 * <p> 25307 * When set, a {@link Trace} instant event and a log with the stacktrace is emitted every 25308 * time a requestLayout of a class matching {@code s} name happens. 25309 * This applies only to views attached from this point onwards. 25310 * 25311 * @see Trace#instant(long, String) 25312 * @hide 25313 */ setTracedRequestLayoutClassClass(String s)25314 public static void setTracedRequestLayoutClassClass(String s) { 25315 sTraceRequestLayoutClass = s; 25316 } 25317 setOpticalFrame(int left, int top, int right, int bottom)25318 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 25319 Insets parentInsets = mParent instanceof View ? 25320 ((View) mParent).getOpticalInsets() : Insets.NONE; 25321 Insets childInsets = getOpticalInsets(); 25322 return setFrame( 25323 left + parentInsets.left - childInsets.left, 25324 top + parentInsets.top - childInsets.top, 25325 right + parentInsets.left + childInsets.right, 25326 bottom + parentInsets.top + childInsets.bottom); 25327 } 25328 25329 /** 25330 * Assign a size and position to a view and all of its 25331 * descendants 25332 * 25333 * <p>This is the second phase of the layout mechanism. 25334 * (The first is measuring). In this phase, each parent calls 25335 * layout on all of its children to position them. 25336 * This is typically done using the child measurements 25337 * that were stored in the measure pass().</p> 25338 * 25339 * <p>Derived classes should not override this method. 25340 * Derived classes with children should override 25341 * onLayout. In that method, they should 25342 * call layout on each of their children.</p> 25343 * 25344 * @param l Left position, relative to parent 25345 * @param t Top position, relative to parent 25346 * @param r Right position, relative to parent 25347 * @param b Bottom position, relative to parent 25348 */ 25349 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)25350 public void layout(int l, int t, int r, int b) { 25351 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 25352 if (isTraversalTracingEnabled()) { 25353 Trace.beginSection(mTracingStrings.onMeasureBeforeLayout); 25354 } 25355 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 25356 if (isTraversalTracingEnabled()) { 25357 Trace.endSection(); 25358 } 25359 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25360 } 25361 25362 int oldL = mLeft; 25363 int oldT = mTop; 25364 int oldB = mBottom; 25365 int oldR = mRight; 25366 25367 boolean changed = isLayoutModeOptical(mParent) ? 25368 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 25369 25370 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 25371 if (isTraversalTracingEnabled()) { 25372 Trace.beginSection(mTracingStrings.onLayout); 25373 } 25374 onLayout(changed, l, t, r, b); 25375 if (isTraversalTracingEnabled()) { 25376 Trace.endSection(); 25377 } 25378 25379 if (shouldDrawRoundScrollbar()) { 25380 if(mRoundScrollbarRenderer == null) { 25381 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 25382 } 25383 } else { 25384 mRoundScrollbarRenderer = null; 25385 } 25386 25387 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 25388 25389 ListenerInfo li = mListenerInfo; 25390 if (li != null && li.mOnLayoutChangeListeners != null) { 25391 ArrayList<OnLayoutChangeListener> listenersCopy = 25392 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 25393 int numListeners = listenersCopy.size(); 25394 for (int i = 0; i < numListeners; ++i) { 25395 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 25396 } 25397 } 25398 } 25399 25400 final boolean wasLayoutValid = isLayoutValid(); 25401 25402 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 25403 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 25404 25405 if (!wasLayoutValid && isFocused()) { 25406 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 25407 if (canTakeFocus()) { 25408 // We have a robust focus, so parents should no longer be wanting focus. 25409 clearParentsWantFocus(); 25410 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 25411 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 25412 // layout. In this case, there's no guarantee that parent layouts will be evaluated 25413 // and thus the safest action is to clear focus here. 25414 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 25415 clearParentsWantFocus(); 25416 } else if (!hasParentWantsFocus()) { 25417 // original requestFocus was likely on this view directly, so just clear focus 25418 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 25419 } 25420 // otherwise, we let parents handle re-assigning focus during their layout passes. 25421 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 25422 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 25423 View focused = findFocus(); 25424 if (focused != null) { 25425 // Try to restore focus as close as possible to our starting focus. 25426 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 25427 // Give up and clear focus once we've reached the top-most parent which wants 25428 // focus. 25429 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 25430 } 25431 } 25432 } 25433 25434 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 25435 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 25436 notifyEnterOrExitForAutoFillIfNeeded(true); 25437 } 25438 25439 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 25440 } 25441 hasParentWantsFocus()25442 private boolean hasParentWantsFocus() { 25443 ViewParent parent = mParent; 25444 while (parent instanceof ViewGroup) { 25445 ViewGroup pv = (ViewGroup) parent; 25446 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 25447 return true; 25448 } 25449 parent = pv.mParent; 25450 } 25451 return false; 25452 } 25453 25454 /** 25455 * Called from layout when this view should 25456 * assign a size and position to each of its children. 25457 * 25458 * Derived classes with children should override 25459 * this method and call layout on each of 25460 * their children. 25461 * @param changed This is a new size or position for this view 25462 * @param left Left position, relative to parent 25463 * @param top Top position, relative to parent 25464 * @param right Right position, relative to parent 25465 * @param bottom Bottom position, relative to parent 25466 */ onLayout(boolean changed, int left, int top, int right, int bottom)25467 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 25468 } 25469 25470 /** 25471 * Assign a size and position to this view. 25472 * 25473 * This is called from layout. 25474 * 25475 * @param left Left position, relative to parent 25476 * @param top Top position, relative to parent 25477 * @param right Right position, relative to parent 25478 * @param bottom Bottom position, relative to parent 25479 * @return true if the new size and position are different than the 25480 * previous ones 25481 * {@hide} 25482 */ 25483 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)25484 protected boolean setFrame(int left, int top, int right, int bottom) { 25485 boolean changed = false; 25486 25487 if (DBG) { 25488 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 25489 + right + "," + bottom + ")"); 25490 } 25491 25492 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 25493 changed = true; 25494 25495 // Remember our drawn bit 25496 int drawn = mPrivateFlags & PFLAG_DRAWN; 25497 25498 int oldWidth = mRight - mLeft; 25499 int oldHeight = mBottom - mTop; 25500 int newWidth = right - left; 25501 int newHeight = bottom - top; 25502 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 25503 25504 // Invalidate our old position 25505 invalidate(sizeChanged); 25506 25507 mLeft = left; 25508 mTop = top; 25509 mRight = right; 25510 mBottom = bottom; 25511 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 25512 25513 mPrivateFlags |= PFLAG_HAS_BOUNDS; 25514 25515 25516 if (sizeChanged) { 25517 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 25518 } 25519 25520 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 25521 // If we are visible, force the DRAWN bit to on so that 25522 // this invalidate will go through (at least to our parent). 25523 // This is because someone may have invalidated this view 25524 // before this call to setFrame came in, thereby clearing 25525 // the DRAWN bit. 25526 mPrivateFlags |= PFLAG_DRAWN; 25527 invalidate(sizeChanged); 25528 // parent display list may need to be recreated based on a change in the bounds 25529 // of any child 25530 invalidateParentCaches(); 25531 } 25532 25533 // Reset drawn bit to original value (invalidate turns it off) 25534 mPrivateFlags |= drawn; 25535 25536 mBackgroundSizeChanged = true; 25537 mDefaultFocusHighlightSizeChanged = true; 25538 if (mForegroundInfo != null) { 25539 mForegroundInfo.mBoundsChanged = true; 25540 } 25541 25542 notifySubtreeAccessibilityStateChangedIfNeeded(); 25543 } 25544 return changed; 25545 } 25546 25547 /** 25548 * Assign a size and position to this view. 25549 * 25550 * This method is meant to be used in animations only as it applies this position and size 25551 * for the view only temporary and it can be changed back at any time by the layout. 25552 * 25553 * @param left Left position, relative to parent 25554 * @param top Top position, relative to parent 25555 * @param right Right position, relative to parent 25556 * @param bottom Bottom position, relative to parent 25557 * 25558 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 25559 */ setLeftTopRightBottom(int left, int top, int right, int bottom)25560 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 25561 setFrame(left, top, right, bottom); 25562 } 25563 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)25564 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 25565 if (mAttachInfo != null && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 25566 boolean isSmall; 25567 if (sToolkitFrameRateSmallUsesPercentReadOnlyFlagValue) { 25568 int size = newWidth * newHeight; 25569 float percent = size / mAttachInfo.mDisplayPixelCount; 25570 isSmall = percent <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD; 25571 } else { 25572 float density = mAttachInfo.mDensity; 25573 int narrowSize = (int) (density * FRAME_RATE_NARROW_SIZE_DP); 25574 int smallSize = (int) (density * FRAME_RATE_SQUARE_SMALL_SIZE_DP); 25575 isSmall = newWidth <= narrowSize || newHeight <= narrowSize 25576 || (newWidth <= smallSize && newHeight <= smallSize); 25577 } 25578 if (isSmall) { 25579 int category = sToolkitFrameRateBySizeReadOnlyFlagValue 25580 ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; 25581 mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_SMALL; 25582 } else { 25583 int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue 25584 ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; 25585 mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE; 25586 } 25587 } 25588 25589 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 25590 if (mOverlay != null) { 25591 mOverlay.getOverlayView().setRight(newWidth); 25592 mOverlay.getOverlayView().setBottom(newHeight); 25593 } 25594 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 25595 // backtracking" of requestFocus during layout, so don't touch focus here. 25596 if (!sCanFocusZeroSized && isLayoutValid() 25597 // Don't touch focus if animating 25598 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 25599 if (newWidth <= 0 || newHeight <= 0) { 25600 if (hasFocus()) { 25601 clearFocus(); 25602 if (mParent instanceof ViewGroup) { 25603 ((ViewGroup) mParent).clearFocusedInCluster(); 25604 } 25605 } 25606 clearAccessibilityFocus(); 25607 } else if (oldWidth <= 0 || oldHeight <= 0) { 25608 if (mParent != null && canTakeFocus()) { 25609 mParent.focusableViewAvailable(this); 25610 } 25611 } 25612 } 25613 rebuildOutline(); 25614 if (onCheckIsTextEditor() || mHandwritingDelegatorCallback != null) { 25615 setHandwritingArea(new Rect(0, 0, newWidth, newHeight)); 25616 } 25617 } 25618 25619 /** 25620 * Finalize inflating a view from XML. This is called as the last phase 25621 * of inflation, after all child views have been added. 25622 * 25623 * <p>Even if the subclass overrides onFinishInflate, they should always be 25624 * sure to call the super method, so that we get called. 25625 */ 25626 @CallSuper onFinishInflate()25627 protected void onFinishInflate() { 25628 } 25629 25630 /** 25631 * Returns the resources associated with this view. 25632 * 25633 * @return Resources object. 25634 */ getResources()25635 public Resources getResources() { 25636 return mResources; 25637 } 25638 25639 /** 25640 * Invalidates the specified Drawable. 25641 * 25642 * @param drawable the drawable to invalidate 25643 */ 25644 @Override invalidateDrawable(@onNull Drawable drawable)25645 public void invalidateDrawable(@NonNull Drawable drawable) { 25646 if (verifyDrawable(drawable)) { 25647 final Rect dirty = drawable.getDirtyBounds(); 25648 final int scrollX = mScrollX; 25649 final int scrollY = mScrollY; 25650 25651 invalidate(dirty.left + scrollX, dirty.top + scrollY, 25652 dirty.right + scrollX, dirty.bottom + scrollY); 25653 rebuildOutline(); 25654 } 25655 } 25656 25657 /** 25658 * Schedules an action on a drawable to occur at a specified time. 25659 * 25660 * @param who the recipient of the action 25661 * @param what the action to run on the drawable 25662 * @param when the time at which the action must occur. Uses the 25663 * {@link SystemClock#uptimeMillis} timebase. 25664 */ 25665 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)25666 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 25667 if (verifyDrawable(who) && what != null) { 25668 final long delay = when - SystemClock.uptimeMillis(); 25669 if (mAttachInfo != null) { 25670 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 25671 Choreographer.CALLBACK_ANIMATION, what, who, 25672 Choreographer.subtractFrameDelay(delay)); 25673 } else { 25674 // Postpone the runnable until we know 25675 // on which thread it needs to run. 25676 getRunQueue().postDelayed(what, delay); 25677 } 25678 } 25679 } 25680 25681 /** 25682 * Cancels a scheduled action on a drawable. 25683 * 25684 * @param who the recipient of the action 25685 * @param what the action to cancel 25686 */ 25687 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)25688 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 25689 if (verifyDrawable(who) && what != null) { 25690 if (mAttachInfo != null) { 25691 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 25692 Choreographer.CALLBACK_ANIMATION, what, who); 25693 } 25694 getRunQueue().removeCallbacks(what); 25695 } 25696 } 25697 25698 /** 25699 * Unschedule any events associated with the given Drawable. This can be 25700 * used when selecting a new Drawable into a view, so that the previous 25701 * one is completely unscheduled. 25702 * 25703 * @param who The Drawable to unschedule. 25704 * 25705 * @see #drawableStateChanged 25706 */ unscheduleDrawable(Drawable who)25707 public void unscheduleDrawable(Drawable who) { 25708 if (mAttachInfo != null && who != null) { 25709 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 25710 Choreographer.CALLBACK_ANIMATION, null, who); 25711 } 25712 } 25713 25714 /** 25715 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 25716 * that the View directionality can and will be resolved before its Drawables. 25717 * 25718 * Will call {@link View#onResolveDrawables} when resolution is done. 25719 * 25720 * @hide 25721 */ resolveDrawables()25722 protected void resolveDrawables() { 25723 // Drawables resolution may need to happen before resolving the layout direction (which is 25724 // done only during the measure() call). 25725 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 25726 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 25727 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 25728 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 25729 // direction to be resolved as its resolved value will be the same as its raw value. 25730 if (!isLayoutDirectionResolved() && 25731 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 25732 return; 25733 } 25734 25735 final int layoutDirection = isLayoutDirectionResolved() ? 25736 getLayoutDirection() : getRawLayoutDirection(); 25737 25738 if (mBackground != null) { 25739 mBackground.setLayoutDirection(layoutDirection); 25740 } 25741 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 25742 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 25743 } 25744 if (mDefaultFocusHighlight != null) { 25745 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 25746 } 25747 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 25748 onResolveDrawables(layoutDirection); 25749 } 25750 areDrawablesResolved()25751 boolean areDrawablesResolved() { 25752 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 25753 } 25754 25755 /** 25756 * Called when layout direction has been resolved. 25757 * 25758 * The default implementation does nothing. 25759 * 25760 * @param layoutDirection The resolved layout direction. 25761 * 25762 * @see #LAYOUT_DIRECTION_LTR 25763 * @see #LAYOUT_DIRECTION_RTL 25764 * 25765 * @hide 25766 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)25767 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 25768 } 25769 25770 /** 25771 * @hide 25772 */ 25773 @TestApi resetResolvedDrawables()25774 protected void resetResolvedDrawables() { 25775 resetResolvedDrawablesInternal(); 25776 } 25777 resetResolvedDrawablesInternal()25778 void resetResolvedDrawablesInternal() { 25779 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 25780 } 25781 25782 /** 25783 * If your view subclass is displaying its own Drawable objects, it should 25784 * override this function and return true for any Drawable it is 25785 * displaying. This allows animations for those drawables to be 25786 * scheduled. 25787 * 25788 * <p>Be sure to call through to the super class when overriding this 25789 * function. 25790 * 25791 * @param who The Drawable to verify. Return true if it is one you are 25792 * displaying, else return the result of calling through to the 25793 * super class. 25794 * 25795 * @return boolean If true then the Drawable is being displayed in the 25796 * view; else false and it is not allowed to animate. 25797 * 25798 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 25799 * @see #drawableStateChanged() 25800 */ 25801 @CallSuper verifyDrawable(@onNull Drawable who)25802 protected boolean verifyDrawable(@NonNull Drawable who) { 25803 // Avoid verifying the scroll bar drawable so that we don't end up in 25804 // an invalidation loop. This effectively prevents the scroll bar 25805 // drawable from triggering invalidations and scheduling runnables. 25806 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 25807 || (mDefaultFocusHighlight == who); 25808 } 25809 25810 /** 25811 * This function is called whenever the state of the view changes in such 25812 * a way that it impacts the state of drawables being shown. 25813 * <p> 25814 * If the View has a StateListAnimator, it will also be called to run necessary state 25815 * change animations. 25816 * <p> 25817 * Be sure to call through to the superclass when overriding this function. 25818 * 25819 * @see Drawable#setState(int[]) 25820 */ 25821 @CallSuper drawableStateChanged()25822 protected void drawableStateChanged() { 25823 final int[] state = getDrawableState(); 25824 boolean changed = false; 25825 25826 final Drawable bg = mBackground; 25827 if (bg != null && bg.isStateful()) { 25828 changed |= bg.setState(state); 25829 } 25830 25831 final Drawable hl = mDefaultFocusHighlight; 25832 if (hl != null && hl.isStateful()) { 25833 changed |= hl.setState(state); 25834 } 25835 25836 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 25837 if (fg != null && fg.isStateful()) { 25838 changed |= fg.setState(state); 25839 } 25840 25841 if (mScrollCache != null) { 25842 final Drawable scrollBar = mScrollCache.scrollBar; 25843 if (scrollBar != null && scrollBar.isStateful()) { 25844 changed |= scrollBar.setState(state) 25845 && mScrollCache.state != ScrollabilityCache.OFF; 25846 } 25847 } 25848 25849 if (mStateListAnimator != null) { 25850 mStateListAnimator.setState(state); 25851 } 25852 25853 if (!isAggregatedVisible()) { 25854 // If we're not visible, skip any animated changes 25855 jumpDrawablesToCurrentState(); 25856 } 25857 25858 if (changed) { 25859 invalidate(); 25860 } 25861 } 25862 25863 /** 25864 * This function is called whenever the view hotspot changes and needs to 25865 * be propagated to drawables or child views managed by the view. 25866 * <p> 25867 * Dispatching to child views is handled by 25868 * {@link #dispatchDrawableHotspotChanged(float, float)}. 25869 * <p> 25870 * Be sure to call through to the superclass when overriding this function. 25871 * 25872 * @param x hotspot x coordinate 25873 * @param y hotspot y coordinate 25874 */ 25875 @CallSuper drawableHotspotChanged(float x, float y)25876 public void drawableHotspotChanged(float x, float y) { 25877 if (mBackground != null) { 25878 mBackground.setHotspot(x, y); 25879 } 25880 if (mDefaultFocusHighlight != null) { 25881 mDefaultFocusHighlight.setHotspot(x, y); 25882 } 25883 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 25884 mForegroundInfo.mDrawable.setHotspot(x, y); 25885 } 25886 25887 dispatchDrawableHotspotChanged(x, y); 25888 } 25889 25890 /** 25891 * Dispatches drawableHotspotChanged to all of this View's children. 25892 * 25893 * @param x hotspot x coordinate 25894 * @param y hotspot y coordinate 25895 * @see #drawableHotspotChanged(float, float) 25896 */ dispatchDrawableHotspotChanged(float x, float y)25897 public void dispatchDrawableHotspotChanged(float x, float y) { 25898 } 25899 25900 /** 25901 * Call this to force a view to update its drawable state. This will cause 25902 * drawableStateChanged to be called on this view. Views that are interested 25903 * in the new state should call getDrawableState. 25904 * 25905 * @see #drawableStateChanged 25906 * @see #getDrawableState 25907 */ refreshDrawableState()25908 public void refreshDrawableState() { 25909 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 25910 drawableStateChanged(); 25911 25912 ViewParent parent = mParent; 25913 if (parent != null) { 25914 parent.childDrawableStateChanged(this); 25915 } 25916 } 25917 25918 /** 25919 * Create a default focus highlight if it doesn't exist. 25920 * @return a default focus highlight. 25921 */ getDefaultFocusHighlightDrawable()25922 private Drawable getDefaultFocusHighlightDrawable() { 25923 if (mDefaultFocusHighlightCache == null) { 25924 if (mContext != null) { 25925 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 25926 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 25927 mDefaultFocusHighlightCache = ta.getDrawable(0); 25928 ta.recycle(); 25929 } 25930 } 25931 return mDefaultFocusHighlightCache; 25932 } 25933 25934 /** 25935 * Set the current default focus highlight. 25936 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 25937 */ setDefaultFocusHighlight(Drawable highlight)25938 private void setDefaultFocusHighlight(Drawable highlight) { 25939 mDefaultFocusHighlight = highlight; 25940 mDefaultFocusHighlightSizeChanged = true; 25941 if (highlight != null) { 25942 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 25943 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 25944 } 25945 highlight.setLayoutDirection(getLayoutDirection()); 25946 if (highlight.isStateful()) { 25947 highlight.setState(getDrawableState()); 25948 } 25949 if (isAttachedToWindow()) { 25950 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 25951 } 25952 // Set callback last, since the view may still be initializing. 25953 highlight.setCallback(this); 25954 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 25955 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 25956 mPrivateFlags |= PFLAG_SKIP_DRAW; 25957 } 25958 invalidate(); 25959 } 25960 25961 /** 25962 * Check whether we need to draw a default focus highlight when this view gets focused, 25963 * which requires: 25964 * <ul> 25965 * <li>In both background and foreground, {@link android.R.attr#state_focused} 25966 * is not defined.</li> 25967 * <li>This view is not in touch mode.</li> 25968 * <li>This view doesn't opt out for a default focus highlight, via 25969 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 25970 * <li>This view is attached to window.</li> 25971 * </ul> 25972 * @return {@code true} if a default focus highlight is needed. 25973 * @hide 25974 */ 25975 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)25976 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 25977 final boolean lackFocusState = (background == null || !background.isStateful() 25978 || !background.hasFocusStateSpecified()) 25979 && (foreground == null || !foreground.isStateful() 25980 || !foreground.hasFocusStateSpecified()); 25981 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 25982 && isAttachedToWindow() && sUseDefaultFocusHighlight; 25983 } 25984 25985 /** 25986 * When this view is focused, switches on/off the default focused highlight. 25987 * <p> 25988 * This always happens when this view is focused, and only at this moment the default focus 25989 * highlight can be visible. 25990 */ switchDefaultFocusHighlight()25991 private void switchDefaultFocusHighlight() { 25992 if (isFocused()) { 25993 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 25994 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 25995 final boolean active = mDefaultFocusHighlight != null; 25996 if (needed && !active) { 25997 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 25998 } else if (!needed && active) { 25999 // The highlight is no longer needed, so tear it down. 26000 setDefaultFocusHighlight(null); 26001 } 26002 } 26003 } 26004 26005 /** 26006 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 26007 * @param canvas the canvas where we're drawing the highlight. 26008 */ drawDefaultFocusHighlight(@onNull Canvas canvas)26009 private void drawDefaultFocusHighlight(@NonNull Canvas canvas) { 26010 if (mDefaultFocusHighlight != null && isFocused()) { 26011 if (mDefaultFocusHighlightSizeChanged) { 26012 mDefaultFocusHighlightSizeChanged = false; 26013 final int l = mScrollX; 26014 final int r = l + mRight - mLeft; 26015 final int t = mScrollY; 26016 final int b = t + mBottom - mTop; 26017 mDefaultFocusHighlight.setBounds(l, t, r, b); 26018 } 26019 mDefaultFocusHighlight.draw(canvas); 26020 } 26021 } 26022 26023 /** 26024 * Return an array of resource IDs of the drawable states representing the 26025 * current state of the view. 26026 * 26027 * @return The current drawable state 26028 * 26029 * @see Drawable#setState(int[]) 26030 * @see #drawableStateChanged() 26031 * @see #onCreateDrawableState(int) 26032 */ getDrawableState()26033 public final int[] getDrawableState() { 26034 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 26035 return mDrawableState; 26036 } else { 26037 mDrawableState = onCreateDrawableState(0); 26038 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 26039 return mDrawableState; 26040 } 26041 } 26042 26043 /** 26044 * Generate the new {@link android.graphics.drawable.Drawable} state for 26045 * this view. This is called by the view 26046 * system when the cached Drawable state is determined to be invalid. To 26047 * retrieve the current state, you should use {@link #getDrawableState}. 26048 * 26049 * @param extraSpace if non-zero, this is the number of extra entries you 26050 * would like in the returned array in which you can place your own 26051 * states. 26052 * 26053 * @return Returns an array holding the current {@link Drawable} state of 26054 * the view. 26055 * 26056 * @see #mergeDrawableStates(int[], int[]) 26057 */ onCreateDrawableState(int extraSpace)26058 protected int[] onCreateDrawableState(int extraSpace) { 26059 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 26060 mParent instanceof View) { 26061 return ((View) mParent).onCreateDrawableState(extraSpace); 26062 } 26063 26064 int[] drawableState; 26065 26066 int privateFlags = mPrivateFlags; 26067 26068 int viewStateIndex = 0; 26069 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 26070 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 26071 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 26072 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 26073 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 26074 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 26075 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { 26076 // This is set if HW acceleration is requested, even if the current 26077 // process doesn't allow it. This is just to allow app preview 26078 // windows to better match their app. 26079 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 26080 } 26081 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 26082 26083 final int privateFlags2 = mPrivateFlags2; 26084 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 26085 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 26086 } 26087 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 26088 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 26089 } 26090 26091 drawableState = StateSet.get(viewStateIndex); 26092 26093 //noinspection ConstantIfStatement 26094 if (false) { 26095 Log.i("View", "drawableStateIndex=" + viewStateIndex); 26096 Log.i("View", toString() 26097 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 26098 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 26099 + " fo=" + hasFocus() 26100 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 26101 + " wf=" + hasWindowFocus() 26102 + ": " + Arrays.toString(drawableState)); 26103 } 26104 26105 if (extraSpace == 0) { 26106 return drawableState; 26107 } 26108 26109 final int[] fullState; 26110 if (drawableState != null) { 26111 fullState = new int[drawableState.length + extraSpace]; 26112 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 26113 } else { 26114 fullState = new int[extraSpace]; 26115 } 26116 26117 return fullState; 26118 } 26119 26120 /** 26121 * Merge your own state values in <var>additionalState</var> into the base 26122 * state values <var>baseState</var> that were returned by 26123 * {@link #onCreateDrawableState(int)}. 26124 * 26125 * @param baseState The base state values returned by 26126 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 26127 * own additional state values. 26128 * 26129 * @param additionalState The additional state values you would like 26130 * added to <var>baseState</var>; this array is not modified. 26131 * 26132 * @return As a convenience, the <var>baseState</var> array you originally 26133 * passed into the function is returned. 26134 * 26135 * @see #onCreateDrawableState(int) 26136 */ mergeDrawableStates(int[] baseState, int[] additionalState)26137 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 26138 final int N = baseState.length; 26139 int i = N - 1; 26140 while (i >= 0 && baseState[i] == 0) { 26141 i--; 26142 } 26143 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 26144 return baseState; 26145 } 26146 26147 /** 26148 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 26149 * on all Drawable objects associated with this view. 26150 * <p> 26151 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 26152 * attached to this view. 26153 */ 26154 @CallSuper jumpDrawablesToCurrentState()26155 public void jumpDrawablesToCurrentState() { 26156 if (mBackground != null) { 26157 mBackground.jumpToCurrentState(); 26158 } 26159 if (mStateListAnimator != null) { 26160 mStateListAnimator.jumpToCurrentState(); 26161 } 26162 if (mDefaultFocusHighlight != null) { 26163 mDefaultFocusHighlight.jumpToCurrentState(); 26164 } 26165 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 26166 mForegroundInfo.mDrawable.jumpToCurrentState(); 26167 } 26168 } 26169 26170 /** 26171 * Sets the background color for this view. 26172 * @param color the color of the background 26173 */ 26174 @RemotableViewMethod setBackgroundColor(@olorInt int color)26175 public void setBackgroundColor(@ColorInt int color) { 26176 if (mBackground instanceof ColorDrawable) { 26177 ((ColorDrawable) mBackground.mutate()).setColor(color); 26178 computeOpaqueFlags(); 26179 mBackgroundResource = 0; 26180 } else { 26181 setBackground(new ColorDrawable(color)); 26182 } 26183 } 26184 26185 /** 26186 * Set the background to a given resource. The resource should refer to 26187 * a Drawable object or 0 to remove the background. 26188 * @param resid The identifier of the resource. 26189 * 26190 * @attr ref android.R.styleable#View_background 26191 */ 26192 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)26193 public void setBackgroundResource(@DrawableRes int resid) { 26194 if (resid != 0 && resid == mBackgroundResource) { 26195 return; 26196 } 26197 26198 Drawable d = null; 26199 if (resid != 0) { 26200 d = mContext.getDrawable(resid); 26201 } 26202 setBackground(d); 26203 26204 mBackgroundResource = resid; 26205 } 26206 26207 /** 26208 * Set the background to a given Drawable, or remove the background. If the 26209 * background has padding, this View's padding is set to the background's 26210 * padding. However, when a background is removed, this View's padding isn't 26211 * touched. If setting the padding is desired, please use 26212 * {@link #setPadding(int, int, int, int)}. 26213 * 26214 * @param background The Drawable to use as the background, or null to remove the 26215 * background 26216 */ setBackground(Drawable background)26217 public void setBackground(Drawable background) { 26218 //noinspection deprecation 26219 setBackgroundDrawable(background); 26220 } 26221 26222 /** 26223 * @deprecated use {@link #setBackground(Drawable)} instead 26224 */ 26225 @Deprecated setBackgroundDrawable(Drawable background)26226 public void setBackgroundDrawable(Drawable background) { 26227 computeOpaqueFlags(); 26228 26229 if (background == mBackground) { 26230 return; 26231 } 26232 26233 boolean requestLayout = false; 26234 26235 mBackgroundResource = 0; 26236 26237 /* 26238 * Regardless of whether we're setting a new background or not, we want 26239 * to clear the previous drawable. setVisible first while we still have the callback set. 26240 */ 26241 if (mBackground != null) { 26242 if (isAttachedToWindow()) { 26243 mBackground.setVisible(false, false); 26244 } 26245 mBackground.setCallback(null); 26246 unscheduleDrawable(mBackground); 26247 } 26248 26249 if (background != null) { 26250 Rect padding = sThreadLocal.get(); 26251 if (padding == null) { 26252 padding = new Rect(); 26253 sThreadLocal.set(padding); 26254 } 26255 resetResolvedDrawablesInternal(); 26256 background.setLayoutDirection(getLayoutDirection()); 26257 if (background.getPadding(padding)) { 26258 resetResolvedPaddingInternal(); 26259 switch (background.getLayoutDirection()) { 26260 case LAYOUT_DIRECTION_RTL: 26261 mUserPaddingLeftInitial = padding.right; 26262 mUserPaddingRightInitial = padding.left; 26263 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 26264 break; 26265 case LAYOUT_DIRECTION_LTR: 26266 default: 26267 mUserPaddingLeftInitial = padding.left; 26268 mUserPaddingRightInitial = padding.right; 26269 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 26270 } 26271 mLeftPaddingDefined = false; 26272 mRightPaddingDefined = false; 26273 } 26274 26275 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 26276 // if it has a different minimum size, we should layout again 26277 if (mBackground == null 26278 || mBackground.getMinimumHeight() != background.getMinimumHeight() 26279 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 26280 requestLayout = true; 26281 } 26282 26283 // Set mBackground before we set this as the callback and start making other 26284 // background drawable state change calls. In particular, the setVisible call below 26285 // can result in drawables attempting to start animations or otherwise invalidate, 26286 // which requires the view set as the callback (us) to recognize the drawable as 26287 // belonging to it as per verifyDrawable. 26288 mBackground = background; 26289 if (background.isStateful()) { 26290 background.setState(getDrawableState()); 26291 } 26292 if (isAttachedToWindow()) { 26293 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 26294 } 26295 26296 applyBackgroundTint(); 26297 26298 // Set callback last, since the view may still be initializing. 26299 background.setCallback(this); 26300 26301 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 26302 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 26303 requestLayout = true; 26304 } 26305 } else { 26306 /* Remove the background */ 26307 mBackground = null; 26308 if ((mViewFlags & WILL_NOT_DRAW) != 0 26309 && (mDefaultFocusHighlight == null) 26310 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 26311 mPrivateFlags |= PFLAG_SKIP_DRAW; 26312 } 26313 26314 /* 26315 * When the background is set, we try to apply its padding to this 26316 * View. When the background is removed, we don't touch this View's 26317 * padding. This is noted in the Javadocs. Hence, we don't need to 26318 * requestLayout(), the invalidate() below is sufficient. 26319 */ 26320 26321 // The old background's minimum size could have affected this 26322 // View's layout, so let's requestLayout 26323 requestLayout = true; 26324 } 26325 26326 computeOpaqueFlags(); 26327 26328 if (requestLayout) { 26329 requestLayout(); 26330 } 26331 26332 mBackgroundSizeChanged = true; 26333 invalidate(true); 26334 invalidateOutline(); 26335 } 26336 26337 /** 26338 * Gets the background drawable 26339 * 26340 * @return The drawable used as the background for this view, if any. 26341 * 26342 * @see #setBackground(Drawable) 26343 * 26344 * @attr ref android.R.styleable#View_background 26345 */ 26346 @InspectableProperty getBackground()26347 public Drawable getBackground() { 26348 return mBackground; 26349 } 26350 26351 /** 26352 * Applies a tint to the background drawable. Does not modify the current tint 26353 * mode, which is {@link BlendMode#SRC_IN} by default. 26354 * <p> 26355 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 26356 * mutate the drawable and apply the specified tint and tint mode using 26357 * {@link Drawable#setTintList(ColorStateList)}. 26358 * 26359 * @param tint the tint to apply, may be {@code null} to clear tint 26360 * 26361 * @attr ref android.R.styleable#View_backgroundTint 26362 * @see #getBackgroundTintList() 26363 * @see Drawable#setTintList(ColorStateList) 26364 */ 26365 @RemotableViewMethod setBackgroundTintList(@ullable ColorStateList tint)26366 public void setBackgroundTintList(@Nullable ColorStateList tint) { 26367 if (mBackgroundTint == null) { 26368 mBackgroundTint = new TintInfo(); 26369 } 26370 mBackgroundTint.mTintList = tint; 26371 mBackgroundTint.mHasTintList = true; 26372 26373 applyBackgroundTint(); 26374 } 26375 26376 /** 26377 * Return the tint applied to the background drawable, if specified. 26378 * 26379 * @return the tint applied to the background drawable 26380 * @attr ref android.R.styleable#View_backgroundTint 26381 * @see #setBackgroundTintList(ColorStateList) 26382 */ 26383 @InspectableProperty(name = "backgroundTint") 26384 @Nullable getBackgroundTintList()26385 public ColorStateList getBackgroundTintList() { 26386 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 26387 } 26388 26389 /** 26390 * Specifies the blending mode used to apply the tint specified by 26391 * {@link #setBackgroundTintList(ColorStateList)}} to the background 26392 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 26393 * 26394 * @param tintMode the blending mode used to apply the tint, may be 26395 * {@code null} to clear tint 26396 * @attr ref android.R.styleable#View_backgroundTintMode 26397 * @see #getBackgroundTintMode() 26398 * @see Drawable#setTintMode(PorterDuff.Mode) 26399 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)26400 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 26401 BlendMode mode = null; 26402 if (tintMode != null) { 26403 mode = BlendMode.fromValue(tintMode.nativeInt); 26404 } 26405 26406 setBackgroundTintBlendMode(mode); 26407 } 26408 26409 /** 26410 * Specifies the blending mode used to apply the tint specified by 26411 * {@link #setBackgroundTintList(ColorStateList)}} to the background 26412 * drawable. The default mode is {@link BlendMode#SRC_IN}. 26413 * 26414 * @param blendMode the blending mode used to apply the tint, may be 26415 * {@code null} to clear tint 26416 * @attr ref android.R.styleable#View_backgroundTintMode 26417 * @see #getBackgroundTintMode() 26418 * @see Drawable#setTintBlendMode(BlendMode) 26419 */ 26420 @RemotableViewMethod setBackgroundTintBlendMode(@ullable BlendMode blendMode)26421 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 26422 if (mBackgroundTint == null) { 26423 mBackgroundTint = new TintInfo(); 26424 } 26425 26426 mBackgroundTint.mBlendMode = blendMode; 26427 mBackgroundTint.mHasTintMode = true; 26428 26429 applyBackgroundTint(); 26430 } 26431 26432 /** 26433 * Return the blending mode used to apply the tint to the background 26434 * drawable, if specified. 26435 * 26436 * @return the blending mode used to apply the tint to the background 26437 * drawable 26438 * @attr ref android.R.styleable#View_backgroundTintMode 26439 * @see #setBackgroundTintBlendMode(BlendMode) 26440 * 26441 */ 26442 @Nullable 26443 @InspectableProperty getBackgroundTintMode()26444 public PorterDuff.Mode getBackgroundTintMode() { 26445 PorterDuff.Mode porterDuffMode; 26446 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 26447 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 26448 } else { 26449 porterDuffMode = null; 26450 } 26451 return porterDuffMode; 26452 } 26453 26454 /** 26455 * Return the blending mode used to apply the tint to the background 26456 * drawable, if specified. 26457 * 26458 * @return the blending mode used to apply the tint to the background 26459 * drawable, null if no blend has previously been configured 26460 * @attr ref android.R.styleable#View_backgroundTintMode 26461 * @see #setBackgroundTintBlendMode(BlendMode) 26462 */ getBackgroundTintBlendMode()26463 public @Nullable BlendMode getBackgroundTintBlendMode() { 26464 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 26465 } 26466 applyBackgroundTint()26467 private void applyBackgroundTint() { 26468 if (mBackground != null && mBackgroundTint != null) { 26469 final TintInfo tintInfo = mBackgroundTint; 26470 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 26471 mBackground = mBackground.mutate(); 26472 26473 if (tintInfo.mHasTintList) { 26474 mBackground.setTintList(tintInfo.mTintList); 26475 } 26476 26477 if (tintInfo.mHasTintMode) { 26478 mBackground.setTintBlendMode(tintInfo.mBlendMode); 26479 } 26480 26481 // The drawable (or one of its children) may not have been 26482 // stateful before applying the tint, so let's try again. 26483 if (mBackground.isStateful()) { 26484 mBackground.setState(getDrawableState()); 26485 } 26486 } 26487 } 26488 } 26489 26490 /** 26491 * Returns the drawable used as the foreground of this View. The 26492 * foreground drawable, if non-null, is always drawn on top of the view's content. 26493 * 26494 * @return a Drawable or null if no foreground was set 26495 * 26496 * @see #onDrawForeground(Canvas) 26497 */ 26498 @InspectableProperty getForeground()26499 public Drawable getForeground() { 26500 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 26501 } 26502 26503 /** 26504 * Supply a Drawable that is to be rendered on top of all of the content in the view. 26505 * 26506 * @param foreground the Drawable to be drawn on top of the children 26507 * 26508 * @attr ref android.R.styleable#View_foreground 26509 */ setForeground(Drawable foreground)26510 public void setForeground(Drawable foreground) { 26511 if (mForegroundInfo == null) { 26512 if (foreground == null) { 26513 // Nothing to do. 26514 return; 26515 } 26516 mForegroundInfo = new ForegroundInfo(); 26517 } 26518 26519 if (foreground == mForegroundInfo.mDrawable) { 26520 // Nothing to do 26521 return; 26522 } 26523 26524 if (mForegroundInfo.mDrawable != null) { 26525 if (isAttachedToWindow()) { 26526 mForegroundInfo.mDrawable.setVisible(false, false); 26527 } 26528 mForegroundInfo.mDrawable.setCallback(null); 26529 unscheduleDrawable(mForegroundInfo.mDrawable); 26530 } 26531 26532 mForegroundInfo.mDrawable = foreground; 26533 mForegroundInfo.mBoundsChanged = true; 26534 if (foreground != null) { 26535 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 26536 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 26537 } 26538 foreground.setLayoutDirection(getLayoutDirection()); 26539 if (foreground.isStateful()) { 26540 foreground.setState(getDrawableState()); 26541 } 26542 applyForegroundTint(); 26543 if (isAttachedToWindow()) { 26544 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 26545 } 26546 // Set callback last, since the view may still be initializing. 26547 foreground.setCallback(this); 26548 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 26549 && (mDefaultFocusHighlight == null)) { 26550 mPrivateFlags |= PFLAG_SKIP_DRAW; 26551 } 26552 requestLayout(); 26553 invalidate(); 26554 } 26555 26556 /** 26557 * Magic bit used to support features of framework-internal window decor implementation details. 26558 * This used to live exclusively in FrameLayout. 26559 * 26560 * @return true if the foreground should draw inside the padding region or false 26561 * if it should draw inset by the view's padding 26562 * @hide internal use only; only used by FrameLayout and internal screen layouts. 26563 */ isForegroundInsidePadding()26564 public boolean isForegroundInsidePadding() { 26565 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 26566 } 26567 26568 /** 26569 * Describes how the foreground is positioned. 26570 * 26571 * @return foreground gravity. 26572 * 26573 * @see #setForegroundGravity(int) 26574 * 26575 * @attr ref android.R.styleable#View_foregroundGravity 26576 */ 26577 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()26578 public int getForegroundGravity() { 26579 return mForegroundInfo != null ? mForegroundInfo.mGravity 26580 : Gravity.START | Gravity.TOP; 26581 } 26582 26583 /** 26584 * Describes how the foreground is positioned. Defaults to START and TOP. 26585 * 26586 * @param gravity see {@link android.view.Gravity} 26587 * 26588 * @see #getForegroundGravity() 26589 * 26590 * @attr ref android.R.styleable#View_foregroundGravity 26591 */ setForegroundGravity(int gravity)26592 public void setForegroundGravity(int gravity) { 26593 if (mForegroundInfo == null) { 26594 mForegroundInfo = new ForegroundInfo(); 26595 } 26596 26597 if (mForegroundInfo.mGravity != gravity) { 26598 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 26599 gravity |= Gravity.START; 26600 } 26601 26602 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 26603 gravity |= Gravity.TOP; 26604 } 26605 26606 mForegroundInfo.mGravity = gravity; 26607 requestLayout(); 26608 } 26609 } 26610 26611 /** 26612 * Applies a tint to the foreground drawable. Does not modify the current tint 26613 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 26614 * <p> 26615 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 26616 * mutate the drawable and apply the specified tint and tint mode using 26617 * {@link Drawable#setTintList(ColorStateList)}. 26618 * 26619 * @param tint the tint to apply, may be {@code null} to clear tint 26620 * 26621 * @attr ref android.R.styleable#View_foregroundTint 26622 * @see #getForegroundTintList() 26623 * @see Drawable#setTintList(ColorStateList) 26624 */ 26625 @RemotableViewMethod setForegroundTintList(@ullable ColorStateList tint)26626 public void setForegroundTintList(@Nullable ColorStateList tint) { 26627 if (mForegroundInfo == null) { 26628 mForegroundInfo = new ForegroundInfo(); 26629 } 26630 if (mForegroundInfo.mTintInfo == null) { 26631 mForegroundInfo.mTintInfo = new TintInfo(); 26632 } 26633 mForegroundInfo.mTintInfo.mTintList = tint; 26634 mForegroundInfo.mTintInfo.mHasTintList = true; 26635 26636 applyForegroundTint(); 26637 } 26638 26639 /** 26640 * Return the tint applied to the foreground drawable, if specified. 26641 * 26642 * @return the tint applied to the foreground drawable 26643 * @attr ref android.R.styleable#View_foregroundTint 26644 * @see #setForegroundTintList(ColorStateList) 26645 */ 26646 @InspectableProperty(name = "foregroundTint") 26647 @Nullable getForegroundTintList()26648 public ColorStateList getForegroundTintList() { 26649 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 26650 ? mForegroundInfo.mTintInfo.mTintList : null; 26651 } 26652 26653 /** 26654 * Specifies the blending mode used to apply the tint specified by 26655 * {@link #setForegroundTintList(ColorStateList)}} to the background 26656 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 26657 * 26658 * @param tintMode the blending mode used to apply the tint, may be 26659 * {@code null} to clear tint 26660 * @attr ref android.R.styleable#View_foregroundTintMode 26661 * @see #getForegroundTintMode() 26662 * @see Drawable#setTintMode(PorterDuff.Mode) 26663 * 26664 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)26665 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 26666 BlendMode mode = null; 26667 if (tintMode != null) { 26668 mode = BlendMode.fromValue(tintMode.nativeInt); 26669 } 26670 setForegroundTintBlendMode(mode); 26671 } 26672 26673 /** 26674 * Specifies the blending mode used to apply the tint specified by 26675 * {@link #setForegroundTintList(ColorStateList)}} to the background 26676 * drawable. The default mode is {@link BlendMode#SRC_IN}. 26677 * 26678 * @param blendMode the blending mode used to apply the tint, may be 26679 * {@code null} to clear tint 26680 * @attr ref android.R.styleable#View_foregroundTintMode 26681 * @see #getForegroundTintMode() 26682 * @see Drawable#setTintBlendMode(BlendMode) 26683 */ 26684 @RemotableViewMethod setForegroundTintBlendMode(@ullable BlendMode blendMode)26685 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 26686 if (mForegroundInfo == null) { 26687 mForegroundInfo = new ForegroundInfo(); 26688 } 26689 if (mForegroundInfo.mTintInfo == null) { 26690 mForegroundInfo.mTintInfo = new TintInfo(); 26691 } 26692 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 26693 mForegroundInfo.mTintInfo.mHasTintMode = true; 26694 26695 applyForegroundTint(); 26696 } 26697 26698 /** 26699 * Return the blending mode used to apply the tint to the foreground 26700 * drawable, if specified. 26701 * 26702 * @return the blending mode used to apply the tint to the foreground 26703 * drawable 26704 * @attr ref android.R.styleable#View_foregroundTintMode 26705 * @see #setForegroundTintMode(PorterDuff.Mode) 26706 */ 26707 @InspectableProperty 26708 @Nullable getForegroundTintMode()26709 public PorterDuff.Mode getForegroundTintMode() { 26710 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 26711 ? mForegroundInfo.mTintInfo.mBlendMode : null; 26712 if (blendMode != null) { 26713 return BlendMode.blendModeToPorterDuffMode(blendMode); 26714 } else { 26715 return null; 26716 } 26717 } 26718 26719 /** 26720 * Return the blending mode used to apply the tint to the foreground 26721 * drawable, if specified. 26722 * 26723 * @return the blending mode used to apply the tint to the foreground 26724 * drawable 26725 * @attr ref android.R.styleable#View_foregroundTintMode 26726 * @see #setForegroundTintBlendMode(BlendMode) 26727 * 26728 */ getForegroundTintBlendMode()26729 public @Nullable BlendMode getForegroundTintBlendMode() { 26730 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 26731 ? mForegroundInfo.mTintInfo.mBlendMode : null; 26732 } 26733 applyForegroundTint()26734 private void applyForegroundTint() { 26735 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 26736 && mForegroundInfo.mTintInfo != null) { 26737 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 26738 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 26739 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 26740 26741 if (tintInfo.mHasTintList) { 26742 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 26743 } 26744 26745 if (tintInfo.mHasTintMode) { 26746 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 26747 } 26748 26749 // The drawable (or one of its children) may not have been 26750 // stateful before applying the tint, so let's try again. 26751 if (mForegroundInfo.mDrawable.isStateful()) { 26752 mForegroundInfo.mDrawable.setState(getDrawableState()); 26753 } 26754 } 26755 } 26756 } 26757 26758 /** 26759 * Get the drawable to be overlayed when a view is autofilled 26760 * 26761 * @return The drawable 26762 * 26763 * @throws IllegalStateException if the drawable could not be found. 26764 */ getAutofilledDrawable()26765 @Nullable private Drawable getAutofilledDrawable() { 26766 if (mAttachInfo == null) { 26767 return null; 26768 } 26769 // Lazily load the isAutofilled drawable. 26770 if (mAttachInfo.mAutofilledDrawable == null) { 26771 Context rootContext = getRootView().getContext(); 26772 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 26773 int attributeResourceId = a.getResourceId(0, 0); 26774 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 26775 a.recycle(); 26776 } 26777 26778 return mAttachInfo.mAutofilledDrawable; 26779 } 26780 26781 /** 26782 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 26783 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 26784 * 26785 * @param canvas The canvas to draw on 26786 */ drawAutofilledHighlight(@onNull Canvas canvas)26787 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 26788 if (isAutofilled() && !hideAutofillHighlight()) { 26789 Drawable autofilledHighlight = getAutofilledDrawable(); 26790 26791 if (autofilledHighlight != null) { 26792 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 26793 autofilledHighlight.draw(canvas); 26794 } 26795 } 26796 } 26797 26798 /** 26799 * Draw any foreground content for this view. 26800 * 26801 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 26802 * drawable or other view-specific decorations. The foreground is drawn on top of the 26803 * primary view content.</p> 26804 * 26805 * @param canvas canvas to draw into 26806 */ onDrawForeground(@onNull Canvas canvas)26807 public void onDrawForeground(@NonNull Canvas canvas) { 26808 onDrawScrollIndicators(canvas); 26809 onDrawScrollBars(canvas); 26810 26811 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 26812 if (foreground != null) { 26813 if (mForegroundInfo.mBoundsChanged) { 26814 mForegroundInfo.mBoundsChanged = false; 26815 final Rect selfBounds = mForegroundInfo.mSelfBounds; 26816 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 26817 26818 if (mForegroundInfo.mInsidePadding) { 26819 selfBounds.set(0, 0, getWidth(), getHeight()); 26820 } else { 26821 selfBounds.set(getPaddingLeft(), getPaddingTop(), 26822 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 26823 } 26824 26825 final int ld = getLayoutDirection(); 26826 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 26827 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 26828 foreground.setBounds(overlayBounds); 26829 } 26830 26831 foreground.draw(canvas); 26832 } 26833 } 26834 26835 /** 26836 * Sets the padding. The view may add on the space required to display 26837 * the scrollbars, depending on the style and visibility of the scrollbars. 26838 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 26839 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 26840 * from the values set in this call. 26841 * 26842 * @attr ref android.R.styleable#View_padding 26843 * @attr ref android.R.styleable#View_paddingBottom 26844 * @attr ref android.R.styleable#View_paddingLeft 26845 * @attr ref android.R.styleable#View_paddingRight 26846 * @attr ref android.R.styleable#View_paddingTop 26847 * @param left the left padding in pixels 26848 * @param top the top padding in pixels 26849 * @param right the right padding in pixels 26850 * @param bottom the bottom padding in pixels 26851 */ setPadding(int left, int top, int right, int bottom)26852 public void setPadding(int left, int top, int right, int bottom) { 26853 resetResolvedPaddingInternal(); 26854 26855 mUserPaddingStart = UNDEFINED_PADDING; 26856 mUserPaddingEnd = UNDEFINED_PADDING; 26857 26858 mUserPaddingLeftInitial = left; 26859 mUserPaddingRightInitial = right; 26860 26861 mLeftPaddingDefined = true; 26862 mRightPaddingDefined = true; 26863 26864 internalSetPadding(left, top, right, bottom); 26865 } 26866 26867 /** 26868 * @hide 26869 */ 26870 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)26871 protected void internalSetPadding(int left, int top, int right, int bottom) { 26872 mUserPaddingLeft = left; 26873 mUserPaddingRight = right; 26874 mUserPaddingBottom = bottom; 26875 26876 final int viewFlags = mViewFlags; 26877 boolean changed = false; 26878 26879 // Common case is there are no scroll bars. 26880 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 26881 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 26882 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 26883 ? 0 : getVerticalScrollbarWidth(); 26884 switch (mVerticalScrollbarPosition) { 26885 case SCROLLBAR_POSITION_DEFAULT: 26886 if (isLayoutRtl()) { 26887 left += offset; 26888 } else { 26889 right += offset; 26890 } 26891 break; 26892 case SCROLLBAR_POSITION_RIGHT: 26893 right += offset; 26894 break; 26895 case SCROLLBAR_POSITION_LEFT: 26896 left += offset; 26897 break; 26898 } 26899 } 26900 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 26901 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 26902 ? 0 : getHorizontalScrollbarHeight(); 26903 } 26904 } 26905 26906 if (mPaddingLeft != left) { 26907 changed = true; 26908 mPaddingLeft = left; 26909 } 26910 if (mPaddingTop != top) { 26911 changed = true; 26912 mPaddingTop = top; 26913 } 26914 if (mPaddingRight != right) { 26915 changed = true; 26916 mPaddingRight = right; 26917 } 26918 if (mPaddingBottom != bottom) { 26919 changed = true; 26920 mPaddingBottom = bottom; 26921 } 26922 26923 if (changed) { 26924 requestLayout(); 26925 invalidateOutline(); 26926 } 26927 } 26928 26929 /** 26930 * Sets the relative padding. The view may add on the space required to display 26931 * the scrollbars, depending on the style and visibility of the scrollbars. 26932 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 26933 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 26934 * from the values set in this call. 26935 * 26936 * @attr ref android.R.styleable#View_padding 26937 * @attr ref android.R.styleable#View_paddingBottom 26938 * @attr ref android.R.styleable#View_paddingStart 26939 * @attr ref android.R.styleable#View_paddingEnd 26940 * @attr ref android.R.styleable#View_paddingTop 26941 * @param start the start padding in pixels 26942 * @param top the top padding in pixels 26943 * @param end the end padding in pixels 26944 * @param bottom the bottom padding in pixels 26945 */ setPaddingRelative(int start, int top, int end, int bottom)26946 public void setPaddingRelative(int start, int top, int end, int bottom) { 26947 resetResolvedPaddingInternal(); 26948 26949 mUserPaddingStart = start; 26950 mUserPaddingEnd = end; 26951 mLeftPaddingDefined = true; 26952 mRightPaddingDefined = true; 26953 26954 switch(getLayoutDirection()) { 26955 case LAYOUT_DIRECTION_RTL: 26956 mUserPaddingLeftInitial = end; 26957 mUserPaddingRightInitial = start; 26958 internalSetPadding(end, top, start, bottom); 26959 break; 26960 case LAYOUT_DIRECTION_LTR: 26961 default: 26962 mUserPaddingLeftInitial = start; 26963 mUserPaddingRightInitial = end; 26964 internalSetPadding(start, top, end, bottom); 26965 } 26966 } 26967 26968 /** 26969 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 26970 * resource ID of the source layout. 26971 * 26972 * @return The layout resource id if this view was inflated from XML, otherwise 26973 * {@link Resources#ID_NULL}. 26974 */ 26975 @LayoutRes getSourceLayoutResId()26976 public int getSourceLayoutResId() { 26977 return mSourceLayoutId; 26978 } 26979 26980 /** 26981 * Returns the top padding of this view. 26982 * 26983 * @return the top padding in pixels 26984 */ 26985 @InspectableProperty getPaddingTop()26986 public int getPaddingTop() { 26987 return mPaddingTop; 26988 } 26989 26990 /** 26991 * Returns the bottom padding of this view. If there are inset and enabled 26992 * scrollbars, this value may include the space required to display the 26993 * scrollbars as well. 26994 * 26995 * @return the bottom padding in pixels 26996 */ 26997 @InspectableProperty getPaddingBottom()26998 public int getPaddingBottom() { 26999 return mPaddingBottom; 27000 } 27001 27002 /** 27003 * Returns the left padding of this view. If there are inset and enabled 27004 * scrollbars, this value may include the space required to display the 27005 * scrollbars as well. 27006 * 27007 * @return the left padding in pixels 27008 */ 27009 @InspectableProperty getPaddingLeft()27010 public int getPaddingLeft() { 27011 if (!isPaddingResolved()) { 27012 resolvePadding(); 27013 } 27014 return mPaddingLeft; 27015 } 27016 27017 /** 27018 * Returns the start padding of this view depending on its resolved layout direction. 27019 * If there are inset and enabled scrollbars, this value may include the space 27020 * required to display the scrollbars as well. 27021 * 27022 * @return the start padding in pixels 27023 */ getPaddingStart()27024 public int getPaddingStart() { 27025 if (!isPaddingResolved()) { 27026 resolvePadding(); 27027 } 27028 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 27029 mPaddingRight : mPaddingLeft; 27030 } 27031 27032 /** 27033 * Returns the right padding of this view. If there are inset and enabled 27034 * scrollbars, this value may include the space required to display the 27035 * scrollbars as well. 27036 * 27037 * @return the right padding in pixels 27038 */ 27039 @InspectableProperty getPaddingRight()27040 public int getPaddingRight() { 27041 if (!isPaddingResolved()) { 27042 resolvePadding(); 27043 } 27044 return mPaddingRight; 27045 } 27046 27047 /** 27048 * Returns the end padding of this view depending on its resolved layout direction. 27049 * If there are inset and enabled scrollbars, this value may include the space 27050 * required to display the scrollbars as well. 27051 * 27052 * @return the end padding in pixels 27053 */ getPaddingEnd()27054 public int getPaddingEnd() { 27055 if (!isPaddingResolved()) { 27056 resolvePadding(); 27057 } 27058 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 27059 mPaddingLeft : mPaddingRight; 27060 } 27061 27062 /** 27063 * Return if the padding has been set through relative values 27064 * {@link #setPaddingRelative(int, int, int, int)} or through 27065 * @attr ref android.R.styleable#View_paddingStart or 27066 * @attr ref android.R.styleable#View_paddingEnd 27067 * 27068 * @return true if the padding is relative or false if it is not. 27069 */ isPaddingRelative()27070 public boolean isPaddingRelative() { 27071 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 27072 } 27073 computeOpticalInsets()27074 Insets computeOpticalInsets() { 27075 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 27076 } 27077 27078 /** 27079 * @hide 27080 */ 27081 @UnsupportedAppUsage resetPaddingToInitialValues()27082 public void resetPaddingToInitialValues() { 27083 if (isRtlCompatibilityMode()) { 27084 mPaddingLeft = mUserPaddingLeftInitial; 27085 mPaddingRight = mUserPaddingRightInitial; 27086 return; 27087 } 27088 if (isLayoutRtl()) { 27089 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 27090 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 27091 } else { 27092 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 27093 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 27094 } 27095 } 27096 27097 /** 27098 * @hide 27099 */ getOpticalInsets()27100 public Insets getOpticalInsets() { 27101 if (mLayoutInsets == null) { 27102 mLayoutInsets = computeOpticalInsets(); 27103 } 27104 return mLayoutInsets; 27105 } 27106 27107 /** 27108 * Set this view's optical insets. 27109 * 27110 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 27111 * property. Views that compute their own optical insets should call it as part of measurement. 27112 * This method does not request layout. If you are setting optical insets outside of 27113 * measure/layout itself you will want to call requestLayout() yourself. 27114 * </p> 27115 * @hide 27116 */ setOpticalInsets(Insets insets)27117 public void setOpticalInsets(Insets insets) { 27118 mLayoutInsets = insets; 27119 } 27120 27121 /** 27122 * Changes the selection state of this view. A view can be selected or not. 27123 * Note that selection is not the same as focus. Views are typically 27124 * selected in the context of an AdapterView like ListView or GridView; 27125 * the selected view is the view that is highlighted. 27126 * 27127 * @param selected true if the view must be selected, false otherwise 27128 */ setSelected(boolean selected)27129 public void setSelected(boolean selected) { 27130 //noinspection DoubleNegation 27131 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 27132 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 27133 if (!selected) resetPressedState(); 27134 invalidate(true); 27135 refreshDrawableState(); 27136 dispatchSetSelected(selected); 27137 if (selected) { 27138 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 27139 } else { 27140 notifyViewAccessibilityStateChangedIfNeeded( 27141 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 27142 } 27143 } 27144 } 27145 27146 /** 27147 * Dispatch setSelected to all of this View's children. 27148 * 27149 * @see #setSelected(boolean) 27150 * 27151 * @param selected The new selected state 27152 */ dispatchSetSelected(boolean selected)27153 protected void dispatchSetSelected(boolean selected) { 27154 } 27155 27156 /** 27157 * Indicates the selection state of this view. 27158 * 27159 * @return true if the view is selected, false otherwise 27160 */ 27161 @ViewDebug.ExportedProperty 27162 @InspectableProperty(hasAttributeId = false) isSelected()27163 public boolean isSelected() { 27164 return (mPrivateFlags & PFLAG_SELECTED) != 0; 27165 } 27166 27167 /** 27168 * Changes the activated state of this view. A view can be activated or not. 27169 * Note that activation is not the same as selection. Selection is 27170 * a transient property, representing the view (hierarchy) the user is 27171 * currently interacting with. Activation is a longer-term state that the 27172 * user can move views in and out of. For example, in a list view with 27173 * single or multiple selection enabled, the views in the current selection 27174 * set are activated. (Um, yeah, we are deeply sorry about the terminology 27175 * here.) The activated state is propagated down to children of the view it 27176 * is set on. 27177 * 27178 * @param activated true if the view must be activated, false otherwise 27179 */ setActivated(boolean activated)27180 public void setActivated(boolean activated) { 27181 //noinspection DoubleNegation 27182 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 27183 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 27184 invalidate(true); 27185 refreshDrawableState(); 27186 dispatchSetActivated(activated); 27187 } 27188 } 27189 27190 /** 27191 * Dispatch setActivated to all of this View's children. 27192 * 27193 * @see #setActivated(boolean) 27194 * 27195 * @param activated The new activated state 27196 */ dispatchSetActivated(boolean activated)27197 protected void dispatchSetActivated(boolean activated) { 27198 } 27199 27200 /** 27201 * Indicates the activation state of this view. 27202 * 27203 * @return true if the view is activated, false otherwise 27204 */ 27205 @ViewDebug.ExportedProperty 27206 @InspectableProperty(hasAttributeId = false) isActivated()27207 public boolean isActivated() { 27208 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 27209 } 27210 27211 /** 27212 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 27213 * observer can be used to get notifications when global events, like 27214 * layout, happen. 27215 * 27216 * The returned ViewTreeObserver observer is not guaranteed to remain 27217 * valid for the lifetime of this View. If the caller of this method keeps 27218 * a long-lived reference to ViewTreeObserver, it should always check for 27219 * the return value of {@link ViewTreeObserver#isAlive()}. 27220 * 27221 * @return The ViewTreeObserver for this view's hierarchy. 27222 */ getViewTreeObserver()27223 public ViewTreeObserver getViewTreeObserver() { 27224 if (mAttachInfo != null) { 27225 return mAttachInfo.mTreeObserver; 27226 } 27227 if (mFloatingTreeObserver == null) { 27228 mFloatingTreeObserver = new ViewTreeObserver(mContext); 27229 } 27230 return mFloatingTreeObserver; 27231 } 27232 27233 /** 27234 * <p>Finds the topmost view in the current view hierarchy.</p> 27235 * 27236 * @return the topmost view containing this view 27237 */ getRootView()27238 public View getRootView() { 27239 if (mAttachInfo != null) { 27240 final View v = mAttachInfo.mRootView; 27241 if (v != null) { 27242 return v; 27243 } 27244 } 27245 27246 View parent = this; 27247 27248 while (parent.mParent instanceof View) { 27249 parent = (View) parent.mParent; 27250 } 27251 27252 return parent; 27253 } 27254 27255 /** 27256 * Transforms a motion event from view-local coordinates to on-screen 27257 * coordinates. 27258 * 27259 * @param ev the view-local motion event 27260 * @return false if the transformation could not be applied 27261 * @hide 27262 */ 27263 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toGlobalMotionEvent(MotionEvent ev)27264 public boolean toGlobalMotionEvent(MotionEvent ev) { 27265 final AttachInfo info = mAttachInfo; 27266 if (info == null) { 27267 return false; 27268 } 27269 27270 final Matrix m = info.mTmpMatrix; 27271 m.set(Matrix.IDENTITY_MATRIX); 27272 transformMatrixToGlobal(m); 27273 ev.transform(m); 27274 return true; 27275 } 27276 27277 /** 27278 * Transforms a motion event from on-screen coordinates to view-local 27279 * coordinates. 27280 * 27281 * @param ev the on-screen motion event 27282 * @return false if the transformation could not be applied 27283 * @hide 27284 */ 27285 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toLocalMotionEvent(MotionEvent ev)27286 public boolean toLocalMotionEvent(MotionEvent ev) { 27287 final AttachInfo info = mAttachInfo; 27288 if (info == null) { 27289 return false; 27290 } 27291 27292 final Matrix m = info.mTmpMatrix; 27293 m.set(Matrix.IDENTITY_MATRIX); 27294 transformMatrixToLocal(m); 27295 ev.transform(m); 27296 return true; 27297 } 27298 27299 /** 27300 * Modifies the input matrix such that it maps view-local coordinates to 27301 * on-screen coordinates. 27302 * 27303 * @param matrix input matrix to modify 27304 */ transformMatrixToGlobal(@onNull Matrix matrix)27305 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 27306 final ViewParent parent = mParent; 27307 if (parent instanceof View) { 27308 final View vp = (View) parent; 27309 vp.transformMatrixToGlobal(matrix); 27310 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 27311 } else if (parent instanceof ViewRootImpl) { 27312 final ViewRootImpl vr = (ViewRootImpl) parent; 27313 vr.transformMatrixToGlobal(matrix); 27314 matrix.preTranslate(0, -vr.mCurScrollY); 27315 } 27316 27317 matrix.preTranslate(mLeft, mTop); 27318 27319 if (!hasIdentityMatrix()) { 27320 matrix.preConcat(getMatrix()); 27321 } 27322 } 27323 27324 /** 27325 * Modifies the input matrix such that it maps on-screen coordinates to 27326 * view-local coordinates. 27327 * 27328 * @param matrix input matrix to modify 27329 */ transformMatrixToLocal(@onNull Matrix matrix)27330 public void transformMatrixToLocal(@NonNull Matrix matrix) { 27331 final ViewParent parent = mParent; 27332 if (parent instanceof View) { 27333 final View vp = (View) parent; 27334 vp.transformMatrixToLocal(matrix); 27335 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 27336 } else if (parent instanceof ViewRootImpl) { 27337 final ViewRootImpl vr = (ViewRootImpl) parent; 27338 vr.transformMatrixToLocal(matrix); 27339 matrix.postTranslate(0, vr.mCurScrollY); 27340 } 27341 27342 matrix.postTranslate(-mLeft, -mTop); 27343 27344 if (!hasIdentityMatrix()) { 27345 matrix.postConcat(getInverseMatrix()); 27346 } 27347 } 27348 27349 /** 27350 * @hide 27351 */ 27352 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 27353 @ViewDebug.IntToString(from = 0, to = "x"), 27354 @ViewDebug.IntToString(from = 1, to = "y") 27355 }) 27356 @UnsupportedAppUsage getLocationOnScreen()27357 public int[] getLocationOnScreen() { 27358 int[] location = new int[2]; 27359 getLocationOnScreen(location); 27360 return location; 27361 } 27362 27363 /** 27364 * Gets the coordinates of this view in the coordinate space of the device 27365 * screen, irrespective of system decorations and whether the system is in 27366 * multi-window mode. 27367 * 27368 * <p>In multi-window mode, the coordinate space encompasses the entire 27369 * device screen, ignoring the bounds of the app window. For example, if the 27370 * view is in the bottom portion of a horizontal split screen, the top edge 27371 * of the screen—not the top edge of the window—is the origin 27372 * from which the y-coordinate is calculated. 27373 * 27374 * <p>In multiple-screen scenarios, the coordinate space can span screens. 27375 * For example, if the app is spanning both screens of a dual-screen device 27376 * and the view is located on the right-hand screen, the x-coordinate is 27377 * calculated from the left edge of the left-hand screen to the left edge of 27378 * the view. When the app is restricted to a single screen in a 27379 * multiple-screen environment, the coordinate space includes only the 27380 * screen on which the app is running. 27381 * 27382 * <p>After the method returns, the argument array contains the x and y 27383 * coordinates of the view relative to the view's left and top edges, 27384 * respectively. 27385 * 27386 * @param outLocation A two-element integer array in which the view 27387 * coordinates are stored. The x-coordinate is at index 0; the 27388 * y-coordinate, at index 1. 27389 */ getLocationOnScreen(@ize2) int[] outLocation)27390 public void getLocationOnScreen(@Size(2) int[] outLocation) { 27391 getLocationInWindow(outLocation); 27392 27393 final AttachInfo info = mAttachInfo; 27394 if (info != null) { 27395 outLocation[0] += info.mWindowLeft; 27396 outLocation[1] += info.mWindowTop; 27397 // If OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS override is enabled, 27398 // applyViewLocationSandboxingIfNeeded sandboxes outLocation within window bounds. 27399 info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation); 27400 } 27401 } 27402 27403 /** 27404 * Gets the coordinates of this view in the coordinate space of the window 27405 * that contains the view, irrespective of system decorations. 27406 * 27407 * <p>In multi-window mode, the origin of the coordinate space is the 27408 * top left corner of the window that contains the view. In full screen 27409 * mode, the origin is the top left corner of the device screen. 27410 * 27411 * <p>In multiple-screen scenarios, if the app spans multiple screens, the 27412 * coordinate space also spans multiple screens. But if the app is 27413 * restricted to a single screen, the coordinate space includes only the 27414 * screen on which the app is running. 27415 * 27416 * <p>After the method returns, the argument array contains the x and y 27417 * coordinates of the view relative to the view's left and top edges, 27418 * respectively. 27419 * 27420 * @param outLocation A two-element integer array in which the view 27421 * coordinates are stored. The x-coordinate is at index 0; the 27422 * y-coordinate, at index 1. 27423 */ getLocationInWindow(@ize2) int[] outLocation)27424 public void getLocationInWindow(@Size(2) int[] outLocation) { 27425 if (outLocation == null || outLocation.length < 2) { 27426 throw new IllegalArgumentException("outLocation must be an array of two integers"); 27427 } 27428 27429 outLocation[0] = 0; 27430 outLocation[1] = 0; 27431 27432 transformFromViewToWindowSpace(outLocation); 27433 } 27434 27435 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)27436 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 27437 if (inOutLocation == null || inOutLocation.length < 2) { 27438 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 27439 } 27440 27441 if (mAttachInfo == null) { 27442 // When the view is not attached to a window, this method does not make sense 27443 inOutLocation[0] = inOutLocation[1] = 0; 27444 return; 27445 } 27446 27447 float position[] = mAttachInfo.mTmpTransformLocation; 27448 position[0] = inOutLocation[0]; 27449 position[1] = inOutLocation[1]; 27450 27451 if (!hasIdentityMatrix()) { 27452 getMatrix().mapPoints(position); 27453 } 27454 27455 position[0] += mLeft; 27456 position[1] += mTop; 27457 27458 ViewParent viewParent = mParent; 27459 while (viewParent instanceof View) { 27460 final View view = (View) viewParent; 27461 27462 position[0] -= view.mScrollX; 27463 position[1] -= view.mScrollY; 27464 27465 if (!view.hasIdentityMatrix()) { 27466 view.getMatrix().mapPoints(position); 27467 } 27468 27469 position[0] += view.mLeft; 27470 position[1] += view.mTop; 27471 27472 viewParent = view.mParent; 27473 } 27474 27475 if (viewParent instanceof ViewRootImpl) { 27476 // *cough* 27477 final ViewRootImpl vr = (ViewRootImpl) viewParent; 27478 position[1] -= vr.mCurScrollY; 27479 } 27480 27481 inOutLocation[0] = Math.round(position[0]); 27482 inOutLocation[1] = Math.round(position[1]); 27483 } 27484 27485 /** 27486 * @param id the id of the view to be found 27487 * @return the view of the specified id, null if cannot be found 27488 * @hide 27489 */ findViewTraversal(@dRes int id)27490 protected <T extends View> T findViewTraversal(@IdRes int id) { 27491 if (id == mID) { 27492 return (T) this; 27493 } 27494 return null; 27495 } 27496 27497 /** 27498 * @param tag the tag of the view to be found 27499 * @return the view of specified tag, null if cannot be found 27500 * @hide 27501 */ findViewWithTagTraversal(Object tag)27502 protected <T extends View> T findViewWithTagTraversal(Object tag) { 27503 if (tag != null && tag.equals(mTag)) { 27504 return (T) this; 27505 } 27506 return null; 27507 } 27508 27509 /** 27510 * @param predicate The predicate to evaluate. 27511 * @param childToSkip If not null, ignores this child during the recursive traversal. 27512 * @return The first view that matches the predicate or null. 27513 * @hide 27514 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)27515 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 27516 View childToSkip) { 27517 if (predicate.test(this)) { 27518 return (T) this; 27519 } 27520 return null; 27521 } 27522 27523 /** 27524 * Finds the first descendant view with the given ID, the view itself if 27525 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 27526 * (< 0) or there is no matching view in the hierarchy. 27527 * <p> 27528 * <strong>Note:</strong> In most cases -- depending on compiler support -- 27529 * the resulting view is automatically cast to the target class type. If 27530 * the target class type is unconstrained, an explicit cast may be 27531 * necessary. 27532 * 27533 * @param id the ID to search for 27534 * @return a view with given ID if found, or {@code null} otherwise 27535 * @see View#requireViewById(int) 27536 */ 27537 @Nullable findViewById(@dRes int id)27538 public final <T extends View> T findViewById(@IdRes int id) { 27539 if (id == NO_ID) { 27540 return null; 27541 } 27542 return findViewTraversal(id); 27543 } 27544 27545 /** 27546 * Finds the first descendant view with the given ID, the view itself if the ID matches 27547 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 27548 * matching view in the hierarchy. 27549 * <p> 27550 * <strong>Note:</strong> In most cases -- depending on compiler support -- 27551 * the resulting view is automatically cast to the target class type. If 27552 * the target class type is unconstrained, an explicit cast may be 27553 * necessary. 27554 * 27555 * @param id the ID to search for 27556 * @return a view with given ID 27557 * @see View#findViewById(int) 27558 */ 27559 @NonNull requireViewById(@dRes int id)27560 public final <T extends View> T requireViewById(@IdRes int id) { 27561 T view = findViewById(id); 27562 if (view == null) { 27563 throw new IllegalArgumentException("ID does not reference a View inside this View"); 27564 } 27565 return view; 27566 } 27567 27568 /** 27569 * Performs the traversal to find a view by its unique and stable accessibility id. 27570 * 27571 * <strong>Note:</strong>This method does not stop at the root namespace 27572 * boundary since the user can touch the screen at an arbitrary location 27573 * potentially crossing the root namespace boundary which will send an 27574 * accessibility event to accessibility services and they should be able 27575 * to obtain the event source. Also accessibility ids are guaranteed to be 27576 * unique in the window. 27577 * 27578 * @param accessibilityId The accessibility id. 27579 * @return The found view. 27580 * @hide 27581 */ findViewByAccessibilityIdTraversal(int accessibilityId)27582 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 27583 if (getAccessibilityViewId() == accessibilityId) { 27584 return (T) this; 27585 } 27586 return null; 27587 } 27588 27589 /** 27590 * Performs the traversal to find a view by its autofill id. 27591 * 27592 * <strong>Note:</strong>This method does not stop at the root namespace 27593 * boundary. 27594 * 27595 * @param autofillId The autofill id. 27596 * @return The found view. 27597 * @hide 27598 */ findViewByAutofillIdTraversal(int autofillId)27599 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 27600 if (getAutofillViewId() == autofillId) { 27601 return (T) this; 27602 } 27603 return null; 27604 } 27605 27606 /** 27607 * Look for a child view with the given tag. If this view has the given 27608 * tag, return this view. 27609 * 27610 * @param tag The tag to search for, using "tag.equals(getTag())". 27611 * @return The View that has the given tag in the hierarchy or null 27612 */ findViewWithTag(Object tag)27613 public final <T extends View> T findViewWithTag(Object tag) { 27614 if (tag == null) { 27615 return null; 27616 } 27617 return findViewWithTagTraversal(tag); 27618 } 27619 27620 /** 27621 * Look for a child view that matches the specified predicate. 27622 * If this view matches the predicate, return this view. 27623 * 27624 * @param predicate The predicate to evaluate. 27625 * @return The first view that matches the predicate or null. 27626 * @hide 27627 */ findViewByPredicate(Predicate<View> predicate)27628 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 27629 return findViewByPredicateTraversal(predicate, null); 27630 } 27631 27632 /** 27633 * Look for a child view that matches the specified predicate, 27634 * starting with the specified view and its descendents and then 27635 * recusively searching the ancestors and siblings of that view 27636 * until this view is reached. 27637 * 27638 * This method is useful in cases where the predicate does not match 27639 * a single unique view (perhaps multiple views use the same id) 27640 * and we are trying to find the view that is "closest" in scope to the 27641 * starting view. 27642 * 27643 * @param start The view to start from. 27644 * @param predicate The predicate to evaluate. 27645 * @return The first view that matches the predicate or null. 27646 * @hide 27647 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)27648 public final <T extends View> T findViewByPredicateInsideOut( 27649 View start, Predicate<View> predicate) { 27650 View childToSkip = null; 27651 for (;;) { 27652 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 27653 if (view != null || start == this) { 27654 return view; 27655 } 27656 27657 ViewParent parent = start.getParent(); 27658 if (parent == null || !(parent instanceof View)) { 27659 return null; 27660 } 27661 27662 childToSkip = start; 27663 start = (View) parent; 27664 } 27665 } 27666 27667 /** 27668 * Sets the identifier for this view. The identifier does not have to be 27669 * unique in this view's hierarchy. The identifier should be a positive 27670 * number. 27671 * 27672 * @see #NO_ID 27673 * @see #getId() 27674 * @see #findViewById(int) 27675 * 27676 * @param id a number used to identify the view 27677 * 27678 * @attr ref android.R.styleable#View_id 27679 */ setId(@dRes int id)27680 public void setId(@IdRes int id) { 27681 mID = id; 27682 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 27683 mID = generateViewId(); 27684 } 27685 } 27686 27687 /** 27688 * {@hide} 27689 * 27690 * @param isRoot true if the view belongs to the root namespace, false 27691 * otherwise 27692 */ 27693 @UnsupportedAppUsage 27694 @TestApi setIsRootNamespace(boolean isRoot)27695 public void setIsRootNamespace(boolean isRoot) { 27696 if (isRoot) { 27697 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 27698 } else { 27699 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 27700 } 27701 } 27702 27703 /** 27704 * {@hide} 27705 * 27706 * @return true if the view belongs to the root namespace, false otherwise 27707 */ 27708 @UnsupportedAppUsage isRootNamespace()27709 public boolean isRootNamespace() { 27710 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 27711 } 27712 27713 /** 27714 * Returns this view's identifier. 27715 * 27716 * @return a positive integer used to identify the view or {@link #NO_ID} 27717 * if the view has no ID 27718 * 27719 * @see #setId(int) 27720 * @see #findViewById(int) 27721 * @attr ref android.R.styleable#View_id 27722 */ 27723 @IdRes 27724 @ViewDebug.CapturedViewProperty 27725 @InspectableProperty getId()27726 public int getId() { 27727 return mID; 27728 } 27729 27730 /** 27731 * Get the identifier used for this view by the drawing system. 27732 * 27733 * @see RenderNode#getUniqueId() 27734 * @return A long that uniquely identifies this view's drawing component 27735 */ getUniqueDrawingId()27736 public long getUniqueDrawingId() { 27737 return mRenderNode.getUniqueId(); 27738 } 27739 27740 /** 27741 * Returns this view's tag. 27742 * 27743 * @return the Object stored in this view as a tag, or {@code null} if not 27744 * set 27745 * 27746 * @see #setTag(Object) 27747 * @see #getTag(int) 27748 */ 27749 @ViewDebug.ExportedProperty 27750 @InspectableProperty getTag()27751 public Object getTag() { 27752 return mTag; 27753 } 27754 27755 /** 27756 * Sets the tag associated with this view. A tag can be used to mark 27757 * a view in its hierarchy and does not have to be unique within the 27758 * hierarchy. Tags can also be used to store data within a view without 27759 * resorting to another data structure. 27760 * 27761 * @param tag an Object to tag the view with 27762 * 27763 * @see #getTag() 27764 * @see #setTag(int, Object) 27765 */ setTag(final Object tag)27766 public void setTag(final Object tag) { 27767 mTag = tag; 27768 } 27769 27770 /** 27771 * Returns the tag associated with this view and the specified key. 27772 * 27773 * @param key The key identifying the tag 27774 * 27775 * @return the Object stored in this view as a tag, or {@code null} if not 27776 * set 27777 * 27778 * @see #setTag(int, Object) 27779 * @see #getTag() 27780 */ getTag(int key)27781 public Object getTag(int key) { 27782 if (mKeyedTags != null) return mKeyedTags.get(key); 27783 return null; 27784 } 27785 27786 /** 27787 * Sets a tag associated with this view and a key. A tag can be used 27788 * to mark a view in its hierarchy and does not have to be unique within 27789 * the hierarchy. Tags can also be used to store data within a view 27790 * without resorting to another data structure. 27791 * 27792 * The specified key should be an id declared in the resources of the 27793 * application to ensure it is unique (see the <a 27794 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 27795 * Keys identified as belonging to 27796 * the Android framework or not associated with any package will cause 27797 * an {@link IllegalArgumentException} to be thrown. 27798 * 27799 * @param key The key identifying the tag 27800 * @param tag An Object to tag the view with 27801 * 27802 * @throws IllegalArgumentException If they specified key is not valid 27803 * 27804 * @see #setTag(Object) 27805 * @see #getTag(int) 27806 */ setTag(int key, final Object tag)27807 public void setTag(int key, final Object tag) { 27808 // If the package id is 0x00 or 0x01, it's either an undefined package 27809 // or a framework id 27810 if ((key >>> 24) < 2) { 27811 throw new IllegalArgumentException("The key must be an application-specific " 27812 + "resource id."); 27813 } 27814 27815 setKeyedTag(key, tag); 27816 } 27817 27818 /** 27819 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 27820 * framework id. 27821 * 27822 * @hide 27823 */ 27824 @UnsupportedAppUsage setTagInternal(int key, Object tag)27825 public void setTagInternal(int key, Object tag) { 27826 if ((key >>> 24) != 0x1) { 27827 throw new IllegalArgumentException("The key must be a framework-specific " 27828 + "resource id."); 27829 } 27830 27831 setKeyedTag(key, tag); 27832 } 27833 setKeyedTag(int key, Object tag)27834 private void setKeyedTag(int key, Object tag) { 27835 if (mKeyedTags == null) { 27836 mKeyedTags = new SparseArray<Object>(2); 27837 } 27838 27839 mKeyedTags.put(key, tag); 27840 } 27841 27842 /** 27843 * Prints information about this view in the log output, with the tag 27844 * {@link #VIEW_LOG_TAG}. 27845 * 27846 * @hide 27847 */ 27848 @UnsupportedAppUsage debug()27849 public void debug() { 27850 debug(0); 27851 } 27852 27853 /** 27854 * Prints information about this view in the log output, with the tag 27855 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 27856 * indentation defined by the <code>depth</code>. 27857 * 27858 * @param depth the indentation level 27859 * 27860 * @hide 27861 */ 27862 @UnsupportedAppUsage debug(int depth)27863 protected void debug(int depth) { 27864 String output = debugIndent(depth - 1); 27865 27866 output += "+ " + this; 27867 int id = getId(); 27868 if (id != -1) { 27869 output += " (id=" + id + ")"; 27870 } 27871 Object tag = getTag(); 27872 if (tag != null) { 27873 output += " (tag=" + tag + ")"; 27874 } 27875 Log.d(VIEW_LOG_TAG, output); 27876 27877 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 27878 output = debugIndent(depth) + " FOCUSED"; 27879 Log.d(VIEW_LOG_TAG, output); 27880 } 27881 27882 output = debugIndent(depth); 27883 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 27884 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 27885 + "} "; 27886 Log.d(VIEW_LOG_TAG, output); 27887 27888 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 27889 || mPaddingBottom != 0) { 27890 output = debugIndent(depth); 27891 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 27892 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 27893 Log.d(VIEW_LOG_TAG, output); 27894 } 27895 27896 output = debugIndent(depth); 27897 output += "mMeasureWidth=" + mMeasuredWidth + 27898 " mMeasureHeight=" + mMeasuredHeight; 27899 Log.d(VIEW_LOG_TAG, output); 27900 27901 output = debugIndent(depth); 27902 if (mLayoutParams == null) { 27903 output += "BAD! no layout params"; 27904 } else { 27905 output = mLayoutParams.debug(output); 27906 } 27907 Log.d(VIEW_LOG_TAG, output); 27908 27909 output = debugIndent(depth); 27910 output += "flags={"; 27911 output += View.printFlags(mViewFlags); 27912 output += "}"; 27913 Log.d(VIEW_LOG_TAG, output); 27914 27915 output = debugIndent(depth); 27916 output += "privateFlags={"; 27917 output += View.printPrivateFlags(mPrivateFlags); 27918 output += "}"; 27919 Log.d(VIEW_LOG_TAG, output); 27920 } 27921 27922 /** 27923 * Creates a string of whitespaces used for indentation. 27924 * 27925 * @param depth the indentation level 27926 * @return a String containing (depth * 2 + 3) * 2 white spaces 27927 * 27928 * @hide 27929 */ debugIndent(int depth)27930 protected static String debugIndent(int depth) { 27931 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 27932 for (int i = 0; i < (depth * 2) + 3; i++) { 27933 spaces.append(' ').append(' '); 27934 } 27935 return spaces.toString(); 27936 } 27937 27938 /** 27939 * <p>Return the offset of the widget's text baseline from the widget's top 27940 * boundary. If this widget does not support baseline alignment, this 27941 * method returns -1. </p> 27942 * 27943 * @return the offset of the baseline within the widget's bounds or -1 27944 * if baseline alignment is not supported 27945 */ 27946 @ViewDebug.ExportedProperty(category = "layout") 27947 @InspectableProperty getBaseline()27948 public int getBaseline() { 27949 return -1; 27950 } 27951 27952 /** 27953 * Returns whether the view hierarchy is currently undergoing a layout pass. This 27954 * information is useful to avoid situations such as calling {@link #requestLayout()} during 27955 * a layout pass. 27956 * 27957 * @return whether the view hierarchy is currently undergoing a layout pass 27958 */ isInLayout()27959 public boolean isInLayout() { 27960 ViewRootImpl viewRoot = getViewRootImpl(); 27961 return (viewRoot != null && viewRoot.isInLayout()); 27962 } 27963 27964 /** To be used only for debugging purposes. */ printStackStrace(String name)27965 private void printStackStrace(String name) { 27966 Log.d(VIEW_LOG_TAG, "---- ST:" + name); 27967 27968 StringBuilder sb = new StringBuilder(); 27969 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 27970 int startIndex = 1; 27971 int endIndex = Math.min(stackTraceElements.length, startIndex + 20); // max 20 entries. 27972 for (int i = startIndex; i < endIndex; i++) { 27973 StackTraceElement s = stackTraceElements[i]; 27974 sb.append(s.getMethodName()) 27975 .append("(") 27976 .append(s.getFileName()) 27977 .append(":") 27978 .append(s.getLineNumber()) 27979 .append(") <- "); 27980 } 27981 Log.d(VIEW_LOG_TAG, name + ": " + sb); 27982 } 27983 /** 27984 * Call this when something has changed which has invalidated the 27985 * layout of this view. This will schedule a layout pass of the view 27986 * tree. This should not be called while the view hierarchy is currently in a layout 27987 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 27988 * end of the current layout pass (and then layout will run again) or after the current 27989 * frame is drawn and the next layout occurs. 27990 * 27991 * <p>Subclasses which override this method should call the superclass method to 27992 * handle possible request-during-layout errors correctly.</p> 27993 */ 27994 @CallSuper requestLayout()27995 public void requestLayout() { 27996 if (isRelayoutTracingEnabled()) { 27997 Trace.instantForTrack(TRACE_TAG_APP, "requestLayoutTracing", 27998 mTracingStrings.classSimpleName); 27999 printStackStrace(mTracingStrings.requestLayoutStacktracePrefix); 28000 } 28001 28002 if (mMeasureCache != null) mMeasureCache.clear(); 28003 28004 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 28005 // Only trigger request-during-layout logic if this is the view requesting it, 28006 // not the views in its parent hierarchy 28007 ViewRootImpl viewRoot = getViewRootImpl(); 28008 if (viewRoot != null && viewRoot.isInLayout()) { 28009 if (!viewRoot.requestLayoutDuringLayout(this)) { 28010 return; 28011 } 28012 } 28013 mAttachInfo.mViewRequestingLayout = this; 28014 } 28015 28016 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 28017 mPrivateFlags |= PFLAG_INVALIDATED; 28018 28019 if (mParent != null && !mParent.isLayoutRequested()) { 28020 mParent.requestLayout(); 28021 } 28022 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 28023 mAttachInfo.mViewRequestingLayout = null; 28024 } 28025 } 28026 28027 /** 28028 * Forces this view to be laid out during the next layout pass. 28029 * This method does not call requestLayout() or forceLayout() 28030 * on the parent. 28031 */ forceLayout()28032 public void forceLayout() { 28033 if (mMeasureCache != null) mMeasureCache.clear(); 28034 28035 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 28036 mPrivateFlags |= PFLAG_INVALIDATED; 28037 } 28038 28039 /** 28040 * <p> 28041 * This is called to find out how big a view should be. The parent 28042 * supplies constraint information in the width and height parameters. 28043 * </p> 28044 * 28045 * <p> 28046 * The actual measurement work of a view is performed in 28047 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 28048 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 28049 * </p> 28050 * 28051 * 28052 * @param widthMeasureSpec Horizontal space requirements as imposed by the 28053 * parent 28054 * @param heightMeasureSpec Vertical space requirements as imposed by the 28055 * parent 28056 * 28057 * @see #onMeasure(int, int) 28058 */ measure(int widthMeasureSpec, int heightMeasureSpec)28059 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 28060 boolean optical = isLayoutModeOptical(this); 28061 if (optical != isLayoutModeOptical(mParent)) { 28062 Insets insets = getOpticalInsets(); 28063 int oWidth = insets.left + insets.right; 28064 int oHeight = insets.top + insets.bottom; 28065 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 28066 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 28067 } 28068 28069 // Suppress sign extension for the low bytes 28070 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 28071 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 28072 28073 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 28074 28075 // Optimize layout by avoiding an extra EXACTLY pass when the view is 28076 // already measured as the correct size. In API 23 and below, this 28077 // extra pass is required to make LinearLayout re-distribute weight. 28078 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 28079 || heightMeasureSpec != mOldHeightMeasureSpec; 28080 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 28081 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 28082 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 28083 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 28084 final boolean needsLayout = specChanged 28085 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 28086 28087 if (forceLayout || needsLayout) { 28088 // first clears the measured dimension flag 28089 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 28090 28091 resolveRtlPropertiesIfNeeded(); 28092 28093 int cacheIndex; 28094 if (sUseMeasureCacheDuringForceLayoutFlagValue) { 28095 cacheIndex = mMeasureCache.indexOfKey(key); 28096 } else { 28097 cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 28098 } 28099 28100 if (cacheIndex < 0) { 28101 if (isTraversalTracingEnabled()) { 28102 Trace.beginSection(mTracingStrings.onMeasure); 28103 } 28104 if (android.os.Flags.adpfMeasureDuringInputEventBoost()) { 28105 final boolean notifyRenderer = hasExpensiveMeasuresDuringInputEvent(); 28106 if (notifyRenderer) { 28107 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 28108 "CPU_LOAD_UP: " + "hasExpensiveMeasuresDuringInputEvent"); 28109 getViewRootImpl().notifyRendererOfExpensiveFrame(); 28110 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 28111 } 28112 } 28113 // measure ourselves, this should set the measured dimension flag back 28114 onMeasure(widthMeasureSpec, heightMeasureSpec); 28115 if (isTraversalTracingEnabled()) { 28116 Trace.endSection(); 28117 } 28118 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 28119 } else { 28120 long value = mMeasureCache.valueAt(cacheIndex); 28121 // Casting a long to int drops the high 32 bits, no mask needed 28122 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 28123 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 28124 } 28125 28126 // flag not set, setMeasuredDimension() was not invoked, we raise 28127 // an exception to warn the developer 28128 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 28129 throw new IllegalStateException("View with id " + getId() + ": " 28130 + getClass().getName() + "#onMeasure() did not set the" 28131 + " measured dimension by calling" 28132 + " setMeasuredDimension()"); 28133 } 28134 28135 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 28136 } 28137 28138 mOldWidthMeasureSpec = widthMeasureSpec; 28139 mOldHeightMeasureSpec = heightMeasureSpec; 28140 28141 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 28142 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 28143 } 28144 28145 /** 28146 * <p> 28147 * Measure the view and its content to determine the measured width and the 28148 * measured height. This method is invoked by {@link #measure(int, int)} and 28149 * should be overridden by subclasses to provide accurate and efficient 28150 * measurement of their contents. 28151 * </p> 28152 * 28153 * <p> 28154 * <strong>CONTRACT:</strong> When overriding this method, you 28155 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 28156 * measured width and height of this view. Failure to do so will trigger an 28157 * <code>IllegalStateException</code>, thrown by 28158 * {@link #measure(int, int)}. Calling the superclass' 28159 * {@link #onMeasure(int, int)} is a valid use. 28160 * </p> 28161 * 28162 * <p> 28163 * The base class implementation of measure defaults to the background size, 28164 * unless a larger size is allowed by the MeasureSpec. Subclasses should 28165 * override {@link #onMeasure(int, int)} to provide better measurements of 28166 * their content. 28167 * </p> 28168 * 28169 * <p> 28170 * If this method is overridden, it is the subclass's responsibility to make 28171 * sure the measured height and width are at least the view's minimum height 28172 * and width ({@link #getSuggestedMinimumHeight()} and 28173 * {@link #getSuggestedMinimumWidth()}). 28174 * </p> 28175 * 28176 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 28177 * The requirements are encoded with 28178 * {@link android.view.View.MeasureSpec}. 28179 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 28180 * The requirements are encoded with 28181 * {@link android.view.View.MeasureSpec}. 28182 * 28183 * @see #getMeasuredWidth() 28184 * @see #getMeasuredHeight() 28185 * @see #setMeasuredDimension(int, int) 28186 * @see #getSuggestedMinimumHeight() 28187 * @see #getSuggestedMinimumWidth() 28188 * @see android.view.View.MeasureSpec#getMode(int) 28189 * @see android.view.View.MeasureSpec#getSize(int) 28190 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)28191 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28192 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 28193 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 28194 } 28195 28196 /** 28197 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 28198 * measured width and measured height. Failing to do so will trigger an 28199 * exception at measurement time.</p> 28200 * 28201 * @param measuredWidth The measured width of this view. May be a complex 28202 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28203 * {@link #MEASURED_STATE_TOO_SMALL}. 28204 * @param measuredHeight The measured height of this view. May be a complex 28205 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28206 * {@link #MEASURED_STATE_TOO_SMALL}. 28207 */ setMeasuredDimension(int measuredWidth, int measuredHeight)28208 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 28209 boolean optical = isLayoutModeOptical(this); 28210 if (optical != isLayoutModeOptical(mParent)) { 28211 Insets insets = getOpticalInsets(); 28212 int opticalWidth = insets.left + insets.right; 28213 int opticalHeight = insets.top + insets.bottom; 28214 28215 measuredWidth += optical ? opticalWidth : -opticalWidth; 28216 measuredHeight += optical ? opticalHeight : -opticalHeight; 28217 } 28218 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 28219 } 28220 28221 /** 28222 * Sets the measured dimension without extra processing for things like optical bounds. 28223 * Useful for reapplying consistent values that have already been cooked with adjustments 28224 * for optical bounds, etc. such as those from the measurement cache. 28225 * 28226 * @param measuredWidth The measured width of this view. May be a complex 28227 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28228 * {@link #MEASURED_STATE_TOO_SMALL}. 28229 * @param measuredHeight The measured height of this view. May be a complex 28230 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28231 * {@link #MEASURED_STATE_TOO_SMALL}. 28232 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)28233 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 28234 mMeasuredWidth = measuredWidth; 28235 mMeasuredHeight = measuredHeight; 28236 28237 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 28238 } 28239 28240 /** 28241 * Merge two states as returned by {@link #getMeasuredState()}. 28242 * @param curState The current state as returned from a view or the result 28243 * of combining multiple views. 28244 * @param newState The new view state to combine. 28245 * @return Returns a new integer reflecting the combination of the two 28246 * states. 28247 */ combineMeasuredStates(int curState, int newState)28248 public static int combineMeasuredStates(int curState, int newState) { 28249 return curState | newState; 28250 } 28251 28252 /** 28253 * Version of {@link #resolveSizeAndState(int, int, int)} 28254 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 28255 */ resolveSize(int size, int measureSpec)28256 public static int resolveSize(int size, int measureSpec) { 28257 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 28258 } 28259 28260 /** 28261 * Utility to reconcile a desired size and state, with constraints imposed 28262 * by a MeasureSpec. Will take the desired size, unless a different size 28263 * is imposed by the constraints. The returned value is a compound integer, 28264 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 28265 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 28266 * resulting size is smaller than the size the view wants to be. 28267 * 28268 * @param size How big the view wants to be. 28269 * @param measureSpec Constraints imposed by the parent. 28270 * @param childMeasuredState Size information bit mask for the view's 28271 * children. 28272 * @return Size information bit mask as defined by 28273 * {@link #MEASURED_SIZE_MASK} and 28274 * {@link #MEASURED_STATE_TOO_SMALL}. 28275 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)28276 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 28277 final int specMode = MeasureSpec.getMode(measureSpec); 28278 final int specSize = MeasureSpec.getSize(measureSpec); 28279 final int result; 28280 switch (specMode) { 28281 case MeasureSpec.AT_MOST: 28282 if (specSize < size) { 28283 result = specSize | MEASURED_STATE_TOO_SMALL; 28284 } else { 28285 result = size; 28286 } 28287 break; 28288 case MeasureSpec.EXACTLY: 28289 result = specSize; 28290 break; 28291 case MeasureSpec.UNSPECIFIED: 28292 default: 28293 result = size; 28294 } 28295 return result | (childMeasuredState & MEASURED_STATE_MASK); 28296 } 28297 28298 /** 28299 * Utility to return a default size. Uses the supplied size if the 28300 * MeasureSpec imposed no constraints. Will get larger if allowed 28301 * by the MeasureSpec. 28302 * 28303 * @param size Default size for this view 28304 * @param measureSpec Constraints imposed by the parent 28305 * @return The size this view should be. 28306 */ getDefaultSize(int size, int measureSpec)28307 public static int getDefaultSize(int size, int measureSpec) { 28308 int result = size; 28309 int specMode = MeasureSpec.getMode(measureSpec); 28310 int specSize = MeasureSpec.getSize(measureSpec); 28311 28312 switch (specMode) { 28313 case MeasureSpec.UNSPECIFIED: 28314 result = size; 28315 break; 28316 case MeasureSpec.AT_MOST: 28317 case MeasureSpec.EXACTLY: 28318 result = specSize; 28319 break; 28320 } 28321 return result; 28322 } 28323 28324 /** 28325 * Returns the suggested minimum height that the view should use. This 28326 * returns the maximum of the view's minimum height 28327 * and the background's minimum height 28328 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 28329 * <p> 28330 * When being used in {@link #onMeasure(int, int)}, the caller should still 28331 * ensure the returned height is within the requirements of the parent. 28332 * 28333 * @return The suggested minimum height of the view. 28334 */ getSuggestedMinimumHeight()28335 protected int getSuggestedMinimumHeight() { 28336 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 28337 28338 } 28339 28340 /** 28341 * Returns the suggested minimum width that the view should use. This 28342 * returns the maximum of the view's minimum width 28343 * and the background's minimum width 28344 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 28345 * <p> 28346 * When being used in {@link #onMeasure(int, int)}, the caller should still 28347 * ensure the returned width is within the requirements of the parent. 28348 * 28349 * @return The suggested minimum width of the view. 28350 */ getSuggestedMinimumWidth()28351 protected int getSuggestedMinimumWidth() { 28352 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 28353 } 28354 28355 /** 28356 * Returns the minimum height of the view. 28357 * 28358 * @return the minimum height the view will try to be, in pixels 28359 * 28360 * @see #setMinimumHeight(int) 28361 * 28362 * @attr ref android.R.styleable#View_minHeight 28363 */ 28364 @InspectableProperty(name = "minHeight") getMinimumHeight()28365 public int getMinimumHeight() { 28366 return mMinHeight; 28367 } 28368 28369 /** 28370 * Sets the minimum height of the view. It is not guaranteed the view will 28371 * be able to achieve this minimum height (for example, if its parent layout 28372 * constrains it with less available height). 28373 * 28374 * @param minHeight The minimum height the view will try to be, in pixels 28375 * 28376 * @see #getMinimumHeight() 28377 * 28378 * @attr ref android.R.styleable#View_minHeight 28379 */ 28380 @RemotableViewMethod setMinimumHeight(int minHeight)28381 public void setMinimumHeight(int minHeight) { 28382 mMinHeight = minHeight; 28383 requestLayout(); 28384 } 28385 28386 /** 28387 * Returns the minimum width of the view. 28388 * 28389 * @return the minimum width the view will try to be, in pixels 28390 * 28391 * @see #setMinimumWidth(int) 28392 * 28393 * @attr ref android.R.styleable#View_minWidth 28394 */ 28395 @InspectableProperty(name = "minWidth") getMinimumWidth()28396 public int getMinimumWidth() { 28397 return mMinWidth; 28398 } 28399 28400 /** 28401 * Sets the minimum width of the view. It is not guaranteed the view will 28402 * be able to achieve this minimum width (for example, if its parent layout 28403 * constrains it with less available width). 28404 * 28405 * @param minWidth The minimum width the view will try to be, in pixels 28406 * 28407 * @see #getMinimumWidth() 28408 * 28409 * @attr ref android.R.styleable#View_minWidth 28410 */ 28411 @RemotableViewMethod setMinimumWidth(int minWidth)28412 public void setMinimumWidth(int minWidth) { 28413 mMinWidth = minWidth; 28414 requestLayout(); 28415 28416 } 28417 28418 /** 28419 * Get the animation currently associated with this view. 28420 * 28421 * @return The animation that is currently playing or 28422 * scheduled to play for this view. 28423 */ getAnimation()28424 public Animation getAnimation() { 28425 return mCurrentAnimation; 28426 } 28427 28428 /** 28429 * Start the specified animation now. 28430 * 28431 * @param animation the animation to start now 28432 */ startAnimation(Animation animation)28433 public void startAnimation(Animation animation) { 28434 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 28435 setAnimation(animation); 28436 invalidateParentCaches(); 28437 invalidate(true); 28438 } 28439 28440 /** 28441 * Cancels any animations for this view. 28442 */ clearAnimation()28443 public void clearAnimation() { 28444 if (mCurrentAnimation != null) { 28445 mCurrentAnimation.detach(); 28446 } 28447 mCurrentAnimation = null; 28448 invalidateParentIfNeeded(); 28449 } 28450 28451 /** 28452 * Sets the next animation to play for this view. 28453 * If you want the animation to play immediately, use 28454 * {@link #startAnimation(android.view.animation.Animation)} instead. 28455 * This method provides allows fine-grained 28456 * control over the start time and invalidation, but you 28457 * must make sure that 1) the animation has a start time set, and 28458 * 2) the view's parent (which controls animations on its children) 28459 * will be invalidated when the animation is supposed to 28460 * start. 28461 * 28462 * @param animation The next animation, or null. 28463 */ setAnimation(Animation animation)28464 public void setAnimation(Animation animation) { 28465 mCurrentAnimation = animation; 28466 28467 if (animation != null) { 28468 // If the screen is off assume the animation start time is now instead of 28469 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 28470 // would cause the animation to start when the screen turns back on 28471 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 28472 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 28473 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 28474 } 28475 animation.reset(); 28476 } 28477 } 28478 28479 /** 28480 * Invoked by a parent ViewGroup to notify the start of the animation 28481 * currently associated with this view. If you override this method, 28482 * always call super.onAnimationStart(); 28483 * 28484 * @see #setAnimation(android.view.animation.Animation) 28485 * @see #getAnimation() 28486 */ 28487 @CallSuper onAnimationStart()28488 protected void onAnimationStart() { 28489 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 28490 } 28491 28492 /** 28493 * Invoked by a parent ViewGroup to notify the end of the animation 28494 * currently associated with this view. If you override this method, 28495 * always call super.onAnimationEnd(); 28496 * 28497 * @see #setAnimation(android.view.animation.Animation) 28498 * @see #getAnimation() 28499 */ 28500 @CallSuper onAnimationEnd()28501 protected void onAnimationEnd() { 28502 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 28503 } 28504 28505 /** 28506 * Invoked if there is a Transform that involves alpha. Subclass that can 28507 * draw themselves with the specified alpha should return true, and then 28508 * respect that alpha when their onDraw() is called. If this returns false 28509 * then the view may be redirected to draw into an offscreen buffer to 28510 * fulfill the request, which will look fine, but may be slower than if the 28511 * subclass handles it internally. The default implementation returns false. 28512 * 28513 * @param alpha The alpha (0..255) to apply to the view's drawing 28514 * @return true if the view can draw with the specified alpha. 28515 */ onSetAlpha(int alpha)28516 protected boolean onSetAlpha(int alpha) { 28517 return false; 28518 } 28519 28520 /** 28521 * This is used by the ViewRoot to perform an optimization when 28522 * the view hierarchy contains one or several SurfaceView. 28523 * SurfaceView is always considered transparent, but its children are not, 28524 * therefore all View objects remove themselves from the global transparent 28525 * region (passed as a parameter to this function). 28526 * 28527 * @param region The transparent region for this ViewAncestor (window). 28528 * 28529 * @return Returns true if the effective visibility of the view at this 28530 * point is opaque, regardless of the transparent region; returns false 28531 * if it is possible for underlying windows to be seen behind the view. 28532 * 28533 */ gatherTransparentRegion(@ullable Region region)28534 public boolean gatherTransparentRegion(@Nullable Region region) { 28535 final AttachInfo attachInfo = mAttachInfo; 28536 if (region != null && attachInfo != null) { 28537 final int pflags = mPrivateFlags; 28538 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 28539 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 28540 // remove it from the transparent region. 28541 final int[] location = attachInfo.mTransparentLocation; 28542 getLocationInWindow(location); 28543 // When a view has Z value, then it will be better to leave some area below the view 28544 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 28545 // the bottom part needs more offset than the left, top and right parts due to the 28546 // spot light effects. 28547 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 28548 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 28549 location[0] + mRight - mLeft + shadowOffset, 28550 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 28551 } else { 28552 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 28553 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 28554 // the background drawable's non-transparent parts from this transparent region. 28555 applyDrawableToTransparentRegion(mBackground, region); 28556 } 28557 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 28558 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 28559 // Similarly, we remove the foreground drawable's non-transparent parts. 28560 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 28561 } 28562 if (mDefaultFocusHighlight != null 28563 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 28564 // Similarly, we remove the default focus highlight's non-transparent parts. 28565 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 28566 } 28567 } 28568 } 28569 return true; 28570 } 28571 28572 /** 28573 * Play a sound effect for this view. 28574 * 28575 * <p>The framework will play sound effects for some built in actions, such as 28576 * clicking, but you may wish to play these effects in your widget, 28577 * for instance, for internal navigation. 28578 * 28579 * <p>The sound effect will only be played if sound effects are enabled by the user, and 28580 * {@link #isSoundEffectsEnabled()} is true. 28581 * 28582 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}. 28583 */ playSoundEffect(@oundEffectConstants.SoundEffect int soundConstant)28584 public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { 28585 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 28586 return; 28587 } 28588 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 28589 } 28590 28591 /** 28592 * BZZZTT!!1! 28593 * 28594 * <p>Provide haptic feedback to the user for this view. 28595 * 28596 * <p>The framework will provide haptic feedback for some built in actions, 28597 * such as long presses, but you may wish to provide feedback for your 28598 * own widget. 28599 * 28600 * <p>The feedback will only be performed if 28601 * {@link #isHapticFeedbackEnabled()} is true. 28602 * 28603 * @param feedbackConstant One of the constants defined in 28604 * {@link HapticFeedbackConstants} 28605 */ performHapticFeedback(int feedbackConstant)28606 public boolean performHapticFeedback(int feedbackConstant) { 28607 return performHapticFeedback(feedbackConstant, 0); 28608 } 28609 28610 /** 28611 * BZZZTT!!1! 28612 * 28613 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 28614 * 28615 * @param feedbackConstant One of the constants defined in 28616 * {@link HapticFeedbackConstants} 28617 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 28618 */ performHapticFeedback(int feedbackConstant, int flags)28619 public boolean performHapticFeedback(int feedbackConstant, int flags) { 28620 if (feedbackConstant == HapticFeedbackConstants.NO_HAPTICS 28621 || mAttachInfo == null) { 28622 return false; 28623 } 28624 //noinspection SimplifiableIfStatement 28625 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 28626 && !isHapticFeedbackEnabled()) { 28627 return false; 28628 } 28629 28630 final boolean always = (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0; 28631 boolean fromIme = false; 28632 if (mAttachInfo.mViewRootImpl != null) { 28633 fromIme = mAttachInfo.mViewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD; 28634 } 28635 if (Flags.useVibratorHapticFeedback()) { 28636 if (!mAttachInfo.canPerformHapticFeedback()) { 28637 return false; 28638 } 28639 getSystemVibrator().performHapticFeedback( 28640 feedbackConstant, always, "View#performHapticFeedback", fromIme); 28641 return true; 28642 } 28643 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, always, fromIme); 28644 } 28645 getSystemVibrator()28646 private Vibrator getSystemVibrator() { 28647 if (mVibrator != null) { 28648 return mVibrator; 28649 } 28650 return mVibrator = mContext.getSystemService(Vibrator.class); 28651 } 28652 28653 /** 28654 * Request that the visibility of the status bar or other screen/window 28655 * decorations be changed. 28656 * 28657 * <p>This method is used to put the over device UI into temporary modes 28658 * where the user's attention is focused more on the application content, 28659 * by dimming or hiding surrounding system affordances. This is typically 28660 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 28661 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 28662 * to be placed behind the action bar (and with these flags other system 28663 * affordances) so that smooth transitions between hiding and showing them 28664 * can be done. 28665 * 28666 * <p>Two representative examples of the use of system UI visibility is 28667 * implementing a content browsing application (like a magazine reader) 28668 * and a video playing application. 28669 * 28670 * <p>The first code shows a typical implementation of a View in a content 28671 * browsing application. In this implementation, the application goes 28672 * into a content-oriented mode by hiding the status bar and action bar, 28673 * and putting the navigation elements into lights out mode. The user can 28674 * then interact with content while in this mode. Such an application should 28675 * provide an easy way for the user to toggle out of the mode (such as to 28676 * check information in the status bar or access notifications). In the 28677 * implementation here, this is done simply by tapping on the content. 28678 * 28679 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 28680 * content} 28681 * 28682 * <p>This second code sample shows a typical implementation of a View 28683 * in a video playing application. In this situation, while the video is 28684 * playing the application would like to go into a complete full-screen mode, 28685 * to use as much of the display as possible for the video. When in this state 28686 * the user can not interact with the application; the system intercepts 28687 * touching on the screen to pop the UI out of full screen mode. See 28688 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 28689 * 28690 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 28691 * content} 28692 * 28693 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 28694 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 28695 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 28696 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 28697 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 28698 * 28699 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 28700 * instead. 28701 */ 28702 @Deprecated setSystemUiVisibility(int visibility)28703 public void setSystemUiVisibility(int visibility) { 28704 if (visibility != mSystemUiVisibility) { 28705 mSystemUiVisibility = visibility; 28706 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 28707 mParent.recomputeViewAttributes(this); 28708 } 28709 } 28710 } 28711 28712 /** 28713 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 28714 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 28715 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 28716 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 28717 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 28718 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 28719 * 28720 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 28721 * instead. 28722 */ 28723 @Deprecated getSystemUiVisibility()28724 public int getSystemUiVisibility() { 28725 return mSystemUiVisibility; 28726 } 28727 28728 /** 28729 * Returns the current system UI visibility that is currently set for 28730 * the entire window. This is the combination of the 28731 * {@link #setSystemUiVisibility(int)} values supplied by all of the 28732 * views in the window. 28733 * 28734 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 28735 * instead. 28736 */ 28737 @Deprecated getWindowSystemUiVisibility()28738 public int getWindowSystemUiVisibility() { 28739 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 28740 } 28741 28742 /** 28743 * Override to find out when the window's requested system UI visibility 28744 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 28745 * This is different from the callbacks received through 28746 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 28747 * in that this is only telling you about the local request of the window, 28748 * not the actual values applied by the system. 28749 * 28750 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 28751 * instead. 28752 */ 28753 @Deprecated onWindowSystemUiVisibilityChanged(int visible)28754 public void onWindowSystemUiVisibilityChanged(int visible) { 28755 } 28756 28757 /** 28758 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 28759 * the view hierarchy. 28760 * 28761 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 28762 * instead. 28763 */ 28764 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)28765 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 28766 onWindowSystemUiVisibilityChanged(visible); 28767 } 28768 28769 /** 28770 * Set a listener to receive callbacks when the visibility of the system bar changes. 28771 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 28772 * 28773 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 28774 * by setting a {@link OnApplyWindowInsetsListener} on this view. 28775 */ 28776 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)28777 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 28778 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 28779 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 28780 mParent.recomputeViewAttributes(this); 28781 } 28782 } 28783 28784 /** 28785 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 28786 * the view hierarchy. 28787 * 28788 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 28789 * by setting a {@link OnApplyWindowInsetsListener} on this view. 28790 */ 28791 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)28792 public void dispatchSystemUiVisibilityChanged(int visibility) { 28793 ListenerInfo li = mListenerInfo; 28794 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 28795 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 28796 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 28797 } 28798 } 28799 updateLocalSystemUiVisibility(int localValue, int localChanges)28800 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 28801 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 28802 if (val != mSystemUiVisibility) { 28803 setSystemUiVisibility(val); 28804 return true; 28805 } 28806 return false; 28807 } 28808 28809 /** @hide */ 28810 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setDisabledSystemUiVisibility(int flags)28811 public void setDisabledSystemUiVisibility(int flags) { 28812 if (mAttachInfo != null) { 28813 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 28814 mAttachInfo.mDisabledSystemUiVisibility = flags; 28815 if (mParent != null) { 28816 mParent.recomputeViewAttributes(this); 28817 } 28818 } 28819 } 28820 } 28821 28822 /** 28823 * This needs to be a better API before it is exposed. For now, only the root view will get 28824 * notified. 28825 * @hide 28826 */ onSystemBarAppearanceChanged(@indowInsetsController.Appearance int appearance)28827 public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { 28828 } 28829 28830 /** 28831 * Creates an image that the system displays during the drag and drop 28832 * operation. This is called a "drag shadow". The default implementation 28833 * for a DragShadowBuilder based on a View returns an image that has exactly the same 28834 * appearance as the given View. The default also positions the center of the drag shadow 28835 * directly under the touch point. If no View is provided (the constructor with no parameters 28836 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 28837 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 28838 * default is an invisible drag shadow. 28839 * <p> 28840 * You are not required to use the View you provide to the constructor as the basis of the 28841 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 28842 * anything you want as the drag shadow. 28843 * </p> 28844 * <p> 28845 * You pass a DragShadowBuilder object to the system when you start the drag. The system 28846 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 28847 * size and position of the drag shadow. It uses this data to construct a 28848 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 28849 * so that your application can draw the shadow image in the Canvas. 28850 * </p> 28851 * 28852 * <div class="special reference"> 28853 * <h3>Developer Guides</h3> 28854 * <p>For a guide to implementing drag and drop features, read the 28855 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 28856 * </div> 28857 */ 28858 public static class DragShadowBuilder { 28859 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 28860 private final WeakReference<View> mView; 28861 28862 /** 28863 * Constructs a shadow image builder based on a View. By default, the resulting drag 28864 * shadow will have the same appearance and dimensions as the View, with the touch point 28865 * over the center of the View. 28866 * @param view A View. Any View in scope can be used. 28867 */ DragShadowBuilder(View view)28868 public DragShadowBuilder(View view) { 28869 mView = new WeakReference<View>(view); 28870 } 28871 28872 /** 28873 * Construct a shadow builder object with no associated View. This 28874 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 28875 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 28876 * to supply the drag shadow's dimensions and appearance without 28877 * reference to any View object. 28878 */ DragShadowBuilder()28879 public DragShadowBuilder() { 28880 mView = new WeakReference<View>(null); 28881 } 28882 28883 /** 28884 * Returns the View object that had been passed to the 28885 * {@link #DragShadowBuilder(View)} 28886 * constructor. If that View parameter was {@code null} or if the 28887 * {@link #DragShadowBuilder()} 28888 * constructor was used to instantiate the builder object, this method will return 28889 * null. 28890 * 28891 * @return The View object associate with this builder object. 28892 */ 28893 @SuppressWarnings({"JavadocReference"}) getView()28894 final public View getView() { 28895 return mView.get(); 28896 } 28897 28898 /** 28899 * Provides the metrics for the shadow image. These include the dimensions of 28900 * the shadow image, and the point within that shadow that should 28901 * be centered under the touch location while dragging. 28902 * <p> 28903 * The default implementation sets the dimensions of the shadow to be the 28904 * same as the dimensions of the View itself and centers the shadow under 28905 * the touch point. 28906 * </p> 28907 * 28908 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 28909 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 28910 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 28911 * image. Since Android P, the width and height must be positive values. 28912 * 28913 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 28914 * shadow image that should be underneath the touch point during the drag and drop 28915 * operation. Your application must set {@link android.graphics.Point#x} to the 28916 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 28917 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)28918 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 28919 final View view = mView.get(); 28920 if (view != null) { 28921 outShadowSize.set(view.getWidth(), view.getHeight()); 28922 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 28923 } else { 28924 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 28925 } 28926 } 28927 28928 /** 28929 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 28930 * based on the dimensions it received from the 28931 * {@link #onProvideShadowMetrics(Point, Point)} callback. 28932 * 28933 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 28934 */ onDrawShadow(@onNull Canvas canvas)28935 public void onDrawShadow(@NonNull Canvas canvas) { 28936 final View view = mView.get(); 28937 if (view != null) { 28938 view.draw(canvas); 28939 } else { 28940 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 28941 } 28942 } 28943 } 28944 28945 /** 28946 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 28947 * startDragAndDrop()} for newer platform versions. 28948 */ 28949 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)28950 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 28951 Object myLocalState, int flags) { 28952 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 28953 } 28954 28955 /** 28956 * Starts a drag and drop operation. When your application calls this method, it passes a 28957 * {@link android.view.View.DragShadowBuilder} object to the system. The 28958 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 28959 * to get metrics for the drag shadow, and then calls the object's 28960 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 28961 * <p> 28962 * Once the system has the drag shadow, it begins the drag and drop operation by sending 28963 * drag events to all the View objects in your application that are currently visible. It does 28964 * this either by calling the View object's drag listener (an implementation of 28965 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 28966 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 28967 * Both are passed a {@link android.view.DragEvent} object that has a 28968 * {@link android.view.DragEvent#getAction()} value of 28969 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 28970 * </p> 28971 * <p> 28972 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 28973 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 28974 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 28975 * to the View the user selected for dragging. 28976 * </p> 28977 * @param data A {@link android.content.ClipData} object pointing to the data to be 28978 * transferred by the drag and drop operation. 28979 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 28980 * drag shadow. 28981 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 28982 * drop operation. When dispatching drag events to views in the same activity this object 28983 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 28984 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 28985 * will return null). 28986 * <p> 28987 * myLocalState is a lightweight mechanism for the sending information from the dragged View 28988 * to the target Views. For example, it can contain flags that differentiate between a 28989 * a copy operation and a move operation. 28990 * </p> 28991 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 28992 * flags, or any combination of the following: 28993 * <ul> 28994 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 28995 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 28996 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 28997 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 28998 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 28999 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 29000 * <li>{@link #DRAG_FLAG_ACCESSIBILITY_ACTION}</li> 29001 * </ul> 29002 * @return {@code true} if the method completes successfully, or 29003 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 29004 * do a drag because of another ongoing operation or some other reasons. 29005 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)29006 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 29007 Object myLocalState, int flags) { 29008 if (ViewDebug.DEBUG_DRAG) { 29009 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 29010 } 29011 if (mAttachInfo == null) { 29012 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 29013 return false; 29014 } 29015 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 29016 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 29017 return false; 29018 } 29019 if ((flags & DRAG_FLAG_GLOBAL) != 0 && ((flags & DRAG_FLAG_GLOBAL_SAME_APPLICATION) != 0)) { 29020 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with both DRAG_FLAG_GLOBAL " 29021 + "and DRAG_FLAG_GLOBAL_SAME_APPLICATION, the drag will default to " 29022 + "DRAG_FLAG_GLOBAL_SAME_APPLICATION"); 29023 flags &= ~DRAG_FLAG_GLOBAL; 29024 } 29025 29026 if (data != null) { 29027 if (com.android.window.flags.Flags.delegateUnhandledDrags()) { 29028 data.prepareToLeaveProcess( 29029 (flags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) != 0); 29030 if ((flags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0) { 29031 if (!hasActivityPendingIntents(data)) { 29032 // Reset the flag if there is no launchable activity intent 29033 flags &= ~DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG; 29034 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with " 29035 + "DRAG_FLAG_START_INTENT_ON_UNHANDLED_DRAG but the clip data " 29036 + "contains non-activity PendingIntents"); 29037 } 29038 } 29039 } else { 29040 data.prepareToLeaveProcess((flags & DRAG_FLAG_GLOBAL) != 0); 29041 } 29042 } 29043 29044 Rect bounds = new Rect(); 29045 getBoundsOnScreen(bounds, true); 29046 29047 Point lastTouchPoint = new Point(); 29048 mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); 29049 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 29050 29051 // Skip surface logic since shadows and animation are not required during the a11y drag 29052 final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); 29053 if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { 29054 try { 29055 IBinder token = mAttachInfo.mSession.performDrag( 29056 mAttachInfo.mWindow, flags, null, 29057 mAttachInfo.mViewRootImpl.getLastTouchSource(), 29058 mAttachInfo.mViewRootImpl.getLastTouchDeviceId(), 29059 mAttachInfo.mViewRootImpl.getLastTouchPointerId(), 29060 0f, 0f, 0f, 0f, data); 29061 if (ViewDebug.DEBUG_DRAG) { 29062 Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); 29063 } 29064 if (token != null) { 29065 root.setLocalDragState(myLocalState); 29066 mAttachInfo.mDragToken = token; 29067 mAttachInfo.mDragData = data; 29068 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 29069 setAccessibilityDragStarted(true); 29070 } 29071 return token != null; 29072 } catch (Exception e) { 29073 Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); 29074 return false; 29075 } 29076 } 29077 29078 Point shadowSize = new Point(); 29079 Point shadowTouchPoint = new Point(); 29080 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 29081 29082 if ((shadowSize.x < 0) || (shadowSize.y < 0) 29083 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 29084 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 29085 } 29086 final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale(); 29087 if (overrideInvScale != 1f) { 29088 shadowTouchPoint.x = (int) (shadowTouchPoint.x / overrideInvScale); 29089 shadowTouchPoint.y = (int) (shadowTouchPoint.y / overrideInvScale); 29090 } 29091 29092 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 29093 // does not accept zero size surface. 29094 if (shadowSize.x == 0 || shadowSize.y == 0) { 29095 if (!sAcceptZeroSizeDragShadow) { 29096 throw new IllegalStateException("Drag shadow dimensions must be positive"); 29097 } 29098 shadowSize.x = 1; 29099 shadowSize.y = 1; 29100 } 29101 29102 if (ViewDebug.DEBUG_DRAG) { 29103 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 29104 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 29105 } 29106 29107 final SurfaceSession session = new SurfaceSession(); 29108 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 29109 .setName("drag surface") 29110 .setParent(root.getSurfaceControl()) 29111 .setBufferSize(shadowSize.x, shadowSize.y) 29112 .setFormat(PixelFormat.TRANSLUCENT) 29113 .setCallsite("View.startDragAndDrop") 29114 .build(); 29115 if (overrideInvScale != 1f) { 29116 final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); 29117 transaction.setMatrix(surfaceControl, 1 / overrideInvScale, 0, 0, 1 / overrideInvScale) 29118 .apply(); 29119 } 29120 final Surface surface = new Surface(); 29121 surface.copyFrom(surfaceControl); 29122 IBinder token = null; 29123 try { 29124 Trace.traceBegin(TRACE_TAG_VIEW, "startDragAndDrop#drawDragShadow"); 29125 final Canvas canvas = isHardwareAccelerated() 29126 ? surface.lockHardwareCanvas() 29127 : surface.lockCanvas(null); 29128 try { 29129 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 29130 shadowBuilder.onDrawShadow(canvas); 29131 } finally { 29132 surface.unlockCanvasAndPost(canvas); 29133 Trace.traceEnd(TRACE_TAG_VIEW); 29134 } 29135 29136 Trace.traceBegin(TRACE_TAG_VIEW, "startDragAndDrop#performDrag"); 29137 try { 29138 token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, 29139 root.getLastTouchSource(), root.getLastTouchDeviceId(), 29140 root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y, 29141 shadowTouchPoint.x, shadowTouchPoint.y, data); 29142 if (ViewDebug.DEBUG_DRAG) { 29143 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 29144 } 29145 if (token != null) { 29146 if (mAttachInfo.mDragSurface != null) { 29147 mAttachInfo.mDragSurface.release(); 29148 } 29149 if (mAttachInfo.mDragData != null) { 29150 // Clean up previous drag data intents 29151 View.cleanUpPendingIntents(mAttachInfo.mDragData); 29152 } 29153 mAttachInfo.mDragSurface = surface; 29154 mAttachInfo.mDragToken = token; 29155 mAttachInfo.mDragData = data; 29156 // Cache the local state object for delivery with DragEvents 29157 root.setLocalDragState(myLocalState); 29158 if (a11yEnabled) { 29159 // Set for AccessibilityEvents 29160 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 29161 } 29162 } 29163 return token != null; 29164 } finally { 29165 Trace.traceEnd(TRACE_TAG_VIEW); 29166 } 29167 } catch (Exception e) { 29168 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 29169 return false; 29170 } finally { 29171 if (token == null) { 29172 surface.destroy(); 29173 } 29174 session.kill(); 29175 surfaceControl.release(); 29176 } 29177 } 29178 29179 /** 29180 * Checks if this clip data has a pending intent that is an activity type. 29181 * @hide 29182 */ hasActivityPendingIntents(ClipData data)29183 static boolean hasActivityPendingIntents(ClipData data) { 29184 final int size = data.getItemCount(); 29185 for (int i = 0; i < size; i++) { 29186 final ClipData.Item item = data.getItemAt(i); 29187 if (item.getIntentSender() != null) { 29188 final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget()); 29189 if (pi.isActivity()) { 29190 return true; 29191 } 29192 } 29193 } 29194 return false; 29195 } 29196 29197 /** 29198 * Cleans up all pending intents in the ClipData. 29199 * @hide 29200 */ cleanUpPendingIntents(ClipData data)29201 static void cleanUpPendingIntents(ClipData data) { 29202 final int size = data.getItemCount(); 29203 for (int i = 0; i < size; i++) { 29204 final ClipData.Item item = data.getItemAt(i); 29205 if (item.getIntentSender() != null) { 29206 final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget()); 29207 pi.cancel(); 29208 } 29209 } 29210 } 29211 setAccessibilityDragStarted(boolean started)29212 void setAccessibilityDragStarted(boolean started) { 29213 int pflags4 = mPrivateFlags4; 29214 if (started) { 29215 pflags4 |= PFLAG4_DRAG_A11Y_STARTED; 29216 } else { 29217 pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; 29218 } 29219 29220 if (pflags4 != mPrivateFlags4) { 29221 mPrivateFlags4 = pflags4; 29222 sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); 29223 } 29224 } 29225 startedSystemDragForAccessibility()29226 private boolean startedSystemDragForAccessibility() { 29227 return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; 29228 } 29229 29230 /** 29231 * Cancels an ongoing drag and drop operation. 29232 * <p> 29233 * A {@link android.view.DragEvent} object with 29234 * {@link android.view.DragEvent#getAction()} value of 29235 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 29236 * {@link android.view.DragEvent#getResult()} value of {@code false} 29237 * will be sent to every 29238 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 29239 * even if they are not currently visible. 29240 * </p> 29241 * <p> 29242 * This method can be called on any View in the same window as the View on which 29243 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 29244 * was called. 29245 * </p> 29246 */ cancelDragAndDrop()29247 public final void cancelDragAndDrop() { 29248 if (ViewDebug.DEBUG_DRAG) { 29249 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 29250 } 29251 if (mAttachInfo == null) { 29252 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 29253 return; 29254 } 29255 if (mAttachInfo.mDragToken != null) { 29256 try { 29257 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 29258 } catch (Exception e) { 29259 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 29260 } 29261 mAttachInfo.mDragToken = null; 29262 } else { 29263 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 29264 } 29265 } 29266 29267 /** 29268 * Updates the drag shadow for the ongoing drag and drop operation. 29269 * 29270 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 29271 * new drag shadow. 29272 */ updateDragShadow(DragShadowBuilder shadowBuilder)29273 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 29274 if (ViewDebug.DEBUG_DRAG) { 29275 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 29276 } 29277 if (mAttachInfo == null) { 29278 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 29279 return; 29280 } 29281 if (mAttachInfo.mDragToken != null) { 29282 try { 29283 Canvas canvas = isHardwareAccelerated() 29284 ? mAttachInfo.mDragSurface.lockHardwareCanvas() 29285 : mAttachInfo.mDragSurface.lockCanvas(null); 29286 try { 29287 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 29288 shadowBuilder.onDrawShadow(canvas); 29289 } finally { 29290 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 29291 } 29292 } catch (Exception e) { 29293 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 29294 } 29295 } else { 29296 Log.e(VIEW_LOG_TAG, "No active drag"); 29297 } 29298 } 29299 29300 /** 29301 * Starts a move from {startX, startY}, the amount of the movement will be the offset 29302 * between {startX, startY} and the new cursor positon. 29303 * @param startX horizontal coordinate where the move started. 29304 * @param startY vertical coordinate where the move started. 29305 * @return whether moving was started successfully. 29306 * @hide 29307 */ startMovingTask(float startX, float startY)29308 public final boolean startMovingTask(float startX, float startY) { 29309 if (ViewDebug.DEBUG_POSITIONING) { 29310 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 29311 } 29312 try { 29313 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 29314 } catch (RemoteException e) { 29315 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 29316 } 29317 return false; 29318 } 29319 29320 /** 29321 * Finish a window move task. 29322 * @hide 29323 */ finishMovingTask()29324 public void finishMovingTask() { 29325 if (ViewDebug.DEBUG_POSITIONING) { 29326 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 29327 } 29328 try { 29329 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 29330 } catch (RemoteException e) { 29331 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 29332 } 29333 } 29334 29335 /** 29336 * Handles drag events sent by the system following a call to 29337 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 29338 * startDragAndDrop()}. 29339 * <p> 29340 * The system calls this method and passes a {@link DragEvent} object in response to drag and 29341 * drop events. This method can then call {@link DragEvent#getAction()} to determine the state 29342 * of the drag and drop operation. 29343 * <p> 29344 * The default implementation returns {@code false} unless an {@link OnReceiveContentListener} 29345 * has been set for this view (see {@link #setOnReceiveContentListener}), in which case 29346 * the default implementation does the following: 29347 * <ul> 29348 * <li>Returns {@code true} for an 29349 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event 29350 * <li>Calls {@link #performReceiveContent} for an 29351 * {@link DragEvent#ACTION_DROP ACTION_DROP} event 29352 * <li>Returns {@code true} for an {@link DragEvent#ACTION_DROP ACTION_DROP} event if the 29353 * {@code OnReceiveContentListener} consumed some or all of the content 29354 * </ul> 29355 * 29356 * @param event The {@link DragEvent} object sent by the system. The 29357 * {@link DragEvent#getAction()} method returns an action type constant that indicates the 29358 * type of drag event represented by this object. 29359 * @return {@code true} if the method successfully handled the drag event, otherwise 29360 * {@code false}. 29361 * <p> 29362 * The method must return {@code true} in response to an 29363 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} action type to continue to 29364 * receive drag events for the current drag and drop operation. 29365 * <p> 29366 * The method should return {@code true} in response to an 29367 * {@link DragEvent#ACTION_DROP ACTION_DROP} action type if the dropped data was consumed 29368 * (at least partially); {@code false}, if none of the data was consumed. 29369 * <p> 29370 * For all other events, the return value is {@code false}. 29371 */ onDragEvent(DragEvent event)29372 public boolean onDragEvent(DragEvent event) { 29373 if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { 29374 return false; 29375 } 29376 // Accept drag events by default if there's an OnReceiveContentListener set. 29377 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { 29378 return true; 29379 } 29380 if (event.getAction() == DragEvent.ACTION_DROP) { 29381 final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); 29382 if (permissions != null) { 29383 permissions.takeTransient(); 29384 } 29385 final ContentInfo payload = 29386 new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) 29387 .setDragAndDropPermissions(permissions) 29388 .build(); 29389 ContentInfo remainingPayload = performReceiveContent(payload); 29390 // Return true unless none of the payload was consumed. 29391 return remainingPayload != payload; 29392 } 29393 return false; 29394 } 29395 29396 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)29397 boolean dispatchDragEnterExitInPreN(DragEvent event) { 29398 return callDragEventHandler(event); 29399 } 29400 29401 /** 29402 * Detects if this View is enabled and has a drag event listener. 29403 * If both are true, then it calls the drag event listener with the 29404 * {@link android.view.DragEvent} it received. If the drag event listener returns 29405 * {@code true}, then dispatchDragEvent() returns {@code true}. 29406 * <p> 29407 * For all other cases, the method calls the 29408 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 29409 * method and returns its result. 29410 * </p> 29411 * <p> 29412 * This ensures that a drag event is always consumed, even if the View does not have a drag 29413 * event listener. However, if the View has a listener and the listener returns true, then 29414 * onDragEvent() is not called. 29415 * </p> 29416 */ dispatchDragEvent(DragEvent event)29417 public boolean dispatchDragEvent(DragEvent event) { 29418 event.mEventHandlerWasCalled = true; 29419 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 29420 event.mAction == DragEvent.ACTION_DROP) { 29421 // About to deliver an event with coordinates to this view. Notify that now this view 29422 // has drag focus. This will send exit/enter events as needed. 29423 getViewRootImpl().setDragFocus(this, event); 29424 } 29425 return callDragEventHandler(event); 29426 } 29427 callDragEventHandler(DragEvent event)29428 final boolean callDragEventHandler(DragEvent event) { 29429 final boolean result; 29430 29431 ListenerInfo li = mListenerInfo; 29432 //noinspection SimplifiableIfStatement 29433 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 29434 && li.mOnDragListener.onDrag(this, event)) { 29435 result = true; 29436 } else { 29437 result = onDragEvent(event); 29438 } 29439 29440 switch (event.mAction) { 29441 case DragEvent.ACTION_DRAG_STARTED: { 29442 if (result && li != null && li.mOnDragListener != null) { 29443 sendWindowContentChangedAccessibilityEvent( 29444 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 29445 } 29446 } break; 29447 case DragEvent.ACTION_DRAG_ENTERED: { 29448 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 29449 refreshDrawableState(); 29450 } break; 29451 case DragEvent.ACTION_DRAG_EXITED: { 29452 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 29453 refreshDrawableState(); 29454 } break; 29455 case DragEvent.ACTION_DROP: { 29456 if (result && li != null && (li.mOnDragListener != null 29457 || li.mOnReceiveContentListener != null)) { 29458 sendWindowContentChangedAccessibilityEvent( 29459 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); 29460 } 29461 } break; 29462 case DragEvent.ACTION_DRAG_ENDED: { 29463 sendWindowContentChangedAccessibilityEvent( 29464 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 29465 mPrivateFlags2 &= ~View.DRAG_MASK; 29466 refreshDrawableState(); 29467 } break; 29468 } 29469 29470 return result; 29471 } 29472 canAcceptDrag()29473 boolean canAcceptDrag() { 29474 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 29475 } 29476 sendWindowContentChangedAccessibilityEvent(int changeType)29477 void sendWindowContentChangedAccessibilityEvent(int changeType) { 29478 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 29479 AccessibilityEvent event = AccessibilityEvent.obtain(); 29480 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 29481 event.setContentChangeTypes(changeType); 29482 sendAccessibilityEventUnchecked(event); 29483 } 29484 } 29485 29486 /** 29487 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 29488 * it is ever exposed at all. 29489 * @hide 29490 */ 29491 @UnsupportedAppUsage onCloseSystemDialogs(String reason)29492 public void onCloseSystemDialogs(String reason) { 29493 } 29494 29495 /** 29496 * Given a Drawable whose bounds have been set to draw into this view, 29497 * update a Region being computed for 29498 * {@link #gatherTransparentRegion(android.graphics.Region)} so 29499 * that any non-transparent parts of the Drawable are removed from the 29500 * given transparent region. 29501 * 29502 * @param dr The Drawable whose transparency is to be applied to the region. 29503 * @param region A Region holding the current transparency information, 29504 * where any parts of the region that are set are considered to be 29505 * transparent. On return, this region will be modified to have the 29506 * transparency information reduced by the corresponding parts of the 29507 * Drawable that are not transparent. 29508 * {@hide} 29509 */ 29510 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyDrawableToTransparentRegion(Drawable dr, Region region)29511 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 29512 if (DBG) { 29513 Log.i("View", "Getting transparent region for: " + this); 29514 } 29515 final Region r = dr.getTransparentRegion(); 29516 final Rect db = dr.getBounds(); 29517 final AttachInfo attachInfo = mAttachInfo; 29518 if (r != null && attachInfo != null) { 29519 final int w = getRight()-getLeft(); 29520 final int h = getBottom()-getTop(); 29521 if (db.left > 0) { 29522 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 29523 r.op(0, 0, db.left, h, Region.Op.UNION); 29524 } 29525 if (db.right < w) { 29526 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 29527 r.op(db.right, 0, w, h, Region.Op.UNION); 29528 } 29529 if (db.top > 0) { 29530 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 29531 r.op(0, 0, w, db.top, Region.Op.UNION); 29532 } 29533 if (db.bottom < h) { 29534 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 29535 r.op(0, db.bottom, w, h, Region.Op.UNION); 29536 } 29537 final int[] location = attachInfo.mTransparentLocation; 29538 getLocationInWindow(location); 29539 r.translate(location[0], location[1]); 29540 region.op(r, Region.Op.INTERSECT); 29541 } else { 29542 region.op(db, Region.Op.DIFFERENCE); 29543 } 29544 } 29545 checkForLongClick(long delay, float x, float y, int classification)29546 private void checkForLongClick(long delay, float x, float y, int classification) { 29547 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 29548 mHasPerformedLongPress = false; 29549 29550 if (mPendingCheckForLongPress == null) { 29551 mPendingCheckForLongPress = new CheckForLongPress(); 29552 } 29553 mPendingCheckForLongPress.setAnchor(x, y); 29554 mPendingCheckForLongPress.rememberWindowAttachCount(); 29555 mPendingCheckForLongPress.rememberPressedState(); 29556 mPendingCheckForLongPress.setClassification(classification); 29557 postDelayed(mPendingCheckForLongPress, delay); 29558 } 29559 } 29560 29561 /** 29562 * Inflate a view from an XML resource. This convenience method wraps the {@link 29563 * LayoutInflater} class, which provides a full range of options for view inflation. 29564 * 29565 * @param context The Context object for your activity or application. 29566 * @param resource The resource ID to inflate 29567 * @param root A view group that will be the parent. Used to properly inflate the 29568 * layout_* parameters. 29569 * @see LayoutInflater 29570 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)29571 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 29572 LayoutInflater factory = LayoutInflater.from(context); 29573 return factory.inflate(resource, root); 29574 } 29575 29576 /** 29577 * Scroll the view with standard behavior for scrolling beyond the normal 29578 * content boundaries. Views that call this method should override 29579 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 29580 * results of an over-scroll operation. 29581 * 29582 * Views can use this method to handle any touch or fling-based scrolling. 29583 * 29584 * @param deltaX Change in X in pixels 29585 * @param deltaY Change in Y in pixels 29586 * @param scrollX Current X scroll value in pixels before applying deltaX 29587 * @param scrollY Current Y scroll value in pixels before applying deltaY 29588 * @param scrollRangeX Maximum content scroll range along the X axis 29589 * @param scrollRangeY Maximum content scroll range along the Y axis 29590 * @param maxOverScrollX Number of pixels to overscroll by in either direction 29591 * along the X axis. 29592 * @param maxOverScrollY Number of pixels to overscroll by in either direction 29593 * along the Y axis. 29594 * @param isTouchEvent true if this scroll operation is the result of a touch event. 29595 * @return true if scrolling was clamped to an over-scroll boundary along either 29596 * axis, false otherwise. 29597 */ 29598 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)29599 protected boolean overScrollBy(int deltaX, int deltaY, 29600 int scrollX, int scrollY, 29601 int scrollRangeX, int scrollRangeY, 29602 int maxOverScrollX, int maxOverScrollY, 29603 boolean isTouchEvent) { 29604 final int overScrollMode = mOverScrollMode; 29605 final boolean canScrollHorizontal = 29606 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 29607 final boolean canScrollVertical = 29608 computeVerticalScrollRange() > computeVerticalScrollExtent(); 29609 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 29610 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 29611 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 29612 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 29613 29614 int newScrollX = scrollX + deltaX; 29615 if (!overScrollHorizontal) { 29616 maxOverScrollX = 0; 29617 } 29618 29619 int newScrollY = scrollY + deltaY; 29620 if (!overScrollVertical) { 29621 maxOverScrollY = 0; 29622 } 29623 29624 // Clamp values if at the limits and record 29625 final int left = -maxOverScrollX; 29626 final int right = maxOverScrollX + scrollRangeX; 29627 final int top = -maxOverScrollY; 29628 final int bottom = maxOverScrollY + scrollRangeY; 29629 29630 boolean clampedX = false; 29631 if (newScrollX > right) { 29632 newScrollX = right; 29633 clampedX = true; 29634 } else if (newScrollX < left) { 29635 newScrollX = left; 29636 clampedX = true; 29637 } 29638 29639 boolean clampedY = false; 29640 if (newScrollY > bottom) { 29641 newScrollY = bottom; 29642 clampedY = true; 29643 } else if (newScrollY < top) { 29644 newScrollY = top; 29645 clampedY = true; 29646 } 29647 29648 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 29649 29650 return clampedX || clampedY; 29651 } 29652 29653 /** 29654 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 29655 * respond to the results of an over-scroll operation. 29656 * 29657 * @param scrollX New X scroll value in pixels 29658 * @param scrollY New Y scroll value in pixels 29659 * @param clampedX True if scrollX was clamped to an over-scroll boundary 29660 * @param clampedY True if scrollY was clamped to an over-scroll boundary 29661 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)29662 protected void onOverScrolled(int scrollX, int scrollY, 29663 boolean clampedX, boolean clampedY) { 29664 // Intentionally empty. 29665 } 29666 29667 /** 29668 * Returns the over-scroll mode for this view. The result will be 29669 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 29670 * (allow over-scrolling only if the view content is larger than the container), 29671 * or {@link #OVER_SCROLL_NEVER}. 29672 * 29673 * @return This view's over-scroll mode. 29674 */ 29675 @InspectableProperty(enumMapping = { 29676 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 29677 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 29678 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 29679 }) getOverScrollMode()29680 public int getOverScrollMode() { 29681 return mOverScrollMode; 29682 } 29683 29684 /** 29685 * Set the over-scroll mode for this view. Valid over-scroll modes are 29686 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 29687 * (allow over-scrolling only if the view content is larger than the container), 29688 * or {@link #OVER_SCROLL_NEVER}. 29689 * 29690 * Setting the over-scroll mode of a view will have an effect only if the 29691 * view is capable of scrolling. 29692 * 29693 * @param overScrollMode The new over-scroll mode for this view. 29694 */ setOverScrollMode(int overScrollMode)29695 public void setOverScrollMode(int overScrollMode) { 29696 if (overScrollMode != OVER_SCROLL_ALWAYS && 29697 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 29698 overScrollMode != OVER_SCROLL_NEVER) { 29699 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 29700 } 29701 mOverScrollMode = overScrollMode; 29702 } 29703 29704 /** 29705 * Enable or disable nested scrolling for this view. 29706 * 29707 * <p>If this property is set to true the view will be permitted to initiate nested 29708 * scrolling operations with a compatible parent view in the current hierarchy. If this 29709 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 29710 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 29711 * the nested scroll.</p> 29712 * 29713 * @param enabled true to enable nested scrolling, false to disable 29714 * 29715 * @see #isNestedScrollingEnabled() 29716 */ setNestedScrollingEnabled(boolean enabled)29717 public void setNestedScrollingEnabled(boolean enabled) { 29718 if (enabled) { 29719 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 29720 } else { 29721 stopNestedScroll(); 29722 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 29723 } 29724 } 29725 29726 /** 29727 * Returns true if nested scrolling is enabled for this view. 29728 * 29729 * <p>If nested scrolling is enabled and this View class implementation supports it, 29730 * this view will act as a nested scrolling child view when applicable, forwarding data 29731 * about the scroll operation in progress to a compatible and cooperating nested scrolling 29732 * parent.</p> 29733 * 29734 * @return true if nested scrolling is enabled 29735 * 29736 * @see #setNestedScrollingEnabled(boolean) 29737 */ 29738 @InspectableProperty isNestedScrollingEnabled()29739 public boolean isNestedScrollingEnabled() { 29740 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 29741 PFLAG3_NESTED_SCROLLING_ENABLED; 29742 } 29743 29744 /** 29745 * Begin a nestable scroll operation along the given axes. 29746 * 29747 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 29748 * 29749 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 29750 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 29751 * In the case of touch scrolling the nested scroll will be terminated automatically in 29752 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 29753 * In the event of programmatic scrolling the caller must explicitly call 29754 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 29755 * 29756 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 29757 * If it returns false the caller may ignore the rest of this contract until the next scroll. 29758 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 29759 * 29760 * <p>At each incremental step of the scroll the caller should invoke 29761 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 29762 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 29763 * parent at least partially consumed the scroll and the caller should adjust the amount it 29764 * scrolls by.</p> 29765 * 29766 * <p>After applying the remainder of the scroll delta the caller should invoke 29767 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 29768 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 29769 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 29770 * </p> 29771 * 29772 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 29773 * {@link #SCROLL_AXIS_VERTICAL}. 29774 * @return true if a cooperative parent was found and nested scrolling has been enabled for 29775 * the current gesture. 29776 * 29777 * @see #stopNestedScroll() 29778 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 29779 * @see #dispatchNestedScroll(int, int, int, int, int[]) 29780 */ startNestedScroll(int axes)29781 public boolean startNestedScroll(int axes) { 29782 if (hasNestedScrollingParent()) { 29783 // Already in progress 29784 return true; 29785 } 29786 if (isNestedScrollingEnabled()) { 29787 ViewParent p = getParent(); 29788 View child = this; 29789 while (p != null) { 29790 try { 29791 if (p.onStartNestedScroll(child, this, axes)) { 29792 mNestedScrollingParent = p; 29793 p.onNestedScrollAccepted(child, this, axes); 29794 return true; 29795 } 29796 } catch (AbstractMethodError e) { 29797 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 29798 "method onStartNestedScroll", e); 29799 // Allow the search upward to continue 29800 } 29801 if (p instanceof View) { 29802 child = (View) p; 29803 } 29804 p = p.getParent(); 29805 } 29806 } 29807 return false; 29808 } 29809 29810 /** 29811 * Stop a nested scroll in progress. 29812 * 29813 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 29814 * 29815 * @see #startNestedScroll(int) 29816 */ stopNestedScroll()29817 public void stopNestedScroll() { 29818 if (mNestedScrollingParent != null) { 29819 mNestedScrollingParent.onStopNestedScroll(this); 29820 mNestedScrollingParent = null; 29821 } 29822 } 29823 29824 /** 29825 * Returns true if this view has a nested scrolling parent. 29826 * 29827 * <p>The presence of a nested scrolling parent indicates that this view has initiated 29828 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 29829 * 29830 * @return whether this view has a nested scrolling parent 29831 */ hasNestedScrollingParent()29832 public boolean hasNestedScrollingParent() { 29833 return mNestedScrollingParent != null; 29834 } 29835 29836 /** 29837 * Dispatch one step of a nested scroll in progress. 29838 * 29839 * <p>Implementations of views that support nested scrolling should call this to report 29840 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 29841 * is not currently in progress or nested scrolling is not 29842 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 29843 * 29844 * <p>Compatible View implementations should also call 29845 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 29846 * consuming a component of the scroll event themselves.</p> 29847 * 29848 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 29849 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 29850 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 29851 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 29852 * @param offsetInWindow Optional. If not null, on return this will contain the offset 29853 * in local view coordinates of this view from before this operation 29854 * to after it completes. View implementations may use this to adjust 29855 * expected input coordinate tracking. 29856 * @return true if the event was dispatched, false if it could not be dispatched. 29857 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 29858 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)29859 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 29860 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 29861 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 29862 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 29863 int startX = 0; 29864 int startY = 0; 29865 if (offsetInWindow != null) { 29866 getLocationInWindow(offsetInWindow); 29867 startX = offsetInWindow[0]; 29868 startY = offsetInWindow[1]; 29869 } 29870 29871 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 29872 dxUnconsumed, dyUnconsumed); 29873 29874 if (offsetInWindow != null) { 29875 getLocationInWindow(offsetInWindow); 29876 offsetInWindow[0] -= startX; 29877 offsetInWindow[1] -= startY; 29878 } 29879 return true; 29880 } else if (offsetInWindow != null) { 29881 // No motion, no dispatch. Keep offsetInWindow up to date. 29882 offsetInWindow[0] = 0; 29883 offsetInWindow[1] = 0; 29884 } 29885 } 29886 return false; 29887 } 29888 29889 /** 29890 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 29891 * 29892 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 29893 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 29894 * scrolling operation to consume some or all of the scroll operation before the child view 29895 * consumes it.</p> 29896 * 29897 * @param dx Horizontal scroll distance in pixels 29898 * @param dy Vertical scroll distance in pixels 29899 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 29900 * and consumed[1] the consumed dy. 29901 * @param offsetInWindow Optional. If not null, on return this will contain the offset 29902 * in local view coordinates of this view from before this operation 29903 * to after it completes. View implementations may use this to adjust 29904 * expected input coordinate tracking. 29905 * @return true if the parent consumed some or all of the scroll delta 29906 * @see #dispatchNestedScroll(int, int, int, int, int[]) 29907 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)29908 public boolean dispatchNestedPreScroll(int dx, int dy, 29909 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 29910 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 29911 if (dx != 0 || dy != 0) { 29912 int startX = 0; 29913 int startY = 0; 29914 if (offsetInWindow != null) { 29915 getLocationInWindow(offsetInWindow); 29916 startX = offsetInWindow[0]; 29917 startY = offsetInWindow[1]; 29918 } 29919 29920 if (consumed == null) { 29921 if (mTempNestedScrollConsumed == null) { 29922 mTempNestedScrollConsumed = new int[2]; 29923 } 29924 consumed = mTempNestedScrollConsumed; 29925 } 29926 consumed[0] = 0; 29927 consumed[1] = 0; 29928 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 29929 29930 if (offsetInWindow != null) { 29931 getLocationInWindow(offsetInWindow); 29932 offsetInWindow[0] -= startX; 29933 offsetInWindow[1] -= startY; 29934 } 29935 return consumed[0] != 0 || consumed[1] != 0; 29936 } else if (offsetInWindow != null) { 29937 offsetInWindow[0] = 0; 29938 offsetInWindow[1] = 0; 29939 } 29940 } 29941 return false; 29942 } 29943 29944 /** 29945 * Dispatch a fling to a nested scrolling parent. 29946 * 29947 * <p>This method should be used to indicate that a nested scrolling child has detected 29948 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 29949 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 29950 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 29951 * along a scrollable axis.</p> 29952 * 29953 * <p>If a nested scrolling child view would normally fling but it is at the edge of 29954 * its own content, it can use this method to delegate the fling to its nested scrolling 29955 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 29956 * 29957 * @param velocityX Horizontal fling velocity in pixels per second 29958 * @param velocityY Vertical fling velocity in pixels per second 29959 * @param consumed true if the child consumed the fling, false otherwise 29960 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 29961 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)29962 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 29963 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 29964 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 29965 } 29966 return false; 29967 } 29968 29969 /** 29970 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 29971 * 29972 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 29973 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 29974 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 29975 * before the child view consumes it. If this method returns <code>true</code>, a nested 29976 * parent view consumed the fling and this view should not scroll as a result.</p> 29977 * 29978 * <p>For a better user experience, only one view in a nested scrolling chain should consume 29979 * the fling at a time. If a parent view consumed the fling this method will return false. 29980 * Custom view implementations should account for this in two ways:</p> 29981 * 29982 * <ul> 29983 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 29984 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 29985 * position regardless.</li> 29986 * <li>If a nested parent does consume the fling, this view should not scroll at all, 29987 * even to settle back to a valid idle position.</li> 29988 * </ul> 29989 * 29990 * <p>Views should also not offer fling velocities to nested parent views along an axis 29991 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 29992 * should not offer a horizontal fling velocity to its parents since scrolling along that 29993 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 29994 * 29995 * @param velocityX Horizontal fling velocity in pixels per second 29996 * @param velocityY Vertical fling velocity in pixels per second 29997 * @return true if a nested scrolling parent consumed the fling 29998 */ dispatchNestedPreFling(float velocityX, float velocityY)29999 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 30000 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 30001 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 30002 } 30003 return false; 30004 } 30005 30006 /** 30007 * Gets a scale factor that determines the distance the view should scroll 30008 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 30009 * @return The vertical scroll scale factor. 30010 * @hide 30011 */ 30012 @UnsupportedAppUsage getVerticalScrollFactor()30013 protected float getVerticalScrollFactor() { 30014 if (mVerticalScrollFactor == 0) { 30015 TypedValue outValue = new TypedValue(); 30016 if (!mContext.getTheme().resolveAttribute( 30017 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 30018 throw new IllegalStateException( 30019 "Expected theme to define listPreferredItemHeight."); 30020 } 30021 mVerticalScrollFactor = outValue.getDimension( 30022 mContext.getResources().getDisplayMetrics()); 30023 } 30024 return mVerticalScrollFactor; 30025 } 30026 30027 /** 30028 * Gets a scale factor that determines the distance the view should scroll 30029 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 30030 * @return The horizontal scroll scale factor. 30031 * @hide 30032 */ 30033 @UnsupportedAppUsage getHorizontalScrollFactor()30034 protected float getHorizontalScrollFactor() { 30035 // TODO: Should use something else. 30036 return getVerticalScrollFactor(); 30037 } 30038 30039 /** 30040 * Return the value specifying the text direction or policy that was set with 30041 * {@link #setTextDirection(int)}. 30042 * 30043 * @return the defined text direction. It can be one of: 30044 * 30045 * {@link #TEXT_DIRECTION_INHERIT}, 30046 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 30047 * {@link #TEXT_DIRECTION_ANY_RTL}, 30048 * {@link #TEXT_DIRECTION_LTR}, 30049 * {@link #TEXT_DIRECTION_RTL}, 30050 * {@link #TEXT_DIRECTION_LOCALE}, 30051 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 30052 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 30053 * 30054 * @attr ref android.R.styleable#View_textDirection 30055 * 30056 * @hide 30057 */ 30058 @ViewDebug.ExportedProperty(category = "text", mapping = { 30059 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 30060 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 30061 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 30062 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 30063 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 30064 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 30065 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 30066 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 30067 }) 30068 @InspectableProperty(hasAttributeId = false, enumMapping = { 30069 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 30070 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 30071 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 30072 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 30073 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 30074 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 30075 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 30076 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 30077 }) 30078 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextDirection()30079 public int getRawTextDirection() { 30080 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 30081 } 30082 30083 /** 30084 * Set the text direction. 30085 * 30086 * @param textDirection the direction to set. Should be one of: 30087 * 30088 * {@link #TEXT_DIRECTION_INHERIT}, 30089 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 30090 * {@link #TEXT_DIRECTION_ANY_RTL}, 30091 * {@link #TEXT_DIRECTION_LTR}, 30092 * {@link #TEXT_DIRECTION_RTL}, 30093 * {@link #TEXT_DIRECTION_LOCALE} 30094 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 30095 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 30096 * 30097 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 30098 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 30099 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 30100 * 30101 * @attr ref android.R.styleable#View_textDirection 30102 */ setTextDirection(int textDirection)30103 public void setTextDirection(int textDirection) { 30104 if (getRawTextDirection() != textDirection) { 30105 // Reset the current text direction and the resolved one 30106 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 30107 resetResolvedTextDirection(); 30108 // Set the new text direction 30109 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 30110 // Do resolution 30111 resolveTextDirection(); 30112 // Notify change 30113 onRtlPropertiesChanged(getLayoutDirection()); 30114 // Refresh 30115 requestLayout(); 30116 invalidate(true); 30117 } 30118 } 30119 30120 /** 30121 * Return the resolved text direction. 30122 * 30123 * @return the resolved text direction. Returns one of: 30124 * 30125 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 30126 * {@link #TEXT_DIRECTION_ANY_RTL}, 30127 * {@link #TEXT_DIRECTION_LTR}, 30128 * {@link #TEXT_DIRECTION_RTL}, 30129 * {@link #TEXT_DIRECTION_LOCALE}, 30130 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 30131 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 30132 * 30133 * @attr ref android.R.styleable#View_textDirection 30134 */ 30135 @ViewDebug.ExportedProperty(category = "text", mapping = { 30136 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 30137 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 30138 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 30139 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 30140 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 30141 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 30142 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 30143 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 30144 }) 30145 @InspectableProperty(hasAttributeId = false, enumMapping = { 30146 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 30147 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 30148 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 30149 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 30150 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 30151 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 30152 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 30153 }) getTextDirection()30154 public int getTextDirection() { 30155 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 30156 } 30157 30158 /** 30159 * Resolve the text direction. 30160 * 30161 * @return true if resolution has been done, false otherwise. 30162 * 30163 * @hide 30164 */ resolveTextDirection()30165 public boolean resolveTextDirection() { 30166 // Reset any previous text direction resolution 30167 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 30168 30169 if (hasRtlSupport()) { 30170 // Set resolved text direction flag depending on text direction flag 30171 final int textDirection = getRawTextDirection(); 30172 switch(textDirection) { 30173 case TEXT_DIRECTION_INHERIT: 30174 if (!canResolveTextDirection()) { 30175 // We cannot do the resolution if there is no parent, so use the default one 30176 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30177 // Resolution will need to happen again later 30178 return false; 30179 } 30180 30181 // Parent has not yet resolved, so we still return the default 30182 try { 30183 if (!mParent.isTextDirectionResolved()) { 30184 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30185 // Resolution will need to happen again later 30186 return false; 30187 } 30188 } catch (AbstractMethodError e) { 30189 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30190 " does not fully implement ViewParent", e); 30191 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 30192 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30193 return true; 30194 } 30195 30196 // Set current resolved direction to the same value as the parent's one 30197 int parentResolvedDirection; 30198 try { 30199 parentResolvedDirection = mParent.getTextDirection(); 30200 } catch (AbstractMethodError e) { 30201 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30202 " does not fully implement ViewParent", e); 30203 parentResolvedDirection = TEXT_DIRECTION_LTR; 30204 } 30205 switch (parentResolvedDirection) { 30206 case TEXT_DIRECTION_FIRST_STRONG: 30207 case TEXT_DIRECTION_ANY_RTL: 30208 case TEXT_DIRECTION_LTR: 30209 case TEXT_DIRECTION_RTL: 30210 case TEXT_DIRECTION_LOCALE: 30211 case TEXT_DIRECTION_FIRST_STRONG_LTR: 30212 case TEXT_DIRECTION_FIRST_STRONG_RTL: 30213 mPrivateFlags2 |= 30214 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 30215 break; 30216 default: 30217 // Default resolved direction is "first strong" heuristic 30218 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30219 } 30220 break; 30221 case TEXT_DIRECTION_FIRST_STRONG: 30222 case TEXT_DIRECTION_ANY_RTL: 30223 case TEXT_DIRECTION_LTR: 30224 case TEXT_DIRECTION_RTL: 30225 case TEXT_DIRECTION_LOCALE: 30226 case TEXT_DIRECTION_FIRST_STRONG_LTR: 30227 case TEXT_DIRECTION_FIRST_STRONG_RTL: 30228 // Resolved direction is the same as text direction 30229 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 30230 break; 30231 default: 30232 // Default resolved direction is "first strong" heuristic 30233 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30234 } 30235 } else { 30236 // Default resolved direction is "first strong" heuristic 30237 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30238 } 30239 30240 // Set to resolved 30241 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 30242 return true; 30243 } 30244 30245 /** 30246 * Check if text direction resolution can be done. 30247 * 30248 * @return true if text direction resolution can be done otherwise return false. 30249 */ canResolveTextDirection()30250 public boolean canResolveTextDirection() { 30251 switch (getRawTextDirection()) { 30252 case TEXT_DIRECTION_INHERIT: 30253 if (mParent != null) { 30254 try { 30255 return mParent.canResolveTextDirection(); 30256 } catch (AbstractMethodError e) { 30257 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30258 " does not fully implement ViewParent", e); 30259 } 30260 } 30261 return false; 30262 30263 default: 30264 return true; 30265 } 30266 } 30267 30268 /** 30269 * Reset resolved text direction. Text direction will be resolved during a call to 30270 * {@link #onMeasure(int, int)}. 30271 * 30272 * @hide 30273 */ 30274 @TestApi resetResolvedTextDirection()30275 public void resetResolvedTextDirection() { 30276 // Reset any previous text direction resolution 30277 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 30278 // Set to default value 30279 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30280 } 30281 30282 /** 30283 * @return true if text direction is inherited. 30284 * 30285 * @hide 30286 */ isTextDirectionInherited()30287 public boolean isTextDirectionInherited() { 30288 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 30289 } 30290 30291 /** 30292 * @return true if text direction is resolved. 30293 */ isTextDirectionResolved()30294 public boolean isTextDirectionResolved() { 30295 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 30296 } 30297 30298 /** 30299 * Return the value specifying the text alignment or policy that was set with 30300 * {@link #setTextAlignment(int)}. 30301 * 30302 * @return the defined text alignment. It can be one of: 30303 * 30304 * {@link #TEXT_ALIGNMENT_INHERIT}, 30305 * {@link #TEXT_ALIGNMENT_GRAVITY}, 30306 * {@link #TEXT_ALIGNMENT_CENTER}, 30307 * {@link #TEXT_ALIGNMENT_TEXT_START}, 30308 * {@link #TEXT_ALIGNMENT_TEXT_END}, 30309 * {@link #TEXT_ALIGNMENT_VIEW_START}, 30310 * {@link #TEXT_ALIGNMENT_VIEW_END} 30311 * 30312 * @attr ref android.R.styleable#View_textAlignment 30313 * 30314 * @hide 30315 */ 30316 @ViewDebug.ExportedProperty(category = "text", mapping = { 30317 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 30318 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 30319 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 30320 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 30321 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 30322 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 30323 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 30324 }) 30325 @InspectableProperty(hasAttributeId = false, enumMapping = { 30326 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 30327 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 30328 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 30329 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 30330 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 30331 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 30332 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 30333 }) 30334 @TextAlignment 30335 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextAlignment()30336 public int getRawTextAlignment() { 30337 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 30338 } 30339 30340 /** 30341 * Set the text alignment. 30342 * 30343 * @param textAlignment The text alignment to set. Should be one of 30344 * 30345 * {@link #TEXT_ALIGNMENT_INHERIT}, 30346 * {@link #TEXT_ALIGNMENT_GRAVITY}, 30347 * {@link #TEXT_ALIGNMENT_CENTER}, 30348 * {@link #TEXT_ALIGNMENT_TEXT_START}, 30349 * {@link #TEXT_ALIGNMENT_TEXT_END}, 30350 * {@link #TEXT_ALIGNMENT_VIEW_START}, 30351 * {@link #TEXT_ALIGNMENT_VIEW_END} 30352 * 30353 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 30354 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 30355 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 30356 * 30357 * @attr ref android.R.styleable#View_textAlignment 30358 */ setTextAlignment(@extAlignment int textAlignment)30359 public void setTextAlignment(@TextAlignment int textAlignment) { 30360 if (textAlignment != getRawTextAlignment()) { 30361 // Reset the current and resolved text alignment 30362 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 30363 resetResolvedTextAlignment(); 30364 // Set the new text alignment 30365 mPrivateFlags2 |= 30366 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 30367 // Do resolution 30368 resolveTextAlignment(); 30369 // Notify change 30370 onRtlPropertiesChanged(getLayoutDirection()); 30371 // Refresh 30372 requestLayout(); 30373 invalidate(true); 30374 } 30375 } 30376 30377 /** 30378 * Return the resolved text alignment. 30379 * 30380 * @return the resolved text alignment. Returns one of: 30381 * 30382 * {@link #TEXT_ALIGNMENT_GRAVITY}, 30383 * {@link #TEXT_ALIGNMENT_CENTER}, 30384 * {@link #TEXT_ALIGNMENT_TEXT_START}, 30385 * {@link #TEXT_ALIGNMENT_TEXT_END}, 30386 * {@link #TEXT_ALIGNMENT_VIEW_START}, 30387 * {@link #TEXT_ALIGNMENT_VIEW_END} 30388 * 30389 * @attr ref android.R.styleable#View_textAlignment 30390 */ 30391 @ViewDebug.ExportedProperty(category = "text", mapping = { 30392 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 30393 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 30394 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 30395 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 30396 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 30397 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 30398 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 30399 }) 30400 @InspectableProperty(enumMapping = { 30401 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 30402 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 30403 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 30404 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 30405 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 30406 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 30407 }) 30408 @TextAlignment getTextAlignment()30409 public int getTextAlignment() { 30410 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 30411 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 30412 } 30413 30414 /** 30415 * Resolve the text alignment. 30416 * 30417 * @return true if resolution has been done, false otherwise. 30418 * 30419 * @hide 30420 */ resolveTextAlignment()30421 public boolean resolveTextAlignment() { 30422 // Reset any previous text alignment resolution 30423 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 30424 30425 if (hasRtlSupport()) { 30426 // Set resolved text alignment flag depending on text alignment flag 30427 final int textAlignment = getRawTextAlignment(); 30428 switch (textAlignment) { 30429 case TEXT_ALIGNMENT_INHERIT: 30430 // Check if we can resolve the text alignment 30431 if (!canResolveTextAlignment()) { 30432 // We cannot do the resolution if there is no parent so use the default 30433 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30434 // Resolution will need to happen again later 30435 return false; 30436 } 30437 30438 // Parent has not yet resolved, so we still return the default 30439 try { 30440 if (!mParent.isTextAlignmentResolved()) { 30441 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30442 // Resolution will need to happen again later 30443 return false; 30444 } 30445 } catch (AbstractMethodError e) { 30446 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30447 " does not fully implement ViewParent", e); 30448 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 30449 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30450 return true; 30451 } 30452 30453 int parentResolvedTextAlignment; 30454 try { 30455 parentResolvedTextAlignment = mParent.getTextAlignment(); 30456 } catch (AbstractMethodError e) { 30457 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30458 " does not fully implement ViewParent", e); 30459 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 30460 } 30461 switch (parentResolvedTextAlignment) { 30462 case TEXT_ALIGNMENT_GRAVITY: 30463 case TEXT_ALIGNMENT_TEXT_START: 30464 case TEXT_ALIGNMENT_TEXT_END: 30465 case TEXT_ALIGNMENT_CENTER: 30466 case TEXT_ALIGNMENT_VIEW_START: 30467 case TEXT_ALIGNMENT_VIEW_END: 30468 // Resolved text alignment is the same as the parent resolved 30469 // text alignment 30470 mPrivateFlags2 |= 30471 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 30472 break; 30473 default: 30474 // Use default resolved text alignment 30475 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30476 } 30477 break; 30478 case TEXT_ALIGNMENT_GRAVITY: 30479 case TEXT_ALIGNMENT_TEXT_START: 30480 case TEXT_ALIGNMENT_TEXT_END: 30481 case TEXT_ALIGNMENT_CENTER: 30482 case TEXT_ALIGNMENT_VIEW_START: 30483 case TEXT_ALIGNMENT_VIEW_END: 30484 // Resolved text alignment is the same as text alignment 30485 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 30486 break; 30487 default: 30488 // Use default resolved text alignment 30489 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30490 } 30491 } else { 30492 // Use default resolved text alignment 30493 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30494 } 30495 30496 // Set the resolved 30497 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 30498 return true; 30499 } 30500 30501 /** 30502 * Check if text alignment resolution can be done. 30503 * 30504 * @return true if text alignment resolution can be done otherwise return false. 30505 */ canResolveTextAlignment()30506 public boolean canResolveTextAlignment() { 30507 switch (getRawTextAlignment()) { 30508 case TEXT_DIRECTION_INHERIT: 30509 if (mParent != null) { 30510 try { 30511 return mParent.canResolveTextAlignment(); 30512 } catch (AbstractMethodError e) { 30513 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30514 " does not fully implement ViewParent", e); 30515 } 30516 } 30517 return false; 30518 30519 default: 30520 return true; 30521 } 30522 } 30523 30524 /** 30525 * Reset resolved text alignment. Text alignment will be resolved during a call to 30526 * {@link #onMeasure(int, int)}. 30527 * 30528 * @hide 30529 */ 30530 @TestApi resetResolvedTextAlignment()30531 public void resetResolvedTextAlignment() { 30532 // Reset any previous text alignment resolution 30533 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 30534 // Set to default 30535 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30536 } 30537 30538 /** 30539 * @return true if text alignment is inherited. 30540 * 30541 * @hide 30542 */ isTextAlignmentInherited()30543 public boolean isTextAlignmentInherited() { 30544 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 30545 } 30546 30547 /** 30548 * @return true if text alignment is resolved. 30549 */ isTextAlignmentResolved()30550 public boolean isTextAlignmentResolved() { 30551 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 30552 } 30553 30554 /** 30555 * Generate a value suitable for use in {@link #setId(int)}. 30556 * This value will not collide with ID values generated at build time by aapt for R.id. 30557 * 30558 * @return a generated ID value 30559 */ generateViewId()30560 public static int generateViewId() { 30561 for (;;) { 30562 final int result = sNextGeneratedId.get(); 30563 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 30564 int newValue = result + 1; 30565 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 30566 if (sNextGeneratedId.compareAndSet(result, newValue)) { 30567 return result; 30568 } 30569 } 30570 } 30571 isViewIdGenerated(int id)30572 private static boolean isViewIdGenerated(int id) { 30573 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 30574 } 30575 30576 /** 30577 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 30578 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 30579 * a normal View or a ViewGroup with 30580 * {@link android.view.ViewGroup#isTransitionGroup()} true. 30581 * @hide 30582 */ captureTransitioningViews(List<View> transitioningViews)30583 public void captureTransitioningViews(List<View> transitioningViews) { 30584 if (getVisibility() == View.VISIBLE) { 30585 transitioningViews.add(this); 30586 } 30587 } 30588 30589 /** 30590 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 30591 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 30592 * @hide 30593 */ findNamedViews(Map<String, View> namedElements)30594 public void findNamedViews(Map<String, View> namedElements) { 30595 if (getVisibility() == VISIBLE || mGhostView != null) { 30596 String transitionName = getTransitionName(); 30597 if (transitionName != null) { 30598 namedElements.put(transitionName, this); 30599 } 30600 } 30601 } 30602 30603 /** 30604 * Resolve the pointer icon that should be used for specified pointer in the motion event. 30605 * 30606 * The default implementation will resolve the pointer icon to one set using 30607 * {@link #setPointerIcon(PointerIcon)} for mouse devices. Subclasses may override this to 30608 * customize the icon for the given pointer. 30609 * 30610 * For example, the pointer icon for a stylus pointer can be resolved in the following way: 30611 * <code><pre> 30612 * @Override 30613 * public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 30614 * final int toolType = event.getToolType(pointerIndex); 30615 * if (!event.isFromSource(InputDevice.SOURCE_MOUSE) 30616 * && event.isFromSource(InputDevice.SOURCE_STYLUS) 30617 * && (toolType == MotionEvent.TOOL_TYPE_STYLUS 30618 * || toolType == MotionEvent.TOOL_TYPE_ERASER)) { 30619 * // Show this pointer icon only if this pointer is a stylus. 30620 * return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_WAIT); 30621 * } 30622 * // Use the default logic for determining the pointer icon for other non-stylus pointers, 30623 * // like for the mouse cursor. 30624 * return super.onResolvePointerIcon(event, pointerIndex); 30625 * } 30626 * </pre></code> 30627 * 30628 * @param event The {@link MotionEvent} that requires a pointer icon to be resolved for one of 30629 * pointers. 30630 * @param pointerIndex The index of the pointer in {@code event} for which to retrieve the 30631 * {@link PointerIcon}. This will be between 0 and {@link MotionEvent#getPointerCount()}. 30632 * @return the pointer icon to use for specified pointer, or {@code null} if a pointer icon 30633 * is not specified and the default icon should be used. 30634 * @see PointerIcon 30635 * @see InputManager#isStylusPointerIconEnabled() 30636 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)30637 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 30638 final float x = event.getX(pointerIndex); 30639 final float y = event.getY(pointerIndex); 30640 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 30641 // Use the default pointer icon. 30642 return null; 30643 } 30644 30645 // Note: A drawing tablet will have both SOURCE_MOUSE and SOURCE_STYLUS, but it would use 30646 // TOOL_TYPE_STYLUS. For now, treat drawing tablets the same way as a mouse or touchpad. 30647 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { 30648 return mMousePointerIcon; 30649 } 30650 30651 return null; 30652 } 30653 30654 /** 30655 * Set the pointer icon to be used for a mouse pointer in the current view. 30656 * 30657 * Passing {@code null} will restore the pointer icon to its default value. 30658 * Note that setting the pointer icon using this method will only set it for events coming from 30659 * a mouse device (i.e. with source {@link InputDevice#SOURCE_MOUSE}). To resolve 30660 * the pointer icon for other device types like styluses, override 30661 * {@link #onResolvePointerIcon(MotionEvent, int)}. 30662 * 30663 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 30664 * @see #onResolvePointerIcon(MotionEvent, int) 30665 * @see PointerIcon 30666 */ setPointerIcon(PointerIcon pointerIcon)30667 public void setPointerIcon(PointerIcon pointerIcon) { 30668 mMousePointerIcon = pointerIcon; 30669 final ViewRootImpl viewRootImpl = getViewRootImpl(); 30670 if (viewRootImpl == null) { 30671 return; 30672 } 30673 viewRootImpl.refreshPointerIcon(); 30674 } 30675 30676 /** 30677 * Gets the mouse pointer icon for the current view. 30678 * 30679 * @see #setPointerIcon(PointerIcon) 30680 */ 30681 @InspectableProperty getPointerIcon()30682 public PointerIcon getPointerIcon() { 30683 return mMousePointerIcon; 30684 } 30685 30686 /** 30687 * Checks pointer capture status. 30688 * 30689 * @return true if the view has pointer capture. 30690 * @see #requestPointerCapture() 30691 * @see #hasPointerCapture() 30692 */ hasPointerCapture()30693 public boolean hasPointerCapture() { 30694 final ViewRootImpl viewRootImpl = getViewRootImpl(); 30695 if (viewRootImpl == null) { 30696 return false; 30697 } 30698 return viewRootImpl.hasPointerCapture(); 30699 } 30700 30701 /** 30702 * Requests pointer capture mode. 30703 * <p> 30704 * When the window has pointer capture, the mouse pointer icon will disappear and will not 30705 * change its position. Enabling pointer capture will change the behavior of input devices in 30706 * the following ways: 30707 * <ul> 30708 * <li>Events from a mouse will be delivered with the source 30709 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be 30710 * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li> 30711 * 30712 * <li>Events from a touchpad or trackpad will be delivered with the source 30713 * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers 30714 * on the touchpad will be available through {@link MotionEvent#getX(int)} and 30715 * {@link MotionEvent#getY(int)}, and their relative movements are stored in 30716 * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li> 30717 * 30718 * <li>Events from other types of devices, such as touchscreens, will not be affected.</li> 30719 * </ul> 30720 * <p> 30721 * When pointer capture changes, connected mouse and trackpad devices may be reconfigured, 30722 * and their properties (such as their sources or motion ranges) may change. Use an 30723 * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device 30724 * changes (which may happen after enabling or disabling pointer capture), and use 30725 * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}. 30726 * <p> 30727 * Events captured through pointer capture will be dispatched to 30728 * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an 30729 * {@link OnCapturedPointerListener} is set, and otherwise to 30730 * {@link #onCapturedPointerEvent(MotionEvent)}. 30731 * <p> 30732 * If the window already has pointer capture, this call does nothing. 30733 * <p> 30734 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 30735 * automatically when the window loses focus. 30736 * 30737 * @see #releasePointerCapture() 30738 * @see #hasPointerCapture() 30739 * @see #onPointerCaptureChange(boolean) 30740 */ requestPointerCapture()30741 public void requestPointerCapture() { 30742 final ViewRootImpl viewRootImpl = getViewRootImpl(); 30743 if (viewRootImpl != null) { 30744 viewRootImpl.requestPointerCapture(true); 30745 } 30746 } 30747 30748 30749 /** 30750 * Releases the pointer capture. 30751 * <p> 30752 * If the window does not have pointer capture, this call will do nothing. 30753 * @see #requestPointerCapture() 30754 * @see #hasPointerCapture() 30755 * @see #onPointerCaptureChange(boolean) 30756 */ releasePointerCapture()30757 public void releasePointerCapture() { 30758 final ViewRootImpl viewRootImpl = getViewRootImpl(); 30759 if (viewRootImpl != null) { 30760 viewRootImpl.requestPointerCapture(false); 30761 } 30762 } 30763 30764 /** 30765 * Called when the window has just acquired or lost pointer capture. 30766 * 30767 * @param hasCapture True if the view now has pointerCapture, false otherwise. 30768 */ 30769 @CallSuper onPointerCaptureChange(boolean hasCapture)30770 public void onPointerCaptureChange(boolean hasCapture) { 30771 } 30772 30773 /** 30774 * @see #onPointerCaptureChange 30775 */ dispatchPointerCaptureChanged(boolean hasCapture)30776 public void dispatchPointerCaptureChanged(boolean hasCapture) { 30777 onPointerCaptureChange(hasCapture); 30778 } 30779 30780 /** 30781 * Implement this method to handle captured pointer events 30782 * 30783 * @param event The captured pointer event. 30784 * @return True if the event was handled, false otherwise. 30785 * @see #requestPointerCapture() 30786 */ onCapturedPointerEvent(MotionEvent event)30787 public boolean onCapturedPointerEvent(MotionEvent event) { 30788 return false; 30789 } 30790 30791 /** 30792 * Interface definition for a callback to be invoked when a captured pointer event 30793 * is being dispatched this view. The callback will be invoked before the event is 30794 * given to the view. 30795 */ 30796 public interface OnCapturedPointerListener { 30797 /** 30798 * Called when a captured pointer event is dispatched to a view. 30799 * @param view The view this event has been dispatched to. 30800 * @param event The captured event. 30801 * @return True if the listener has consumed the event, false otherwise. 30802 */ 30803 boolean onCapturedPointer(View view, MotionEvent event); 30804 } 30805 30806 /** 30807 * Set a listener to receive callbacks when the pointer capture state of a view changes. 30808 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 30809 */ setOnCapturedPointerListener(OnCapturedPointerListener l)30810 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 30811 getListenerInfo().mOnCapturedPointerListener = l; 30812 } 30813 30814 // Properties 30815 // 30816 /** 30817 * A Property wrapper around the <code>alpha</code> functionality handled by the 30818 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 30819 */ 30820 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 30821 @Override 30822 public void setValue(View object, float value) { 30823 object.setAlpha(value); 30824 } 30825 30826 @Override 30827 public Float get(View object) { 30828 return object.getAlpha(); 30829 } 30830 }; 30831 30832 /** 30833 * A Property wrapper around the <code>translationX</code> functionality handled by the 30834 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 30835 */ 30836 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 30837 @Override 30838 public void setValue(View object, float value) { 30839 object.setTranslationX(value); 30840 } 30841 30842 @Override 30843 public Float get(View object) { 30844 return object.getTranslationX(); 30845 } 30846 }; 30847 30848 /** 30849 * A Property wrapper around the <code>translationY</code> functionality handled by the 30850 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 30851 */ 30852 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 30853 @Override 30854 public void setValue(View object, float value) { 30855 object.setTranslationY(value); 30856 } 30857 30858 @Override 30859 public Float get(View object) { 30860 return object.getTranslationY(); 30861 } 30862 }; 30863 30864 /** 30865 * A Property wrapper around the <code>translationZ</code> functionality handled by the 30866 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 30867 */ 30868 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 30869 @Override 30870 public void setValue(View object, float value) { 30871 object.setTranslationZ(value); 30872 } 30873 30874 @Override 30875 public Float get(View object) { 30876 return object.getTranslationZ(); 30877 } 30878 }; 30879 30880 /** 30881 * A Property wrapper around the <code>x</code> functionality handled by the 30882 * {@link View#setX(float)} and {@link View#getX()} methods. 30883 */ 30884 public static final Property<View, Float> X = new FloatProperty<View>("x") { 30885 @Override 30886 public void setValue(View object, float value) { 30887 object.setX(value); 30888 } 30889 30890 @Override 30891 public Float get(View object) { 30892 return object.getX(); 30893 } 30894 }; 30895 30896 /** 30897 * A Property wrapper around the <code>y</code> functionality handled by the 30898 * {@link View#setY(float)} and {@link View#getY()} methods. 30899 */ 30900 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 30901 @Override 30902 public void setValue(View object, float value) { 30903 object.setY(value); 30904 } 30905 30906 @Override 30907 public Float get(View object) { 30908 return object.getY(); 30909 } 30910 }; 30911 30912 /** 30913 * A Property wrapper around the <code>z</code> functionality handled by the 30914 * {@link View#setZ(float)} and {@link View#getZ()} methods. 30915 */ 30916 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 30917 @Override 30918 public void setValue(View object, float value) { 30919 object.setZ(value); 30920 } 30921 30922 @Override 30923 public Float get(View object) { 30924 return object.getZ(); 30925 } 30926 }; 30927 30928 /** 30929 * A Property wrapper around the <code>rotation</code> functionality handled by the 30930 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 30931 */ 30932 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 30933 @Override 30934 public void setValue(View object, float value) { 30935 object.setRotation(value); 30936 } 30937 30938 @Override 30939 public Float get(View object) { 30940 return object.getRotation(); 30941 } 30942 }; 30943 30944 /** 30945 * A Property wrapper around the <code>rotationX</code> functionality handled by the 30946 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 30947 */ 30948 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 30949 @Override 30950 public void setValue(View object, float value) { 30951 object.setRotationX(value); 30952 } 30953 30954 @Override 30955 public Float get(View object) { 30956 return object.getRotationX(); 30957 } 30958 }; 30959 30960 /** 30961 * A Property wrapper around the <code>rotationY</code> functionality handled by the 30962 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 30963 */ 30964 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 30965 @Override 30966 public void setValue(View object, float value) { 30967 object.setRotationY(value); 30968 } 30969 30970 @Override 30971 public Float get(View object) { 30972 return object.getRotationY(); 30973 } 30974 }; 30975 30976 /** 30977 * A Property wrapper around the <code>scaleX</code> functionality handled by the 30978 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 30979 */ 30980 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 30981 @Override 30982 public void setValue(View object, float value) { 30983 object.setScaleX(value); 30984 } 30985 30986 @Override 30987 public Float get(View object) { 30988 return object.getScaleX(); 30989 } 30990 }; 30991 30992 /** 30993 * A Property wrapper around the <code>scaleY</code> functionality handled by the 30994 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 30995 */ 30996 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 30997 @Override 30998 public void setValue(View object, float value) { 30999 object.setScaleY(value); 31000 } 31001 31002 @Override 31003 public Float get(View object) { 31004 return object.getScaleY(); 31005 } 31006 }; 31007 31008 /** 31009 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 31010 * Each MeasureSpec represents a requirement for either the width or the height. 31011 * A MeasureSpec is comprised of a size and a mode. There are three possible 31012 * modes: 31013 * <dl> 31014 * <dt>UNSPECIFIED</dt> 31015 * <dd> 31016 * The parent has not imposed any constraint on the child. It can be whatever size 31017 * it wants. 31018 * </dd> 31019 * 31020 * <dt>EXACTLY</dt> 31021 * <dd> 31022 * The parent has determined an exact size for the child. The child is going to be 31023 * given those bounds regardless of how big it wants to be. 31024 * </dd> 31025 * 31026 * <dt>AT_MOST</dt> 31027 * <dd> 31028 * The child can be as large as it wants up to the specified size. 31029 * </dd> 31030 * </dl> 31031 * 31032 * MeasureSpecs are implemented as ints to reduce object allocation. This class 31033 * is provided to pack and unpack the <size, mode> tuple into the int. 31034 */ 31035 public static class MeasureSpec { 31036 private static final int MODE_SHIFT = 30; 31037 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 31038 31039 /** @hide */ 31040 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 31041 @Retention(RetentionPolicy.SOURCE) 31042 public @interface MeasureSpecMode {} 31043 31044 /** 31045 * Measure specification mode: The parent has not imposed any constraint 31046 * on the child. It can be whatever size it wants. 31047 */ 31048 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 31049 31050 /** 31051 * Measure specification mode: The parent has determined an exact size 31052 * for the child. The child is going to be given those bounds regardless 31053 * of how big it wants to be. 31054 */ 31055 public static final int EXACTLY = 1 << MODE_SHIFT; 31056 31057 /** 31058 * Measure specification mode: The child can be as large as it wants up 31059 * to the specified size. 31060 */ 31061 public static final int AT_MOST = 2 << MODE_SHIFT; 31062 31063 /** 31064 * Creates a measure specification based on the supplied size and mode. 31065 * 31066 * The mode must always be one of the following: 31067 * <ul> 31068 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 31069 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 31070 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 31071 * </ul> 31072 * 31073 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 31074 * implementation was such that the order of arguments did not matter 31075 * and overflow in either value could impact the resulting MeasureSpec. 31076 * {@link android.widget.RelativeLayout} was affected by this bug. 31077 * Apps targeting API levels greater than 17 will get the fixed, more strict 31078 * behavior.</p> 31079 * 31080 * @param size the size of the measure specification 31081 * @param mode the mode of the measure specification 31082 * @return the measure specification based on size and mode 31083 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)31084 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 31085 @MeasureSpecMode int mode) { 31086 return (size & ~MODE_MASK) | (mode & MODE_MASK); 31087 } 31088 31089 /** 31090 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 31091 * will automatically get a size of 0. Older apps expect this. 31092 * 31093 * @hide internal use only for compatibility with system widgets and older apps 31094 */ 31095 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)31096 public static int makeSafeMeasureSpec(int size, int mode) { 31097 return makeMeasureSpec(size, mode); 31098 } 31099 31100 /** 31101 * Extracts the mode from the supplied measure specification. 31102 * 31103 * @param measureSpec the measure specification to extract the mode from 31104 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 31105 * {@link android.view.View.MeasureSpec#AT_MOST} or 31106 * {@link android.view.View.MeasureSpec#EXACTLY} 31107 */ 31108 @MeasureSpecMode getMode(int measureSpec)31109 public static int getMode(int measureSpec) { 31110 //noinspection ResourceType 31111 return (measureSpec & MODE_MASK); 31112 } 31113 31114 /** 31115 * Extracts the size from the supplied measure specification. 31116 * 31117 * @param measureSpec the measure specification to extract the size from 31118 * @return the size in pixels defined in the supplied measure specification 31119 */ getSize(int measureSpec)31120 public static int getSize(int measureSpec) { 31121 return (measureSpec & ~MODE_MASK); 31122 } 31123 adjust(int measureSpec, int delta)31124 static int adjust(int measureSpec, int delta) { 31125 final int mode = getMode(measureSpec); 31126 int size = getSize(measureSpec); 31127 if (mode == UNSPECIFIED) { 31128 // No need to adjust size for UNSPECIFIED mode. 31129 return makeMeasureSpec(size, UNSPECIFIED); 31130 } 31131 size += delta; 31132 if (size < 0) { 31133 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 31134 ") spec: " + toString(measureSpec) + " delta: " + delta); 31135 size = 0; 31136 } 31137 return makeMeasureSpec(size, mode); 31138 } 31139 31140 /** 31141 * Returns a String representation of the specified measure 31142 * specification. 31143 * 31144 * @param measureSpec the measure specification to convert to a String 31145 * @return a String with the following format: "MeasureSpec: MODE SIZE" 31146 */ toString(int measureSpec)31147 public static String toString(int measureSpec) { 31148 int mode = getMode(measureSpec); 31149 int size = getSize(measureSpec); 31150 31151 StringBuilder sb = new StringBuilder("MeasureSpec: "); 31152 31153 if (mode == UNSPECIFIED) 31154 sb.append("UNSPECIFIED "); 31155 else if (mode == EXACTLY) 31156 sb.append("EXACTLY "); 31157 else if (mode == AT_MOST) 31158 sb.append("AT_MOST "); 31159 else 31160 sb.append(mode).append(" "); 31161 31162 sb.append(size); 31163 return sb.toString(); 31164 } 31165 } 31166 31167 private final class CheckForLongPress implements Runnable { 31168 private int mOriginalWindowAttachCount; 31169 private float mX; 31170 private float mY; 31171 private boolean mOriginalPressedState; 31172 /** 31173 * The classification of the long click being checked: one of the 31174 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 31175 */ 31176 private int mClassification; 31177 31178 @UnsupportedAppUsage CheckForLongPress()31179 private CheckForLongPress() { 31180 } 31181 31182 @Override run()31183 public void run() { 31184 if ((mOriginalPressedState == isPressed()) && (mParent != null) 31185 && mOriginalWindowAttachCount == mWindowAttachCount) { 31186 recordGestureClassification(mClassification); 31187 if (performLongClick(mX, mY)) { 31188 mHasPerformedLongPress = true; 31189 } 31190 } 31191 } 31192 setAnchor(float x, float y)31193 public void setAnchor(float x, float y) { 31194 mX = x; 31195 mY = y; 31196 } 31197 rememberWindowAttachCount()31198 public void rememberWindowAttachCount() { 31199 mOriginalWindowAttachCount = mWindowAttachCount; 31200 } 31201 rememberPressedState()31202 public void rememberPressedState() { 31203 mOriginalPressedState = isPressed(); 31204 } 31205 setClassification(int classification)31206 public void setClassification(int classification) { 31207 mClassification = classification; 31208 } 31209 } 31210 31211 private final class CheckForTap implements Runnable { 31212 public float x; 31213 public float y; 31214 31215 @Override run()31216 public void run() { 31217 mPrivateFlags &= ~PFLAG_PREPRESSED; 31218 setPressed(true, x, y); 31219 final long delay = 31220 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 31221 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 31222 } 31223 } 31224 31225 private final class PerformClick implements Runnable { 31226 @Override run()31227 public void run() { 31228 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 31229 performClickInternal(); 31230 } 31231 } 31232 31233 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)31234 private void recordGestureClassification(int classification) { 31235 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 31236 return; 31237 } 31238 // To avoid negatively impacting View performance, the latency and displacement metrics 31239 // are omitted. 31240 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 31241 classification); 31242 } 31243 31244 /** 31245 * This method returns a ViewPropertyAnimator object, which can be used to animate 31246 * specific properties on this View. 31247 * 31248 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 31249 */ animate()31250 public ViewPropertyAnimator animate() { 31251 if (mAnimator == null) { 31252 mAnimator = new ViewPropertyAnimator(this); 31253 } 31254 return mAnimator; 31255 } 31256 31257 /** 31258 * Sets the name of the View to be used to identify Views in Transitions. 31259 * Names should be unique in the View hierarchy. 31260 * 31261 * @param transitionName The name of the View to uniquely identify it for Transitions. 31262 */ setTransitionName(String transitionName)31263 public final void setTransitionName(String transitionName) { 31264 mTransitionName = transitionName; 31265 } 31266 31267 /** 31268 * Returns the name of the View to be used to identify Views in Transitions. 31269 * Names should be unique in the View hierarchy. 31270 * 31271 * <p>This returns null if the View has not been given a name.</p> 31272 * 31273 * @return The name used of the View to be used to identify Views in Transitions or null 31274 * if no name has been given. 31275 */ 31276 @ViewDebug.ExportedProperty 31277 @InspectableProperty getTransitionName()31278 public String getTransitionName() { 31279 return mTransitionName; 31280 } 31281 31282 /** 31283 * @hide 31284 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)31285 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 31286 // Do nothing. 31287 } 31288 31289 /** 31290 * Interface definition for a callback to be invoked when a hardware key event is 31291 * dispatched to this view. The callback will be invoked before the key event is 31292 * given to the view. This is only useful for hardware keyboards; a software input 31293 * method has no obligation to trigger this listener. 31294 */ 31295 public interface OnKeyListener { 31296 /** 31297 * Called when a hardware key is dispatched to a view. This allows listeners to 31298 * get a chance to respond before the target view. 31299 * <p>Key presses in software keyboards will generally NOT trigger this method, 31300 * although some may elect to do so in some situations. Do not assume a 31301 * software input method has to be key-based; even if it is, it may use key presses 31302 * in a different way than you expect, so there is no way to reliably catch soft 31303 * input key presses. 31304 * 31305 * @param v The view the key has been dispatched to. 31306 * @param keyCode The code for the physical key that was pressed 31307 * @param event The KeyEvent object containing full information about 31308 * the event. 31309 * @return True if the listener has consumed the event, false otherwise. 31310 */ 31311 boolean onKey(View v, int keyCode, KeyEvent event); 31312 } 31313 31314 /** 31315 * Interface definition for a callback to be invoked when a hardware key event hasn't 31316 * been handled by the view hierarchy. 31317 */ 31318 public interface OnUnhandledKeyEventListener { 31319 /** 31320 * Called when a hardware key is dispatched to a view after being unhandled during normal 31321 * {@link KeyEvent} dispatch. 31322 * 31323 * @param v The view the key has been dispatched to. 31324 * @param event The KeyEvent object containing information about the event. 31325 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 31326 */ 31327 boolean onUnhandledKeyEvent(View v, KeyEvent event); 31328 } 31329 31330 /** 31331 * Interface definition for a callback to be invoked when a touch event is 31332 * dispatched to this view. The callback will be invoked before the touch 31333 * event is given to the view. 31334 */ 31335 public interface OnTouchListener { 31336 /** 31337 * Called when a touch event is dispatched to a view. This allows listeners to 31338 * get a chance to respond before the target view. 31339 * 31340 * @param v The view the touch event has been dispatched to. 31341 * @param event The MotionEvent object containing full information about 31342 * the event. 31343 * @return True if the listener has consumed the event, false otherwise. 31344 */ 31345 boolean onTouch(View v, MotionEvent event); 31346 } 31347 31348 /** 31349 * Interface definition for a callback to be invoked when a hover event is 31350 * dispatched to this view. The callback will be invoked before the hover 31351 * event is given to the view. 31352 */ 31353 public interface OnHoverListener { 31354 /** 31355 * Called when a hover event is dispatched to a view. This allows listeners to 31356 * get a chance to respond before the target view. 31357 * 31358 * @param v The view the hover event has been dispatched to. 31359 * @param event The MotionEvent object containing full information about 31360 * the event. 31361 * @return True if the listener has consumed the event, false otherwise. 31362 */ 31363 boolean onHover(View v, MotionEvent event); 31364 } 31365 31366 /** 31367 * Interface definition for a callback to be invoked when a generic motion event is 31368 * dispatched to this view. The callback will be invoked before the generic motion 31369 * event is given to the view. 31370 */ 31371 public interface OnGenericMotionListener { 31372 /** 31373 * Called when a generic motion event is dispatched to a view. This allows listeners to 31374 * get a chance to respond before the target view. 31375 * 31376 * @param v The view the generic motion event has been dispatched to. 31377 * @param event The MotionEvent object containing full information about 31378 * the event. 31379 * @return True if the listener has consumed the event, false otherwise. 31380 */ 31381 boolean onGenericMotion(View v, MotionEvent event); 31382 } 31383 31384 /** 31385 * Interface definition for a callback to be invoked when a view has been clicked and held. 31386 */ 31387 public interface OnLongClickListener { 31388 /** 31389 * Called when a view has been clicked and held. 31390 * 31391 * @param v The view that was clicked and held. 31392 * 31393 * @return true if the callback consumed the long click, false otherwise. 31394 */ 31395 boolean onLongClick(View v); 31396 31397 /** 31398 * Returns whether the default {@link HapticFeedbackConstants#LONG_PRESS} haptic feedback 31399 * is performed when this listener has consumed the long click. This method is called 31400 * immediately after {@link #onLongClick} has returned true. 31401 * 31402 * @param v The view that was clicked and held. 31403 * @return true to perform the default {@link HapticFeedbackConstants#LONG_PRESS} haptic 31404 * feedback, or false if the handler manages all haptics itself. 31405 */ onLongClickUseDefaultHapticFeedback(@onNull View v)31406 default boolean onLongClickUseDefaultHapticFeedback(@NonNull View v) { 31407 return true; 31408 } 31409 } 31410 31411 /** 31412 * Interface definition for a listener that's invoked when a drag event is dispatched to this 31413 * view. The listener is invoked before the view's own 31414 * {@link #onDragEvent(DragEvent)} method. To fall back to the view's 31415 * {@code onDragEvent(DragEvent)} behavior, return {@code false} from the listener method. 31416 * 31417 * <div class="special reference"> 31418 * <h3>Developer Guides</h3> 31419 * <p>For a guide to implementing drag and drop features, see the 31420 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and drop</a> developer guide.</p> 31421 * </div> 31422 */ 31423 public interface OnDragListener { 31424 /** 31425 * Called when a drag event is dispatched to a view. Enables listeners to override the 31426 * base behavior provided by {@link #onDragEvent(DragEvent)}. 31427 * 31428 * @param v The {@code View} that received the drag event. 31429 * @param event The event object for the drag event. 31430 * @return {@code true} if the drag event was handled successfully; {@code false}, if the 31431 * drag event was not handled. <b>Note:</b> A {@code false} return value triggers the 31432 * view's {@link #onDragEvent(DragEvent)} handler. 31433 */ 31434 boolean onDrag(View v, DragEvent event); 31435 } 31436 31437 /** 31438 * Interface definition for a callback to be invoked when the focus state of 31439 * a view changed. 31440 */ 31441 public interface OnFocusChangeListener { 31442 /** 31443 * Called when the focus state of a view has changed. 31444 * 31445 * @param v The view whose state has changed. 31446 * @param hasFocus The new focus state of v. 31447 */ 31448 void onFocusChange(View v, boolean hasFocus); 31449 } 31450 31451 /** 31452 * Interface definition for a callback to be invoked when a view is clicked. 31453 */ 31454 public interface OnClickListener { 31455 /** 31456 * Called when a view has been clicked. 31457 * 31458 * @param v The view that was clicked. 31459 */ 31460 void onClick(View v); 31461 } 31462 31463 /** 31464 * Interface definition for a callback to be invoked when a view is context clicked. 31465 */ 31466 public interface OnContextClickListener { 31467 /** 31468 * Called when a view is context clicked. 31469 * 31470 * @param v The view that has been context clicked. 31471 * @return true if the callback consumed the context click, false otherwise. 31472 */ 31473 boolean onContextClick(View v); 31474 } 31475 31476 /** 31477 * Interface definition for a callback to be invoked when the context menu 31478 * for this view is being built. 31479 */ 31480 public interface OnCreateContextMenuListener { 31481 /** 31482 * Called when the context menu for this view is being built. It is not 31483 * safe to hold onto the menu after this method returns. 31484 * 31485 * @param menu The context menu that is being built 31486 * @param v The view for which the context menu is being built 31487 * @param menuInfo Extra information about the item for which the 31488 * context menu should be shown. This information will vary 31489 * depending on the class of v. 31490 */ 31491 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 31492 } 31493 31494 /** 31495 * Interface definition for a callback to be invoked when the status bar changes 31496 * visibility. This reports <strong>global</strong> changes to the system UI 31497 * state, not what the application is requesting. 31498 * 31499 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 31500 * 31501 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 31502 * by setting a {@link OnApplyWindowInsetsListener} on this view. 31503 */ 31504 @Deprecated 31505 public interface OnSystemUiVisibilityChangeListener { 31506 /** 31507 * Called when the status bar changes visibility because of a call to 31508 * {@link View#setSystemUiVisibility(int)}. 31509 * 31510 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 31511 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 31512 * This tells you the <strong>global</strong> state of these UI visibility 31513 * flags, not what your app is currently applying. 31514 */ 31515 public void onSystemUiVisibilityChange(int visibility); 31516 } 31517 31518 /** 31519 * Interface definition for a callback to be invoked when this view is attached 31520 * or detached from its window. 31521 */ 31522 public interface OnAttachStateChangeListener { 31523 /** 31524 * Called when the view is attached to a window. 31525 * @param v The view that was attached 31526 */ 31527 public void onViewAttachedToWindow(@NonNull View v); 31528 /** 31529 * Called when the view is detached from a window. 31530 * @param v The view that was detached 31531 */ 31532 public void onViewDetachedFromWindow(@NonNull View v); 31533 } 31534 31535 /** 31536 * Listener for applying window insets on a view in a custom way. 31537 * 31538 * <p>Apps may choose to implement this interface if they want to apply custom policy 31539 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 31540 * is set, its 31541 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 31542 * method will be called instead of the View's own 31543 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 31544 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 31545 * the View's normal behavior as part of its own.</p> 31546 */ 31547 public interface OnApplyWindowInsetsListener { 31548 /** 31549 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 31550 * on a View, this listener method will be called instead of the view's own 31551 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 31552 * 31553 * @param v The view applying window insets 31554 * @param insets The insets to apply 31555 * @return The insets supplied, minus any insets that were consumed 31556 */ 31557 public @NonNull WindowInsets onApplyWindowInsets(@NonNull View v, 31558 @NonNull WindowInsets insets); 31559 } 31560 31561 private final class UnsetPressedState implements Runnable { 31562 @Override run()31563 public void run() { 31564 setPressed(false); 31565 } 31566 } 31567 31568 /** 31569 * When a view becomes invisible checks if autofill considers the view invisible too. This 31570 * happens after the regular removal operation to make sure the operation is finished by the 31571 * time this is called. 31572 */ 31573 private static class VisibilityChangeForAutofillHandler extends Handler { 31574 private final AutofillManager mAfm; 31575 private final View mView; 31576 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)31577 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 31578 @NonNull View view) { 31579 mAfm = afm; 31580 mView = view; 31581 } 31582 31583 @Override handleMessage(Message msg)31584 public void handleMessage(Message msg) { 31585 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 31586 } 31587 } 31588 31589 /** 31590 * Base class for derived classes that want to save and restore their own 31591 * state in {@link android.view.View#onSaveInstanceState()}. 31592 */ 31593 public static class BaseSavedState extends AbsSavedState { 31594 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 31595 static final int IS_AUTOFILLED = 0b10; 31596 static final int AUTOFILL_ID = 0b100; 31597 31598 // Flags that describe what data in this state is valid 31599 int mSavedData; 31600 String mStartActivityRequestWhoSaved; 31601 boolean mIsAutofilled; 31602 boolean mHideHighlight; 31603 int mAutofillViewId; 31604 31605 /** 31606 * Constructor used when reading from a parcel. Reads the state of the superclass. 31607 * 31608 * @param source parcel to read from 31609 */ BaseSavedState(Parcel source)31610 public BaseSavedState(Parcel source) { 31611 this(source, null); 31612 } 31613 31614 /** 31615 * Constructor used when reading from a parcel using a given class loader. 31616 * Reads the state of the superclass. 31617 * 31618 * @param source parcel to read from 31619 * @param loader ClassLoader to use for reading 31620 */ BaseSavedState(Parcel source, ClassLoader loader)31621 public BaseSavedState(Parcel source, ClassLoader loader) { 31622 super(source, loader); 31623 mSavedData = source.readInt(); 31624 mStartActivityRequestWhoSaved = source.readString(); 31625 mIsAutofilled = source.readBoolean(); 31626 mHideHighlight = source.readBoolean(); 31627 mAutofillViewId = source.readInt(); 31628 } 31629 31630 /** 31631 * Constructor called by derived classes when creating their SavedState objects 31632 * 31633 * @param superState The state of the superclass of this view 31634 */ BaseSavedState(Parcelable superState)31635 public BaseSavedState(Parcelable superState) { 31636 super(superState); 31637 } 31638 31639 @Override writeToParcel(Parcel out, int flags)31640 public void writeToParcel(Parcel out, int flags) { 31641 super.writeToParcel(out, flags); 31642 31643 out.writeInt(mSavedData); 31644 out.writeString(mStartActivityRequestWhoSaved); 31645 out.writeBoolean(mIsAutofilled); 31646 out.writeBoolean(mHideHighlight); 31647 out.writeInt(mAutofillViewId); 31648 } 31649 31650 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 31651 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 31652 @Override 31653 public BaseSavedState createFromParcel(Parcel in) { 31654 return new BaseSavedState(in); 31655 } 31656 31657 @Override 31658 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 31659 return new BaseSavedState(in, loader); 31660 } 31661 31662 @Override 31663 public BaseSavedState[] newArray(int size) { 31664 return new BaseSavedState[size]; 31665 } 31666 }; 31667 } 31668 31669 /** 31670 * A set of information given to a view when it is attached to its parent 31671 * window. 31672 */ 31673 final static class AttachInfo { 31674 31675 interface Callbacks { 31676 void playSoundEffect(int effectId); 31677 boolean performHapticFeedback(int effectId, boolean always, boolean fromIme); 31678 } 31679 31680 /** 31681 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 31682 * to a Handler. This class contains the target (View) to invalidate and 31683 * the coordinates of the dirty rectangle. 31684 * 31685 * For performance purposes, this class also implements a pool of up to 31686 * POOL_LIMIT objects that get reused. This reduces memory allocations 31687 * whenever possible. 31688 */ 31689 static class InvalidateInfo { 31690 31691 @UnsupportedAppUsage InvalidateInfo()31692 InvalidateInfo() { 31693 } 31694 31695 private static final int POOL_LIMIT = 10; 31696 31697 private static final SynchronizedPool<InvalidateInfo> sPool = 31698 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 31699 31700 @UnsupportedAppUsage 31701 View target; 31702 31703 @UnsupportedAppUsage 31704 int left; 31705 @UnsupportedAppUsage 31706 int top; 31707 @UnsupportedAppUsage 31708 int right; 31709 @UnsupportedAppUsage 31710 int bottom; 31711 obtain()31712 public static InvalidateInfo obtain() { 31713 InvalidateInfo instance = sPool.acquire(); 31714 return (instance != null) ? instance : new InvalidateInfo(); 31715 } 31716 recycle()31717 public void recycle() { 31718 target = null; 31719 sPool.release(this); 31720 } 31721 } 31722 31723 @UnsupportedAppUsage 31724 final IWindowSession mSession; 31725 31726 @UnsupportedAppUsage 31727 final IWindow mWindow; 31728 31729 final IBinder mWindowToken; 31730 31731 Display mDisplay; 31732 31733 final Callbacks mRootCallbacks; 31734 31735 IWindowId mIWindowId; 31736 WindowId mWindowId; 31737 31738 /** 31739 * The top view of the hierarchy. 31740 */ 31741 View mRootView; 31742 31743 IBinder mPanelParentWindowToken; 31744 31745 boolean mHardwareAccelerated; 31746 boolean mHardwareAccelerationRequested; 31747 ThreadedRenderer mThreadedRenderer; 31748 List<RenderNode> mPendingAnimatingRenderNodes; 31749 31750 /** 31751 * The state of the display to which the window is attached, as reported 31752 * by {@link Display#getState()}. Note that the display state constants 31753 * declared by {@link Display} do not exactly line up with the screen state 31754 * constants declared by {@link View} (there are more display states than 31755 * screen states). 31756 */ 31757 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 31758 int mDisplayState = Display.STATE_UNKNOWN; 31759 31760 /** 31761 * Scale factor used by the compatibility mode 31762 */ 31763 @UnsupportedAppUsage 31764 float mApplicationScale; 31765 31766 /** 31767 * Indicates whether the application is in compatibility mode 31768 */ 31769 @UnsupportedAppUsage 31770 boolean mScalingRequired; 31771 31772 /** 31773 * Left position of this view's window 31774 */ 31775 int mWindowLeft; 31776 31777 /** 31778 * Top position of this view's window 31779 */ 31780 int mWindowTop; 31781 31782 /** 31783 * Indicates whether views need to use 32-bit drawing caches 31784 */ 31785 boolean mUse32BitDrawingCache; 31786 31787 /** 31788 * For windows that are full-screen but using insets to layout inside 31789 * of the screen decorations, these are the current insets for the 31790 * content of the window. 31791 */ 31792 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 31793 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 31794 final Rect mContentInsets = new Rect(); 31795 31796 /** 31797 * For windows that are full-screen but using insets to layout inside 31798 * of the screen decorations, these are the current insets for the 31799 * actual visible parts of the window. 31800 */ 31801 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 31802 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 31803 final Rect mVisibleInsets = new Rect(); 31804 31805 /** 31806 * For windows that are full-screen but using insets to layout inside 31807 * of the screen decorations, these are the current insets for the 31808 * stable system windows. 31809 */ 31810 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 31811 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 31812 final Rect mStableInsets = new Rect(); 31813 31814 /** 31815 * Current caption insets to the display coordinate. 31816 */ 31817 final Rect mCaptionInsets = new Rect(); 31818 31819 /** 31820 * In multi-window we force show the system bars. Because we don't want that the surface 31821 * size changes in this mode, we instead have a flag whether the system bars sizes should 31822 * always be consumed, so the app is treated like there are no virtual system bars at all. 31823 */ 31824 boolean mAlwaysConsumeSystemBars; 31825 31826 /** 31827 * The internal insets given by this window. This value is 31828 * supplied by the client (through 31829 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 31830 * be given to the window manager when changed to be used in laying 31831 * out windows behind it. 31832 */ 31833 @UnsupportedAppUsage 31834 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 31835 = new ViewTreeObserver.InternalInsetsInfo(); 31836 31837 /** 31838 * Set to true when mGivenInternalInsets is non-empty. 31839 */ 31840 boolean mHasNonEmptyGivenInternalInsets; 31841 31842 /** 31843 * All views in the window's hierarchy that serve as scroll containers, 31844 * used to determine if the window can be resized or must be panned 31845 * to adjust for a soft input area. 31846 */ 31847 @UnsupportedAppUsage 31848 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 31849 31850 @UnsupportedAppUsage 31851 final KeyEvent.DispatcherState mKeyDispatchState 31852 = new KeyEvent.DispatcherState(); 31853 31854 /** 31855 * Indicates whether the view's window currently has the focus. 31856 */ 31857 @UnsupportedAppUsage 31858 boolean mHasWindowFocus; 31859 31860 /** 31861 * The current visibility of the window. 31862 */ 31863 int mWindowVisibility; 31864 31865 /** 31866 * Indicates the time at which drawing started to occur. 31867 */ 31868 @UnsupportedAppUsage 31869 long mDrawingTime; 31870 31871 /** 31872 * Indicates whether the view's window is currently in touch mode. 31873 */ 31874 @UnsupportedAppUsage 31875 boolean mInTouchMode; 31876 31877 /** 31878 * Indicates whether the view has requested unbuffered input dispatching for the current 31879 * event stream. 31880 */ 31881 boolean mUnbufferedDispatchRequested; 31882 31883 /** 31884 * Indicates that ViewAncestor should trigger a global layout change 31885 * the next time it performs a traversal 31886 */ 31887 @UnsupportedAppUsage 31888 boolean mRecomputeGlobalAttributes; 31889 31890 /** 31891 * Always report new attributes at next traversal. 31892 */ 31893 boolean mForceReportNewAttributes; 31894 31895 /** 31896 * Set during a traveral if any views want to keep the screen on. 31897 */ 31898 @UnsupportedAppUsage 31899 boolean mKeepScreenOn; 31900 31901 /** 31902 * Set during a traveral if the light center needs to be updated. 31903 */ 31904 boolean mNeedsUpdateLightCenter; 31905 31906 /** 31907 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 31908 */ 31909 int mSystemUiVisibility; 31910 31911 /** 31912 * Hack to force certain system UI visibility flags to be cleared. 31913 */ 31914 int mDisabledSystemUiVisibility; 31915 31916 /** 31917 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 31918 * attached. 31919 */ 31920 boolean mHasSystemUiListeners; 31921 31922 /** 31923 * Set if the visibility of any views has changed. 31924 */ 31925 @UnsupportedAppUsage 31926 boolean mViewVisibilityChanged; 31927 31928 /** 31929 * Set to true if a view has been scrolled. 31930 */ 31931 @UnsupportedAppUsage 31932 boolean mViewScrollChanged; 31933 31934 /** 31935 * Set to true if a pointer event is currently being handled. 31936 */ 31937 boolean mHandlingPointerEvent; 31938 31939 /** 31940 * The window matrix of this view when it's on a {@link SurfaceControlViewHost} that is 31941 * embedded within a SurfaceView. 31942 */ 31943 Matrix mWindowMatrixInEmbeddedHierarchy; 31944 31945 /** 31946 * Global to the view hierarchy used as a temporary for dealing with 31947 * x/y points in the transparent region computations. 31948 */ 31949 final int[] mTransparentLocation = new int[2]; 31950 31951 /** 31952 * Global to the view hierarchy used as a temporary for dealing with 31953 * x/y points in the ViewGroup.invalidateChild implementation. 31954 */ 31955 final int[] mInvalidateChildLocation = new int[2]; 31956 31957 /** 31958 * Global to the view hierarchy used as a temporary for dealing with 31959 * computing absolute on-screen location. 31960 */ 31961 final int[] mTmpLocation = new int[2]; 31962 31963 /** 31964 * Global to the view hierarchy used as a temporary for dealing with 31965 * x/y location when view is transformed. 31966 */ 31967 final float[] mTmpTransformLocation = new float[2]; 31968 31969 /** 31970 * The view tree observer used to dispatch global events like 31971 * layout, pre-draw, touch mode change, etc. 31972 */ 31973 @UnsupportedAppUsage 31974 final ViewTreeObserver mTreeObserver; 31975 31976 /** 31977 * A Canvas used by the view hierarchy to perform bitmap caching. 31978 */ 31979 Canvas mCanvas; 31980 31981 /** 31982 * The view root impl. 31983 */ 31984 final ViewRootImpl mViewRootImpl; 31985 31986 /** 31987 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 31988 * handler can be used to pump events in the UI events queue. 31989 */ 31990 @UnsupportedAppUsage 31991 final Handler mHandler; 31992 31993 /** 31994 * Temporary for use in computing invalidate rectangles while 31995 * calling up the hierarchy. 31996 */ 31997 final Rect mTmpInvalRect = new Rect(); 31998 31999 /** 32000 * Temporary for use in computing hit areas with transformed views 32001 */ 32002 final RectF mTmpTransformRect = new RectF(); 32003 32004 /** 32005 * Temporary for use in computing hit areas with transformed views 32006 */ 32007 final RectF mTmpTransformRect1 = new RectF(); 32008 32009 /** 32010 * Temporary list of rectanges. 32011 */ 32012 final List<RectF> mTmpRectList = new ArrayList<>(); 32013 32014 /** 32015 * Temporary for use in transforming invalidation rect 32016 */ 32017 final Matrix mTmpMatrix = new Matrix(); 32018 32019 /** 32020 * Temporary for use in transforming invalidation rect 32021 */ 32022 final Transformation mTmpTransformation = new Transformation(); 32023 32024 /** 32025 * Temporary for use in querying outlines from OutlineProviders 32026 */ 32027 final Outline mTmpOutline = new Outline(); 32028 32029 /** 32030 * Temporary list for use in collecting focusable descendents of a view. 32031 */ 32032 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 32033 32034 /** 32035 * Indicates if the next focus will be looped back to the first focusable view of the entire 32036 * hierarchy when finding in the direction of {@link #FOCUS_FORWARD} or to the last 32037 * focusable view when finding in the direction of {@link #FOCUS_BACKWARD}. 32038 */ 32039 boolean mNextFocusLooped = false; 32040 32041 /** 32042 * The id of the window for accessibility purposes. 32043 */ 32044 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 32045 32046 /** 32047 * Flags related to accessibility processing. 32048 * 32049 * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS 32050 * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS 32051 */ 32052 int mAccessibilityFetchFlags; 32053 32054 /** 32055 * The drawable for highlighting accessibility focus. 32056 */ 32057 Drawable mAccessibilityFocusDrawable; 32058 32059 /** 32060 * The drawable for highlighting autofilled views. 32061 * 32062 * @see #isAutofilled() 32063 */ 32064 Drawable mAutofilledDrawable; 32065 32066 /** 32067 * Show where the margins, bounds and layout bounds are for each view. 32068 */ 32069 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 32070 32071 /** 32072 * Point used to compute visible regions. 32073 */ 32074 final Point mPoint = new Point(); 32075 32076 /** 32077 * Used to track which View originated a requestLayout() call, used when 32078 * requestLayout() is called during layout. 32079 */ 32080 View mViewRequestingLayout; 32081 32082 /** 32083 * Used to track the identity of the current drag operation. 32084 */ 32085 IBinder mDragToken; 32086 32087 /** 32088 * Used to track the data of the current drag operation for cleanup later. 32089 */ 32090 ClipData mDragData; 32091 32092 /** 32093 * The drag shadow surface for the current drag operation. 32094 */ 32095 public Surface mDragSurface; 32096 32097 /** 32098 * The view that currently has a tooltip displayed. 32099 */ 32100 View mTooltipHost; 32101 32102 /** 32103 * The initial structure has been reported so the view is ready to report updates. 32104 */ 32105 boolean mReadyForContentCaptureUpdates; 32106 32107 /** 32108 * Map(keyed by session) of content capture events that need to be notified after the view 32109 * hierarchy is traversed: value is either the view itself for appearead events, or its 32110 * autofill id for disappeared. 32111 */ 32112 SparseArray<ArrayList<Object>> mContentCaptureEvents; 32113 32114 /** 32115 * Cached reference to the {@link ContentCaptureManager}. 32116 */ 32117 ContentCaptureManager mContentCaptureManager; 32118 32119 /** 32120 * Listener used to fit content on window level. 32121 */ 32122 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 32123 32124 /** 32125 * The leash token of this view's parent when it's in an embedded hierarchy that is 32126 * re-parented to another window. 32127 */ 32128 IBinder mLeashedParentToken; 32129 32130 /** 32131 * The accessibility view id of this view's parent when it's in an embedded 32132 * hierarchy that is re-parented to another window. 32133 */ 32134 int mLeashedParentAccessibilityViewId; 32135 32136 /** 32137 * 32138 */ 32139 ScrollCaptureInternal mScrollCaptureInternal; 32140 32141 /** 32142 * sensitive views attached to the window 32143 */ 32144 int mSensitiveViewsCount; 32145 32146 /** 32147 * The value of viewVelocityApi(), read only once per ViewRootImpl 32148 */ 32149 final boolean mViewVelocityApi = viewVelocityApi(); 32150 32151 /** 32152 * Density so that it doesn't need to be retrieved on every invalidation. 32153 */ 32154 final float mDensity; 32155 32156 /** 32157 * The number of pixels in the display (width * height). 32158 */ 32159 final float mDisplayPixelCount; 32160 32161 /** 32162 * Creates a new set of attachment information with the specified 32163 * events handler and thread. 32164 * 32165 * @param handler the events handler the view must use 32166 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)32167 AttachInfo(IWindowSession session, IWindow window, Display display, 32168 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 32169 Context context) { 32170 mSession = session; 32171 mWindow = window; 32172 mWindowToken = window.asBinder(); 32173 mDisplay = display; 32174 mViewRootImpl = viewRootImpl; 32175 mHandler = handler; 32176 mRootCallbacks = effectPlayer; 32177 mTreeObserver = new ViewTreeObserver(context); 32178 DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 32179 mDensity = displayMetrics.density; 32180 float pixelCount = (float) displayMetrics.widthPixels * displayMetrics.heightPixels; 32181 mDisplayPixelCount = pixelCount == 0f ? Float.POSITIVE_INFINITY : pixelCount; 32182 } 32183 increaseSensitiveViewsCount()32184 void increaseSensitiveViewsCount() { 32185 if (mSensitiveViewsCount == 0) { 32186 mViewRootImpl.addSensitiveContentAppProtection(); 32187 } 32188 mSensitiveViewsCount++; 32189 } 32190 decreaseSensitiveViewsCount()32191 void decreaseSensitiveViewsCount() { 32192 mSensitiveViewsCount--; 32193 if (mSensitiveViewsCount == 0) { 32194 mViewRootImpl.removeSensitiveContentAppProtection(); 32195 } 32196 if (mSensitiveViewsCount < 0) { 32197 Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount); 32198 mSensitiveViewsCount = 0; 32199 } 32200 } 32201 32202 @Nullable getContentCaptureManager(@onNull Context context)32203 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 32204 if (mContentCaptureManager != null) { 32205 return mContentCaptureManager; 32206 } 32207 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 32208 return mContentCaptureManager; 32209 } 32210 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)32211 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 32212 if (mContentCaptureManager == null) { 32213 return; 32214 } 32215 32216 ArrayList<Object> events = ensureEvents( 32217 mContentCaptureManager.getMainContentCaptureSession()); 32218 events.add(insets); 32219 } 32220 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)32221 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 32222 @NonNull View view, boolean appeared) { 32223 ArrayList<Object> events = ensureEvents(session); 32224 events.add(appeared ? view : view.getAutofillId()); 32225 } 32226 32227 @NonNull ensureEvents(@onNull ContentCaptureSession session)32228 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 32229 if (mContentCaptureEvents == null) { 32230 // Most of the time there will be just one session, so intial capacity is 1 32231 mContentCaptureEvents = new SparseArray<>(1); 32232 } 32233 int sessionId = session.getId(); 32234 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 32235 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 32236 if (events == null) { 32237 events = new ArrayList<>(); 32238 mContentCaptureEvents.put(sessionId, events); 32239 } 32240 32241 return events; 32242 } 32243 canPerformHapticFeedback()32244 private boolean canPerformHapticFeedback() { 32245 return mSession != null 32246 && (mDisplay.getFlags() & Display.FLAG_TOUCH_FEEDBACK_DISABLED) == 0; 32247 } 32248 32249 @Nullable getScrollCaptureInternal()32250 ScrollCaptureInternal getScrollCaptureInternal() { 32251 if (mScrollCaptureInternal != null) { 32252 mScrollCaptureInternal = new ScrollCaptureInternal(); 32253 } 32254 return mScrollCaptureInternal; 32255 } 32256 getRootSurfaceControl()32257 AttachedSurfaceControl getRootSurfaceControl() { 32258 return mViewRootImpl; 32259 } 32260 dump(String prefix, PrintWriter writer)32261 public void dump(String prefix, PrintWriter writer) { 32262 String innerPrefix = prefix + " "; 32263 writer.println(prefix + "AttachInfo:"); 32264 writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); 32265 writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); 32266 writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); 32267 writer.println(innerPrefix + "mUnbufferedDispatchRequested=" 32268 + mUnbufferedDispatchRequested); 32269 } 32270 } 32271 32272 /** 32273 * <p>ScrollabilityCache holds various fields used by a View when scrolling 32274 * is supported. This avoids keeping too many unused fields in most 32275 * instances of View.</p> 32276 */ 32277 private static class ScrollabilityCache implements Runnable { 32278 32279 /** 32280 * Scrollbars are not visible 32281 */ 32282 public static final int OFF = 0; 32283 32284 /** 32285 * Scrollbars are visible 32286 */ 32287 public static final int ON = 1; 32288 32289 /** 32290 * Scrollbars are fading away 32291 */ 32292 public static final int FADING = 2; 32293 32294 public boolean fadeScrollBars; 32295 32296 public int fadingEdgeLength; 32297 public int scrollBarDefaultDelayBeforeFade; 32298 public int scrollBarFadeDuration; 32299 32300 public int scrollBarSize; 32301 public int scrollBarMinTouchTarget; 32302 @UnsupportedAppUsage 32303 public ScrollBarDrawable scrollBar; 32304 public float[] interpolatorValues; 32305 @UnsupportedAppUsage 32306 public View host; 32307 32308 public final Paint paint; 32309 public final Matrix matrix; 32310 public Shader shader; 32311 32312 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 32313 32314 private static final float[] OPAQUE = { 255 }; 32315 private static final float[] TRANSPARENT = { 0.0f }; 32316 32317 /** 32318 * When fading should start. This time moves into the future every time 32319 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 32320 */ 32321 public long fadeStartTime; 32322 32323 32324 /** 32325 * The current state of the scrollbars: ON, OFF, or FADING 32326 */ 32327 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 32328 public int state = OFF; 32329 32330 private int mLastColor; 32331 32332 public final Rect mScrollBarBounds = new Rect(); 32333 public final Rect mScrollBarTouchBounds = new Rect(); 32334 32335 public static final int NOT_DRAGGING = 0; 32336 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 32337 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 32338 public int mScrollBarDraggingState = NOT_DRAGGING; 32339 32340 public float mScrollBarDraggingPos = 0; 32341 ScrollabilityCache(ViewConfiguration configuration, View host)32342 public ScrollabilityCache(ViewConfiguration configuration, View host) { 32343 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 32344 scrollBarSize = configuration.getScaledScrollBarSize(); 32345 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 32346 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 32347 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 32348 32349 paint = new Paint(); 32350 matrix = new Matrix(); 32351 // use use a height of 1, and then wack the matrix each time we 32352 // actually use it. 32353 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 32354 paint.setShader(shader); 32355 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 32356 32357 this.host = host; 32358 } 32359 setFadeColor(int color)32360 public void setFadeColor(int color) { 32361 if (color != mLastColor) { 32362 mLastColor = color; 32363 32364 if (color != 0) { 32365 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 32366 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 32367 paint.setShader(shader); 32368 // Restore the default transfer mode (src_over) 32369 paint.setXfermode(null); 32370 } else { 32371 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 32372 paint.setShader(shader); 32373 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 32374 } 32375 } 32376 } 32377 run()32378 public void run() { 32379 long now = AnimationUtils.currentAnimationTimeMillis(); 32380 if (now >= fadeStartTime) { 32381 32382 // the animation fades the scrollbars out by changing 32383 // the opacity (alpha) from fully opaque to fully 32384 // transparent 32385 int nextFrame = (int) now; 32386 int framesCount = 0; 32387 32388 Interpolator interpolator = scrollBarInterpolator; 32389 32390 // Start opaque 32391 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 32392 32393 // End transparent 32394 nextFrame += scrollBarFadeDuration; 32395 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 32396 32397 state = FADING; 32398 32399 // Kick off the fade animation 32400 host.invalidate(true); 32401 } 32402 } 32403 } 32404 32405 private class SendAccessibilityEventThrottle implements Runnable { 32406 public volatile boolean mIsPending; 32407 private AccessibilityEvent mAccessibilityEvent; 32408 post(AccessibilityEvent accessibilityEvent)32409 public void post(AccessibilityEvent accessibilityEvent) { 32410 updateWithAccessibilityEvent(accessibilityEvent); 32411 if (!mIsPending) { 32412 mIsPending = true; 32413 postDelayed(this, 32414 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 32415 } 32416 } 32417 32418 @Override run()32419 public void run() { 32420 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 32421 requestParentSendAccessibilityEvent(mAccessibilityEvent); 32422 } 32423 reset(); 32424 } 32425 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)32426 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 32427 mAccessibilityEvent = accessibilityEvent; 32428 } 32429 reset()32430 public void reset() { 32431 mIsPending = false; 32432 mAccessibilityEvent = null; 32433 } 32434 32435 } 32436 32437 /** 32438 * Resuable callback for sending 32439 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 32440 */ 32441 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 32442 public int mDeltaX; 32443 public int mDeltaY; 32444 32445 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)32446 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 32447 super.updateWithAccessibilityEvent(accessibilityEvent); 32448 mDeltaX += accessibilityEvent.getScrollDeltaX(); 32449 mDeltaY += accessibilityEvent.getScrollDeltaY(); 32450 accessibilityEvent.setScrollDeltaX(mDeltaX); 32451 accessibilityEvent.setScrollDeltaY(mDeltaY); 32452 } 32453 32454 @Override reset()32455 public void reset() { 32456 super.reset(); 32457 mDeltaX = 0; 32458 mDeltaY = 0; 32459 } 32460 } 32461 /** 32462 * Remove the pending callback for sending a throttled accessibility event. 32463 */ 32464 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)32465 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 32466 if (callback == null || !callback.mIsPending) return; 32467 removeCallbacks(callback); 32468 callback.reset(); 32469 } 32470 32471 /** 32472 * <p> 32473 * This class represents a delegate that can be registered in a {@link View} 32474 * to enhance accessibility support via composition rather via inheritance. 32475 * It is specifically targeted to widget developers that extend basic View 32476 * classes i.e. classes in package android.view, that would like their 32477 * applications to be backwards compatible. 32478 * </p> 32479 * <div class="special reference"> 32480 * <h3>Developer Guides</h3> 32481 * <p>For more information about making applications accessible, read the 32482 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 32483 * developer guide.</p> 32484 * </div> 32485 * <p> 32486 * A scenario in which a developer would like to use an accessibility delegate 32487 * is overriding a method introduced in a later API version than the minimal API 32488 * version supported by the application. For example, the method 32489 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 32490 * in API version 4 when the accessibility APIs were first introduced. If a 32491 * developer would like their application to run on API version 4 devices (assuming 32492 * all other APIs used by the application are version 4 or lower) and take advantage 32493 * of this method, instead of overriding the method which would break the application's 32494 * backwards compatibility, they can override the corresponding method in this 32495 * delegate and register the delegate in the target View if the API version of 32496 * the system is high enough, i.e. the API version is the same as or higher than the API 32497 * version that introduced 32498 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 32499 * </p> 32500 * <p> 32501 * Here is an example implementation: 32502 * </p> 32503 * <code><pre><p> 32504 * if (Build.VERSION.SDK_INT >= 14) { 32505 * // If the API version is equal of higher than the version in 32506 * // which onInitializeAccessibilityNodeInfo was introduced we 32507 * // register a delegate with a customized implementation. 32508 * View view = findViewById(R.id.view_id); 32509 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 32510 * public void onInitializeAccessibilityNodeInfo(View host, 32511 * AccessibilityNodeInfo info) { 32512 * // Let the default implementation populate the info. 32513 * super.onInitializeAccessibilityNodeInfo(host, info); 32514 * // Set some other information. 32515 * info.setEnabled(host.isEnabled()); 32516 * } 32517 * }); 32518 * } 32519 * </code></pre></p> 32520 * <p> 32521 * This delegate contains methods that correspond to the accessibility methods 32522 * in View. If a delegate has been specified the implementation in View hands 32523 * off handling to the corresponding method in this delegate. The default 32524 * implementation the delegate methods behaves exactly as the corresponding 32525 * method in View for the case of no accessibility delegate been set. Hence, 32526 * to customize the behavior of a View method, clients can override only the 32527 * corresponding delegate method without altering the behavior of the rest 32528 * accessibility related methods of the host view. 32529 * </p> 32530 * <p> 32531 * <strong>Note:</strong> On platform versions prior to 32532 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 32533 * views in the {@code android.widget.*} package are called <i>before</i> 32534 * host methods. This prevents certain properties such as class name from 32535 * being modified by overriding 32536 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 32537 * as any changes will be overwritten by the host class. 32538 * <p> 32539 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 32540 * methods are called <i>after</i> host methods, which all properties to be 32541 * modified without being overwritten by the host class. 32542 * <aside class="note"> 32543 * <b>Note:</b> Use a {@link androidx.core.view.AccessibilityDelegateCompat} 32544 * wrapper instead of this class for backwards-compatibility. 32545 * </aside> 32546 * 32547 */ 32548 public static class AccessibilityDelegate { 32549 32550 /** 32551 * Sends an accessibility event of the given type. If accessibility is not 32552 * enabled this method has no effect. 32553 * <p> 32554 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 32555 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 32556 * been set. 32557 * </p> 32558 * 32559 * @param host The View hosting the delegate. 32560 * @param eventType The type of the event to send. 32561 * 32562 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 32563 */ sendAccessibilityEvent(@onNull View host, int eventType)32564 public void sendAccessibilityEvent(@NonNull View host, int eventType) { 32565 host.sendAccessibilityEventInternal(eventType); 32566 } 32567 32568 /** 32569 * Performs the specified accessibility action on the view. For 32570 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 32571 * <p> 32572 * The default implementation behaves as 32573 * {@link View#performAccessibilityAction(int, Bundle) 32574 * View#performAccessibilityAction(int, Bundle)} for the case of 32575 * no accessibility delegate been set. 32576 * </p> 32577 * 32578 * @param action The action to perform. 32579 * @return Whether the action was performed. 32580 * 32581 * @see View#performAccessibilityAction(int, Bundle) 32582 * View#performAccessibilityAction(int, Bundle) 32583 */ performAccessibilityAction(@onNull View host, int action, @Nullable Bundle args)32584 public boolean performAccessibilityAction(@NonNull View host, int action, 32585 @Nullable Bundle args) { 32586 return host.performAccessibilityActionInternal(action, args); 32587 } 32588 32589 /** 32590 * Sends an accessibility event. This method behaves exactly as 32591 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 32592 * empty {@link AccessibilityEvent} and does not perform a check whether 32593 * accessibility is enabled. 32594 * <p> 32595 * The default implementation behaves as 32596 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 32597 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 32598 * the case of no accessibility delegate been set. 32599 * </p> 32600 * 32601 * @param host The View hosting the delegate. 32602 * @param event The event to send. 32603 * 32604 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 32605 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 32606 */ sendAccessibilityEventUnchecked(@onNull View host, @NonNull AccessibilityEvent event)32607 public void sendAccessibilityEventUnchecked(@NonNull View host, 32608 @NonNull AccessibilityEvent event) { 32609 host.sendAccessibilityEventUncheckedInternal(event); 32610 } 32611 32612 /** 32613 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 32614 * to its children for adding their text content to the event. 32615 * <p> 32616 * The default implementation behaves as 32617 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 32618 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 32619 * the case of no accessibility delegate been set. 32620 * </p> 32621 * 32622 * @param host The View hosting the delegate. 32623 * @param event The event. 32624 * @return True if the event population was completed. 32625 * 32626 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 32627 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 32628 */ dispatchPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)32629 public boolean dispatchPopulateAccessibilityEvent(@NonNull View host, 32630 @NonNull AccessibilityEvent event) { 32631 return host.dispatchPopulateAccessibilityEventInternal(event); 32632 } 32633 32634 /** 32635 * Gives a chance to the host View to populate the accessibility event with its 32636 * text content. 32637 * <p> 32638 * The default implementation behaves as 32639 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 32640 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 32641 * the case of no accessibility delegate been set. 32642 * </p> 32643 * 32644 * @param host The View hosting the delegate. 32645 * @param event The accessibility event which to populate. 32646 * 32647 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 32648 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 32649 */ onPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)32650 public void onPopulateAccessibilityEvent(@NonNull View host, 32651 @NonNull AccessibilityEvent event) { 32652 host.onPopulateAccessibilityEventInternal(event); 32653 } 32654 32655 /** 32656 * Initializes an {@link AccessibilityEvent} with information about the 32657 * the host View which is the event source. 32658 * <p> 32659 * The default implementation behaves as 32660 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 32661 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 32662 * the case of no accessibility delegate been set. 32663 * </p> 32664 * 32665 * @param host The View hosting the delegate. 32666 * @param event The event to initialize. 32667 * 32668 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 32669 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 32670 */ onInitializeAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)32671 public void onInitializeAccessibilityEvent(@NonNull View host, 32672 @NonNull AccessibilityEvent event) { 32673 host.onInitializeAccessibilityEventInternal(event); 32674 } 32675 32676 /** 32677 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 32678 * <p> 32679 * The default implementation behaves as 32680 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 32681 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 32682 * the case of no accessibility delegate been set. 32683 * </p> 32684 * 32685 * @param host The View hosting the delegate. 32686 * @param info The instance to initialize. 32687 * 32688 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 32689 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 32690 */ onInitializeAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info)32691 public void onInitializeAccessibilityNodeInfo(@NonNull View host, 32692 @NonNull AccessibilityNodeInfo info) { 32693 host.onInitializeAccessibilityNodeInfoInternal(info); 32694 } 32695 32696 /** 32697 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 32698 * additional data. 32699 * <p> 32700 * This method only needs to be implemented if the View offers to provide additional data. 32701 * </p> 32702 * <p> 32703 * The default implementation behaves as 32704 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 32705 * for the case where no accessibility delegate is set. 32706 * </p> 32707 * 32708 * @param host The View hosting the delegate. Never {@code null}. 32709 * @param info The info to which to add the extra data. Never {@code null}. 32710 * @param extraDataKey A key specifying the type of extra data to add to the info. The 32711 * extra data should be added to the {@link Bundle} returned by 32712 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 32713 * {@code null}. 32714 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 32715 * May be {@code null} if the if the service provided no arguments. 32716 * 32717 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 32718 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)32719 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 32720 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 32721 @Nullable Bundle arguments) { 32722 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 32723 } 32724 32725 /** 32726 * Called when a child of the host View has requested sending an 32727 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 32728 * to augment the event. 32729 * <p> 32730 * The default implementation behaves as 32731 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 32732 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 32733 * the case of no accessibility delegate been set. 32734 * </p> 32735 * 32736 * @param host The View hosting the delegate. 32737 * @param child The child which requests sending the event. 32738 * @param event The event to be sent. 32739 * @return True if the event should be sent 32740 * 32741 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 32742 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 32743 */ onRequestSendAccessibilityEvent(@onNull ViewGroup host, @NonNull View child, @NonNull AccessibilityEvent event)32744 public boolean onRequestSendAccessibilityEvent(@NonNull ViewGroup host, @NonNull View child, 32745 @NonNull AccessibilityEvent event) { 32746 return host.onRequestSendAccessibilityEventInternal(child, event); 32747 } 32748 32749 /** 32750 * Gets the provider for managing a virtual view hierarchy rooted at this View 32751 * and reported to {@link android.accessibilityservice.AccessibilityService}s 32752 * that explore the window content. 32753 * <p> 32754 * The default implementation behaves as 32755 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 32756 * the case of no accessibility delegate been set. 32757 * </p> 32758 * 32759 * @return The provider. 32760 * 32761 * @see AccessibilityNodeProvider 32762 */ getAccessibilityNodeProvider( @onNull View host)32763 public @Nullable AccessibilityNodeProvider getAccessibilityNodeProvider( 32764 @NonNull View host) { 32765 return null; 32766 } 32767 32768 /** 32769 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 32770 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 32771 * This method is responsible for obtaining an accessibility node info from a 32772 * pool of reusable instances and calling 32773 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 32774 * view to initialize the former. 32775 * <p> 32776 * <strong>Note:</strong> The client is responsible for recycling the obtained 32777 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 32778 * creation. 32779 * </p> 32780 * <p> 32781 * The default implementation behaves as 32782 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 32783 * the case of no accessibility delegate been set. 32784 * </p> 32785 * @return A populated {@link AccessibilityNodeInfo}. 32786 * 32787 * @see AccessibilityNodeInfo 32788 * 32789 * @hide 32790 */ 32791 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) createAccessibilityNodeInfo(@onNull View host)32792 public AccessibilityNodeInfo createAccessibilityNodeInfo(@NonNull View host) { 32793 return host.createAccessibilityNodeInfoInternal(); 32794 } 32795 } 32796 32797 private static class MatchIdPredicate implements Predicate<View> { 32798 public int mId; 32799 32800 @Override test(View view)32801 public boolean test(View view) { 32802 return (view.mID == mId); 32803 } 32804 } 32805 32806 private static class MatchLabelForPredicate implements Predicate<View> { 32807 private int mLabeledId; 32808 32809 @Override test(View view)32810 public boolean test(View view) { 32811 return (view.mLabelForId == mLabeledId); 32812 } 32813 } 32814 32815 private static class SensitiveAutofillHintsHelper { 32816 /** 32817 * List of autofill hints deemed sensitive for screen protection during screen share. 32818 */ 32819 private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>(); 32820 static { 32821 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME); 32822 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO); 32823 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD); 32824 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER); 32825 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); 32826 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE); 32827 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY); 32828 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH); 32829 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR); 32830 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDENTIAL_MANAGER); 32831 } 32832 32833 /** 32834 * Whether View's autofill hints contains a sensitive autofill hint. 32835 * 32836 * @see #SENSITIVE_CONTENT_AUTOFILL_HINTS 32837 */ containsSensitiveAutofillHint(@ullable String[] autofillHints)32838 static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) { 32839 if (autofillHints == null) { 32840 return false; 32841 } 32842 32843 int size = autofillHints.length; 32844 for (int i = 0; i < size; i++) { 32845 if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) { 32846 return true; 32847 } 32848 } 32849 return false; 32850 } 32851 } 32852 32853 /** 32854 * Returns the current scroll capture hint for this view. 32855 * 32856 * @return the current scroll capture hint 32857 */ 32858 @ScrollCaptureHint getScrollCaptureHint()32859 public int getScrollCaptureHint() { 32860 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 32861 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 32862 } 32863 32864 /** 32865 * Sets the scroll capture hint for this View. These flags affect the search for a potential 32866 * scroll capture targets. 32867 * 32868 * @param hint the scrollCaptureHint flags value to set 32869 */ setScrollCaptureHint(@crollCaptureHint int hint)32870 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 32871 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 32872 // Since include/exclude are mutually exclusive, exclude takes precedence. 32873 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 32874 hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; 32875 } 32876 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 32877 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 32878 } 32879 32880 /** 32881 * Sets the callback to receive scroll capture requests. This component is the adapter between 32882 * the scroll capture API and application UI code. If no callback is set, the system may provide 32883 * an implementation. Any value provided here will take precedence over a system version. 32884 * <p> 32885 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 32886 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 32887 * <p> 32888 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 32889 * setting a custom callback to help ensure it is selected as the target. 32890 * 32891 * @param callback the new callback to assign 32892 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)32893 public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 32894 getListenerInfo().mScrollCaptureCallback = callback; 32895 } 32896 32897 /** {@hide} */ 32898 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)32899 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 32900 @NonNull Point windowOffset) { 32901 if (mAttachInfo == null) { 32902 return null; 32903 } 32904 if (mAttachInfo.mScrollCaptureInternal == null) { 32905 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 32906 } 32907 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 32908 windowOffset); 32909 } 32910 32911 /** 32912 * Dispatch a scroll capture search request down the view hierarchy. 32913 * 32914 * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to 32915 * the parent 32916 * @param windowOffset the offset of this view within the window 32917 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 32918 * results.accept} may be called zero or more times on the calling 32919 * thread before onScrollCaptureSearch returns 32920 */ dispatchScrollCaptureSearch( @onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)32921 public void dispatchScrollCaptureSearch( 32922 @NonNull Rect localVisibleRect, @NonNull Point windowOffset, 32923 @NonNull Consumer<ScrollCaptureTarget> targets) { 32924 onScrollCaptureSearch(localVisibleRect, windowOffset, targets); 32925 } 32926 32927 /** 32928 * Called when scroll capture is requested, to search for appropriate content to scroll. If 32929 * applicable, this view adds itself to the provided list for consideration, subject to the 32930 * flags set by {@link #setScrollCaptureHint}. 32931 * 32932 * @param localVisibleRect the local visible rect of this view 32933 * @param windowOffset the offset of localVisibleRect within the window 32934 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 32935 * results.accept} may be called zero or more times on the calling 32936 * thread before onScrollCaptureSearch returns 32937 * @throws IllegalStateException if this view is not attached to a window 32938 */ onScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)32939 public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, 32940 @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { 32941 int hint = getScrollCaptureHint(); 32942 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 32943 return; 32944 } 32945 boolean rectIsVisible = true; 32946 32947 // Apply clipBounds if present. 32948 if (mClipBounds != null) { 32949 rectIsVisible = localVisibleRect.intersect(mClipBounds); 32950 } 32951 if (!rectIsVisible) { 32952 return; 32953 } 32954 32955 // Get a callback provided by the framework, library or application. 32956 ScrollCaptureCallback callback = 32957 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 32958 32959 // Try framework support for standard scrolling containers. 32960 if (callback == null) { 32961 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 32962 } 32963 32964 // If found, then add it to the list. 32965 if (callback != null) { 32966 // Add to the list for consideration 32967 Point offset = new Point(windowOffset.x, windowOffset.y); 32968 Rect rect = new Rect(localVisibleRect); 32969 targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); 32970 } 32971 } 32972 32973 /** 32974 * Dump all private flags in readable format, useful for documentation and 32975 * consistency checking. 32976 */ dumpFlags()32977 private static void dumpFlags() { 32978 final HashMap<String, String> found = Maps.newHashMap(); 32979 try { 32980 for (Field field : View.class.getDeclaredFields()) { 32981 final int modifiers = field.getModifiers(); 32982 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 32983 if (field.getType().equals(int.class)) { 32984 final int value = field.getInt(null); 32985 dumpFlag(found, field.getName(), value); 32986 } else if (field.getType().equals(int[].class)) { 32987 final int[] values = (int[]) field.get(null); 32988 for (int i = 0; i < values.length; i++) { 32989 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 32990 } 32991 } 32992 } 32993 } 32994 } catch (IllegalAccessException e) { 32995 throw new RuntimeException(e); 32996 } 32997 32998 final ArrayList<String> keys = Lists.newArrayList(); 32999 keys.addAll(found.keySet()); 33000 Collections.sort(keys); 33001 for (String key : keys) { 33002 Log.d(VIEW_LOG_TAG, found.get(key)); 33003 } 33004 } 33005 dumpFlag(HashMap<String, String> found, String name, int value)33006 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 33007 // Sort flags by prefix, then by bits, always keeping unique keys 33008 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 33009 final int prefix = name.indexOf('_'); 33010 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 33011 final String output = bits + " " + name; 33012 found.put(key, output); 33013 } 33014 33015 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)33016 public void encode(@NonNull ViewHierarchyEncoder stream) { 33017 stream.beginObject(this); 33018 encodeProperties(stream); 33019 stream.endObject(); 33020 } 33021 33022 /** {@hide} */ 33023 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)33024 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 33025 Object resolveId = ViewDebug.resolveId(getContext(), mID); 33026 if (resolveId instanceof String) { 33027 stream.addProperty("id", (String) resolveId); 33028 } else { 33029 stream.addProperty("id", mID); 33030 } 33031 33032 stream.addProperty("misc:transformation.alpha", 33033 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 33034 stream.addProperty("misc:transitionName", getTransitionName()); 33035 33036 // layout 33037 stream.addProperty("layout:left", mLeft); 33038 stream.addProperty("layout:right", mRight); 33039 stream.addProperty("layout:top", mTop); 33040 stream.addProperty("layout:bottom", mBottom); 33041 stream.addProperty("layout:width", getWidth()); 33042 stream.addProperty("layout:height", getHeight()); 33043 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 33044 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 33045 stream.addProperty("layout:hasTransientState", hasTransientState()); 33046 stream.addProperty("layout:baseline", getBaseline()); 33047 33048 // layout params 33049 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 33050 if (layoutParams != null) { 33051 stream.addPropertyKey("layoutParams"); 33052 layoutParams.encode(stream); 33053 } 33054 33055 // scrolling 33056 stream.addProperty("scrolling:scrollX", mScrollX); 33057 stream.addProperty("scrolling:scrollY", mScrollY); 33058 33059 // padding 33060 stream.addProperty("padding:paddingLeft", mPaddingLeft); 33061 stream.addProperty("padding:paddingRight", mPaddingRight); 33062 stream.addProperty("padding:paddingTop", mPaddingTop); 33063 stream.addProperty("padding:paddingBottom", mPaddingBottom); 33064 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 33065 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 33066 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 33067 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 33068 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 33069 33070 // measurement 33071 stream.addProperty("measurement:minHeight", mMinHeight); 33072 stream.addProperty("measurement:minWidth", mMinWidth); 33073 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 33074 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 33075 33076 // drawing 33077 stream.addProperty("drawing:elevation", getElevation()); 33078 stream.addProperty("drawing:translationX", getTranslationX()); 33079 stream.addProperty("drawing:translationY", getTranslationY()); 33080 stream.addProperty("drawing:translationZ", getTranslationZ()); 33081 stream.addProperty("drawing:rotation", getRotation()); 33082 stream.addProperty("drawing:rotationX", getRotationX()); 33083 stream.addProperty("drawing:rotationY", getRotationY()); 33084 stream.addProperty("drawing:scaleX", getScaleX()); 33085 stream.addProperty("drawing:scaleY", getScaleY()); 33086 stream.addProperty("drawing:pivotX", getPivotX()); 33087 stream.addProperty("drawing:pivotY", getPivotY()); 33088 stream.addProperty("drawing:clipBounds", 33089 mClipBounds == null ? null : mClipBounds.toString()); 33090 stream.addProperty("drawing:opaque", isOpaque()); 33091 stream.addProperty("drawing:alpha", getAlpha()); 33092 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 33093 stream.addProperty("drawing:shadow", hasShadow()); 33094 stream.addProperty("drawing:solidColor", getSolidColor()); 33095 stream.addProperty("drawing:layerType", mLayerType); 33096 stream.addProperty("drawing:willNotDraw", willNotDraw()); 33097 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 33098 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 33099 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 33100 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 33101 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 33102 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 33103 33104 // focus 33105 stream.addProperty("focus:hasFocus", hasFocus()); 33106 stream.addProperty("focus:isFocused", isFocused()); 33107 stream.addProperty("focus:focusable", getFocusable()); 33108 stream.addProperty("focus:isFocusable", isFocusable()); 33109 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 33110 33111 stream.addProperty("misc:clickable", isClickable()); 33112 stream.addProperty("misc:pressed", isPressed()); 33113 stream.addProperty("misc:selected", isSelected()); 33114 stream.addProperty("misc:touchMode", isInTouchMode()); 33115 stream.addProperty("misc:hovered", isHovered()); 33116 stream.addProperty("misc:activated", isActivated()); 33117 33118 stream.addProperty("misc:visibility", getVisibility()); 33119 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 33120 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 33121 33122 stream.addProperty("misc:enabled", isEnabled()); 33123 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 33124 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 33125 33126 // theme attributes 33127 Resources.Theme theme = getContext().getTheme(); 33128 if (theme != null) { 33129 stream.addPropertyKey("theme"); 33130 theme.encode(stream); 33131 } 33132 33133 // view attribute information 33134 int n = mAttributes != null ? mAttributes.length : 0; 33135 stream.addProperty("meta:__attrCount__", n/2); 33136 for (int i = 0; i < n; i += 2) { 33137 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 33138 } 33139 33140 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 33141 33142 // text 33143 stream.addProperty("text:textDirection", getTextDirection()); 33144 stream.addProperty("text:textAlignment", getTextAlignment()); 33145 33146 // accessibility 33147 CharSequence contentDescription = getContentDescription(); 33148 stream.addUserProperty("accessibility:contentDescription", 33149 contentDescription == null ? "" : contentDescription.toString()); 33150 stream.addProperty("accessibility:labelFor", getLabelFor()); 33151 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 33152 } 33153 33154 /** 33155 * Determine if this view is rendered on a round wearable device and is the main view 33156 * on the screen. 33157 */ shouldDrawRoundScrollbar()33158 boolean shouldDrawRoundScrollbar() { 33159 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 33160 return false; 33161 } 33162 33163 final View rootView = getRootView(); 33164 final WindowInsets insets = getRootWindowInsets(); 33165 33166 int height = getHeight(); 33167 int width = getWidth(); 33168 int displayHeight = rootView.getHeight(); 33169 int displayWidth = rootView.getWidth(); 33170 33171 if (height != displayHeight || width != displayWidth) { 33172 return false; 33173 } 33174 33175 return true; 33176 } 33177 33178 /** 33179 * Sets the tooltip text which will be displayed in a small popup next to the view. 33180 * <p> 33181 * The tooltip will be displayed: 33182 * <ul> 33183 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 33184 * menu). </li> 33185 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 33186 * </ul> 33187 * <p> 33188 * <strong>Note:</strong> Do not override this method, as it will have no 33189 * effect on the text displayed in the tooltip. 33190 * 33191 * @param tooltipText the tooltip text, or null if no tooltip is required 33192 * @see #getTooltipText() 33193 * @attr ref android.R.styleable#View_tooltipText 33194 */ setTooltipText(@ullable CharSequence tooltipText)33195 public void setTooltipText(@Nullable CharSequence tooltipText) { 33196 if (TextUtils.isEmpty(tooltipText)) { 33197 setFlags(0, TOOLTIP); 33198 hideTooltip(); 33199 mTooltipInfo = null; 33200 } else { 33201 setFlags(TOOLTIP, TOOLTIP); 33202 if (mTooltipInfo == null) { 33203 mTooltipInfo = new TooltipInfo(); 33204 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 33205 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 33206 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 33207 mTooltipInfo.clearAnchorPos(); 33208 } 33209 mTooltipInfo.mTooltipText = tooltipText; 33210 } 33211 } 33212 33213 /** 33214 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 33215 */ 33216 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)33217 public void setTooltip(@Nullable CharSequence tooltipText) { 33218 setTooltipText(tooltipText); 33219 } 33220 33221 /** 33222 * Returns the view's tooltip text. 33223 * 33224 * <strong>Note:</strong> Do not override this method, as it will have no 33225 * effect on the text displayed in the tooltip. You must call 33226 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 33227 * 33228 * @return the tooltip text 33229 * @see #setTooltipText(CharSequence) 33230 * @attr ref android.R.styleable#View_tooltipText 33231 */ 33232 @InspectableProperty 33233 @Nullable getTooltipText()33234 public CharSequence getTooltipText() { 33235 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 33236 } 33237 33238 /** 33239 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 33240 */ 33241 @Nullable getTooltip()33242 public CharSequence getTooltip() { 33243 return getTooltipText(); 33244 } 33245 showTooltip(int x, int y, boolean fromLongClick)33246 private boolean showTooltip(int x, int y, boolean fromLongClick) { 33247 if (mAttachInfo == null || mTooltipInfo == null) { 33248 return false; 33249 } 33250 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 33251 return false; 33252 } 33253 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 33254 return false; 33255 } 33256 hideTooltip(); 33257 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 33258 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 33259 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 33260 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 33261 mAttachInfo.mTooltipHost = this; 33262 // The available accessibility actions have changed 33263 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 33264 return true; 33265 } 33266 33267 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hideTooltip()33268 void hideTooltip() { 33269 if (mTooltipInfo == null) { 33270 return; 33271 } 33272 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 33273 if (mTooltipInfo.mTooltipPopup == null) { 33274 return; 33275 } 33276 mTooltipInfo.mTooltipPopup.hide(); 33277 mTooltipInfo.mTooltipPopup = null; 33278 mTooltipInfo.mTooltipFromLongClick = false; 33279 mTooltipInfo.clearAnchorPos(); 33280 if (mAttachInfo != null) { 33281 mAttachInfo.mTooltipHost = null; 33282 } 33283 // The available accessibility actions have changed 33284 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 33285 } 33286 showLongClickTooltip(int x, int y)33287 private boolean showLongClickTooltip(int x, int y) { 33288 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 33289 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 33290 return showTooltip(x, y, true); 33291 } 33292 showHoverTooltip()33293 private boolean showHoverTooltip() { 33294 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 33295 } 33296 dispatchTooltipHoverEvent(MotionEvent event)33297 boolean dispatchTooltipHoverEvent(MotionEvent event) { 33298 if (mTooltipInfo == null) { 33299 return false; 33300 } 33301 switch(event.getAction()) { 33302 case MotionEvent.ACTION_HOVER_MOVE: 33303 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 33304 break; 33305 } 33306 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 33307 if (mTooltipInfo.mTooltipPopup == null) { 33308 // Schedule showing the tooltip after a timeout. 33309 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 33310 postDelayed(mTooltipInfo.mShowTooltipRunnable, 33311 ViewConfiguration.getHoverTooltipShowTimeout()); 33312 } 33313 33314 // Hide hover-triggered tooltip after a period of inactivity. 33315 // Match the timeout used by NativeInputManager to hide the mouse pointer 33316 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 33317 final int timeout; 33318 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 33319 == SYSTEM_UI_FLAG_LOW_PROFILE) { 33320 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 33321 } else { 33322 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 33323 } 33324 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 33325 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 33326 } 33327 return true; 33328 33329 case MotionEvent.ACTION_HOVER_EXIT: 33330 mTooltipInfo.clearAnchorPos(); 33331 if (!mTooltipInfo.mTooltipFromLongClick) { 33332 hideTooltip(); 33333 } 33334 break; 33335 } 33336 return false; 33337 } 33338 handleTooltipKey(KeyEvent event)33339 void handleTooltipKey(KeyEvent event) { 33340 switch (event.getAction()) { 33341 case KeyEvent.ACTION_DOWN: 33342 if (event.getRepeatCount() == 0) { 33343 hideTooltip(); 33344 } 33345 break; 33346 33347 case KeyEvent.ACTION_UP: 33348 handleTooltipUp(); 33349 break; 33350 } 33351 } 33352 handleTooltipUp()33353 private void handleTooltipUp() { 33354 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 33355 return; 33356 } 33357 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 33358 postDelayed(mTooltipInfo.mHideTooltipRunnable, 33359 ViewConfiguration.getLongPressTooltipHideTimeout()); 33360 } 33361 getFocusableAttribute(TypedArray attributes)33362 private int getFocusableAttribute(TypedArray attributes) { 33363 TypedValue val = new TypedValue(); 33364 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 33365 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 33366 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 33367 } else { 33368 return val.data; 33369 } 33370 } else { 33371 return FOCUSABLE_AUTO; 33372 } 33373 } 33374 33375 /** 33376 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 33377 * is not showing. 33378 * @hide 33379 */ 33380 @TestApi getTooltipView()33381 public View getTooltipView() { 33382 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 33383 return null; 33384 } 33385 return mTooltipInfo.mTooltipPopup.getContentView(); 33386 } 33387 33388 /** 33389 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 33390 * @hide 33391 */ 33392 @TestApi isDefaultFocusHighlightEnabled()33393 public static boolean isDefaultFocusHighlightEnabled() { 33394 return sUseDefaultFocusHighlight; 33395 } 33396 33397 /** 33398 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 33399 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 33400 * (visually on-top views first). 33401 * 33402 * @param evt the previously unhandled {@link KeyEvent}. 33403 * @return the {@link View} which consumed the event or {@code null} if not consumed. 33404 */ dispatchUnhandledKeyEvent(KeyEvent evt)33405 View dispatchUnhandledKeyEvent(KeyEvent evt) { 33406 if (onUnhandledKeyEvent(evt)) { 33407 return this; 33408 } 33409 return null; 33410 } 33411 33412 /** 33413 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 33414 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 33415 * this will dispatch into all the listeners registered via 33416 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 33417 * order (most recently added will receive events first). 33418 * 33419 * @param event An unhandled event. 33420 * @return {@code true} if the event was handled, {@code false} otherwise. 33421 * @see #addOnUnhandledKeyEventListener 33422 */ onUnhandledKeyEvent(@onNull KeyEvent event)33423 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 33424 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 33425 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 33426 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 33427 return true; 33428 } 33429 } 33430 } 33431 return false; 33432 } 33433 hasUnhandledKeyListener()33434 boolean hasUnhandledKeyListener() { 33435 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 33436 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 33437 } 33438 33439 /** 33440 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 33441 * UI thread. 33442 * 33443 * @param listener a receiver of unhandled {@link KeyEvent}s. 33444 * @see #removeOnUnhandledKeyEventListener 33445 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)33446 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 33447 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 33448 if (listeners == null) { 33449 listeners = new ArrayList<>(); 33450 getListenerInfo().mUnhandledKeyListeners = listeners; 33451 } 33452 listeners.add(listener); 33453 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 33454 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 33455 } 33456 } 33457 33458 /** 33459 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 33460 * UI thread. 33461 * 33462 * @param listener a receiver of unhandled {@link KeyEvent}s. 33463 * @see #addOnUnhandledKeyEventListener 33464 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)33465 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 33466 if (mListenerInfo != null) { 33467 if (mListenerInfo.mUnhandledKeyListeners != null 33468 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 33469 mListenerInfo.mUnhandledKeyListeners.remove(listener); 33470 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 33471 mListenerInfo.mUnhandledKeyListeners = null; 33472 if (mParent instanceof ViewGroup) { 33473 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 33474 } 33475 } 33476 } 33477 } 33478 } 33479 33480 /** 33481 * Set the view to be detached or not detached. 33482 * 33483 * @param detached Whether the view is detached. 33484 * 33485 * @hide 33486 */ setDetached(boolean detached)33487 protected void setDetached(boolean detached) { 33488 if (detached) { 33489 mPrivateFlags4 |= PFLAG4_DETACHED; 33490 } else { 33491 mPrivateFlags4 &= ~PFLAG4_DETACHED; 33492 } 33493 } 33494 33495 /** 33496 * Sets whether this view is a credential for Credential Manager purposes. 33497 * 33498 * <p>See {@link #isCredential()}. 33499 * 33500 * @param isCredential Whether the view is a credential. 33501 * 33502 * @attr ref android.R.styleable#View_isCredential 33503 */ setIsCredential(boolean isCredential)33504 public void setIsCredential(boolean isCredential) { 33505 if (isCredential) { 33506 mPrivateFlags4 |= PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; 33507 } else { 33508 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; 33509 } 33510 } 33511 33512 /** 33513 * Gets the mode for determining whether this view is a credential. 33514 * 33515 * <p>See {@link #setIsCredential(boolean)}. 33516 * 33517 * @return false by default, or value passed to {@link #setIsCredential(boolean)}. 33518 * 33519 * @attr ref android.R.styleable#View_isCredential 33520 */ isCredential()33521 public boolean isCredential() { 33522 return ((mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER) 33523 == PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER); 33524 } 33525 33526 // TODO(316208691): Revive following removed API docs. 33527 // @see EditorInfo#setStylusHandwritingEnabled(boolean) 33528 /** 33529 * Set whether this view enables automatic handwriting initiation. 33530 * 33531 * For a view with an active {@link InputConnection}, if auto handwriting is enabled then 33532 * stylus movement within its view boundary will automatically trigger the handwriting mode. 33533 * Check {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} for 33534 * more details about handwriting mode. 33535 * 33536 * If the View wants to initiate handwriting mode by itself, it can set this field to 33537 * {@code false} and call 33538 * {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} when there 33539 * is stylus movement detected. 33540 * 33541 * Note that this attribute has no effect on the View's children. For example, if a 33542 * {@link ViewGroup} disables auto handwriting but its children set auto handwriting to true, 33543 * auto handwriting will still work for the children, and vice versa. 33544 * 33545 * @see #onCreateInputConnection(EditorInfo) 33546 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 33547 * @param enabled whether auto handwriting initiation is enabled for this view. 33548 * @attr ref android.R.styleable#View_autoHandwritingEnabled 33549 */ setAutoHandwritingEnabled(boolean enabled)33550 public void setAutoHandwritingEnabled(boolean enabled) { 33551 if (enabled) { 33552 mPrivateFlags4 |= PFLAG4_AUTO_HANDWRITING_ENABLED; 33553 } else { 33554 mPrivateFlags4 &= ~PFLAG4_AUTO_HANDWRITING_ENABLED; 33555 } 33556 updatePositionUpdateListener(); 33557 postUpdate(this::updateHandwritingArea); 33558 } 33559 33560 /** 33561 * Return whether the View allows automatic handwriting initiation. Returns true if automatic 33562 * handwriting initiation is enabled, and vice versa. 33563 * @see #setAutoHandwritingEnabled(boolean) 33564 */ isAutoHandwritingEnabled()33565 public boolean isAutoHandwritingEnabled() { 33566 return (mPrivateFlags4 & PFLAG4_AUTO_HANDWRITING_ENABLED) 33567 == PFLAG4_AUTO_HANDWRITING_ENABLED; 33568 } 33569 33570 /** 33571 * Return whether the stylus handwriting is available for this View. 33572 * @hide 33573 */ isStylusHandwritingAvailable()33574 public boolean isStylusHandwritingAvailable() { 33575 return getContext().getSystemService(InputMethodManager.class) 33576 .isStylusHandwritingAvailable(); 33577 } 33578 setTraversalTracingEnabled(boolean enabled)33579 private void setTraversalTracingEnabled(boolean enabled) { 33580 if (enabled) { 33581 if (mTracingStrings == null) { 33582 mTracingStrings = new ViewTraversalTracingStrings(this); 33583 } 33584 mPrivateFlags4 |= PFLAG4_TRAVERSAL_TRACING_ENABLED; 33585 } else { 33586 mPrivateFlags4 &= ~PFLAG4_TRAVERSAL_TRACING_ENABLED; 33587 } 33588 } 33589 isTraversalTracingEnabled()33590 private boolean isTraversalTracingEnabled() { 33591 return (mPrivateFlags4 & PFLAG4_TRAVERSAL_TRACING_ENABLED) 33592 == PFLAG4_TRAVERSAL_TRACING_ENABLED; 33593 } 33594 setRelayoutTracingEnabled(boolean enabled)33595 private void setRelayoutTracingEnabled(boolean enabled) { 33596 if (enabled) { 33597 if (mTracingStrings == null) { 33598 mTracingStrings = new ViewTraversalTracingStrings(this); 33599 } 33600 mPrivateFlags4 |= PFLAG4_RELAYOUT_TRACING_ENABLED; 33601 } else { 33602 mPrivateFlags4 &= ~PFLAG4_RELAYOUT_TRACING_ENABLED; 33603 } 33604 } 33605 isRelayoutTracingEnabled()33606 private boolean isRelayoutTracingEnabled() { 33607 return (mPrivateFlags4 & PFLAG4_RELAYOUT_TRACING_ENABLED) 33608 == PFLAG4_RELAYOUT_TRACING_ENABLED; 33609 } 33610 33611 /** 33612 * Collects a {@link ViewTranslationRequest} which represents the content to be translated in 33613 * the view. 33614 * 33615 * <p>The default implementation does nothing.</p> 33616 * 33617 * @param supportedFormats the supported translation formats. For now, the only possible value 33618 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 33619 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be used to 33620 * collect the information to be translated in the view. The {@code requestsCollector} only 33621 * accepts one request; an IllegalStateException is thrown if more than one 33622 * {@link ViewTranslationRequest} is submitted to it. The {@link AutofillId} must be set on the 33623 * {@link ViewTranslationRequest}. 33624 */ onCreateViewTranslationRequest(@onNull @ataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)33625 public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, 33626 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 33627 } 33628 33629 /** 33630 * Collects {@link ViewTranslationRequest}s which represents the content to be translated 33631 * for the virtual views in the host view. This is called if this view returned a virtual 33632 * view structure from {@link #onProvideContentCaptureStructure} and the system determined that 33633 * those virtual views were relevant for translation. 33634 * 33635 * <p>The default implementation does nothing.</p> 33636 * 33637 * @param virtualIds the virtual view ids which represents the virtual views in the host 33638 * view. 33639 * @param supportedFormats the supported translation formats. For now, the only possible value 33640 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 33641 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called 33642 * multiple times to collect the information to be translated in the host view. One 33643 * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must 33644 * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this 33645 * Consumer after the method returns. 33646 */ 33647 @SuppressLint("NullableCollection") onCreateVirtualViewTranslationRequests(@onNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)33648 public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, 33649 @NonNull @DataFormat int[] supportedFormats, 33650 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 33651 // no-op 33652 } 33653 33654 /** 33655 * Returns a {@link ViewTranslationCallback} that is used to display the translated information 33656 * or {@code null} if this View doesn't support translation. 33657 * 33658 * @hide 33659 */ 33660 @Nullable getViewTranslationCallback()33661 public ViewTranslationCallback getViewTranslationCallback() { 33662 return mViewTranslationCallback; 33663 } 33664 33665 /** 33666 * Sets a {@link ViewTranslationCallback} that is used to display/hide the translated 33667 * information. Developers can provide the customized implementation for show/hide translated 33668 * information. 33669 * 33670 * @param callback a {@link ViewTranslationCallback} that is used to control how to display the 33671 * translated information 33672 */ setViewTranslationCallback(@onNull ViewTranslationCallback callback)33673 public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { 33674 mViewTranslationCallback = callback; 33675 } 33676 33677 /** 33678 * Clear the {@link ViewTranslationCallback} from this view. 33679 */ clearViewTranslationCallback()33680 public void clearViewTranslationCallback() { 33681 mViewTranslationCallback = null; 33682 } 33683 33684 /** 33685 * Returns the {@link ViewTranslationResponse} associated with this view. The response will be 33686 * set when the translation is done then {@link #onViewTranslationResponse} is called. The 33687 * {@link ViewTranslationCallback} can use to get {@link ViewTranslationResponse} to display the 33688 * translated information. 33689 * 33690 * @return a {@link ViewTranslationResponse} that contains the translated information associated 33691 * with this view or {@code null} if this View doesn't have the translation. 33692 */ 33693 @Nullable getViewTranslationResponse()33694 public ViewTranslationResponse getViewTranslationResponse() { 33695 return mViewTranslationResponse; 33696 } 33697 33698 /** 33699 * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated 33700 * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that 33701 * the {@link ViewTranslationResponse} can be used to display the translation when the system 33702 * calls {@link ViewTranslationCallback#onShowTranslation}. 33703 * 33704 * <p> The default implementation will set the ViewTranslationResponse that can be get from 33705 * {@link View#getViewTranslationResponse}. </p> 33706 * 33707 * @param response a {@link ViewTranslationResponse} that contains the translated information 33708 * which can be shown in the view. 33709 */ onViewTranslationResponse(@onNull ViewTranslationResponse response)33710 public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { 33711 mViewTranslationResponse = response; 33712 } 33713 33714 /** 33715 * Clears the ViewTranslationResponse stored by the default implementation of {@link 33716 * #onViewTranslationResponse}. 33717 * 33718 * @hide 33719 */ clearViewTranslationResponse()33720 public void clearViewTranslationResponse() { 33721 mViewTranslationResponse = null; 33722 } 33723 33724 /** 33725 * Called when the content from {@link View#onCreateVirtualViewTranslationRequests} had been 33726 * translated by the TranslationService. 33727 * 33728 * <p> The default implementation does nothing.</p> 33729 * 33730 * @param response a {@link ViewTranslationResponse} SparseArray for the request that send by 33731 * {@link View#onCreateVirtualViewTranslationRequests} that contains the translated information 33732 * which can be shown in the view. The key of SparseArray is the virtual child ids. 33733 */ onVirtualViewTranslationResponses( @onNull LongSparseArray<ViewTranslationResponse> response)33734 public void onVirtualViewTranslationResponses( 33735 @NonNull LongSparseArray<ViewTranslationResponse> response) { 33736 // no-op 33737 } 33738 33739 /** 33740 * Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing 33741 * the hierarchy when the app requests ui translation. Typically, this method should only be 33742 * overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other 33743 * classes should override {@link View#onCreateViewTranslationRequest} for normal view or 33744 * override {@link View#onVirtualViewTranslationResponses} for view contains virtual children. 33745 * When requested to start the ui translation, the system will call this method to traverse the 33746 * view hierarchy to collect {@link ViewTranslationRequest}s and create a 33747 * {@link android.view.translation.Translator} to translate the requests. All the 33748 * {@link ViewTranslationRequest}s must be added when the traversal is done. 33749 * 33750 * <p> The default implementation calls {@link View#onCreateViewTranslationRequest} for normal 33751 * view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual 33752 * children to build {@link ViewTranslationRequest} if the view should be translated. 33753 * The view is marked as having {@link #setHasTransientState(boolean) transient state} so that 33754 * recycling of views doesn't prevent the system from attaching the response to it. Therefore, 33755 * if overriding this method, you should set or reset the transient state. </p> 33756 * 33757 * @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or 33758 * {@code null} if the view doesn't have virtual child that should be translated. The virtual 33759 * child ids are the same virtual ids provided by ContentCapture. 33760 * @param supportedFormats the supported translation formats. For now, the only possible value 33761 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 33762 * @param capability a {@link TranslationCapability} that holds translation capability. 33763 * information, e.g. source spec, target spec. 33764 * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose. 33765 */ dispatchCreateViewTranslationRequest(@onNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests)33766 public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, 33767 @NonNull @DataFormat int[] supportedFormats, 33768 @NonNull TranslationCapability capability, 33769 @NonNull List<ViewTranslationRequest> requests) { 33770 AutofillId autofillId = getAutofillId(); 33771 if (viewIds.containsKey(autofillId)) { 33772 if (viewIds.get(autofillId) == null) { 33773 // TODO: avoiding the allocation per view 33774 onCreateViewTranslationRequest(supportedFormats, 33775 new ViewTranslationRequestConsumer(requests)); 33776 } else { 33777 onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, 33778 request -> { 33779 requests.add(request); 33780 }); 33781 } 33782 } 33783 } 33784 33785 private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { 33786 private final List<ViewTranslationRequest> mRequests; 33787 private boolean mCalled; 33788 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests)33789 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { 33790 mRequests = requests; 33791 } 33792 33793 @Override accept(ViewTranslationRequest request)33794 public void accept(ViewTranslationRequest request) { 33795 if (mCalled) { 33796 throw new IllegalStateException("The translation Consumer is not reusable."); 33797 } 33798 mCalled = true; 33799 if (request != null && request.getKeys().size() > 0) { 33800 mRequests.add(request); 33801 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 33802 Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " 33803 + getAutofillId()); 33804 } 33805 setHasTransientState(true); 33806 setHasTranslationTransientState(true); 33807 } 33808 } 33809 } 33810 33811 /** 33812 * Called to generate a {@link DisplayHash} for this view. 33813 * 33814 * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of 33815 * the values returned from 33816 * {@link DisplayHashManager#getSupportedHashAlgorithms()} 33817 * @param bounds The bounds for the content within the View to generate the hash for. If 33818 * bounds are null, the entire View's bounds will be used. If empty, it will 33819 * invoke the callback 33820 * {@link DisplayHashResultCallback#onDisplayHashError} with error 33821 * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} 33822 * @param executor The executor that the callback should be invoked on. 33823 * @param callback The callback to handle the results of generating the display hash 33824 */ generateDisplayHash(@onNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback)33825 public void generateDisplayHash(@NonNull String hashAlgorithm, 33826 @Nullable Rect bounds, @NonNull Executor executor, 33827 @NonNull DisplayHashResultCallback callback) { 33828 IWindowSession session = getWindowSession(); 33829 if (session == null) { 33830 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 33831 return; 33832 } 33833 IWindow window = getWindow(); 33834 if (window == null) { 33835 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 33836 return; 33837 } 33838 33839 Rect visibleBounds = new Rect(); 33840 getGlobalVisibleRect(visibleBounds); 33841 33842 if (bounds != null && bounds.isEmpty()) { 33843 callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); 33844 return; 33845 } 33846 33847 if (bounds != null) { 33848 bounds.offset(visibleBounds.left, visibleBounds.top); 33849 visibleBounds.intersectUnchecked(bounds); 33850 } 33851 33852 if (visibleBounds.isEmpty()) { 33853 callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); 33854 return; 33855 } 33856 33857 RemoteCallback remoteCallback = new RemoteCallback(result -> 33858 executor.execute(() -> { 33859 DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH, android.view.displayhash.DisplayHash.class); 33860 int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, 33861 DISPLAY_HASH_ERROR_UNKNOWN); 33862 if (displayHash != null) { 33863 callback.onDisplayHashResult(displayHash); 33864 } else { 33865 callback.onDisplayHashError(errorCode); 33866 } 33867 })); 33868 33869 try { 33870 session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); 33871 } catch (RemoteException e) { 33872 Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); 33873 callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); 33874 } 33875 } 33876 33877 /** 33878 * The AttachedSurfaceControl itself is not a View, it is just the interface to the 33879 * windowing-system object that contains the entire view hierarchy. 33880 * For the root View of a given hierarchy see {@link #getRootView}. 33881 33882 * @return The {@link android.view.AttachedSurfaceControl} interface for this View. 33883 * This will only return a non-null value when called between {@link #onAttachedToWindow} 33884 * and {@link #onDetachedFromWindow}. 33885 */ getRootSurfaceControl()33886 public @Nullable AttachedSurfaceControl getRootSurfaceControl() { 33887 if (mAttachInfo != null) { 33888 return mAttachInfo.getRootSurfaceControl(); 33889 } 33890 return null; 33891 } 33892 33893 /** 33894 * Used to calculate the frame rate category of a View. 33895 * 33896 * @hide 33897 */ calculateFrameRateCategory()33898 protected int calculateFrameRateCategory() { 33899 int category; 33900 switch (getViewRootImpl().intermittentUpdateState()) { 33901 case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> category = 33902 FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_INTERMITTENT; 33903 case ViewRootImpl.INTERMITTENT_STATE_NOT_INTERMITTENT -> 33904 category = mSizeBasedFrameRateCategoryAndReason; 33905 default -> category = mLastFrameRateCategory; 33906 } 33907 return category; 33908 } 33909 33910 /** 33911 * Used to vote the preferred frame rate and frame rate category to ViewRootImpl 33912 * 33913 * @hide 33914 */ votePreferredFrameRate()33915 protected void votePreferredFrameRate() { 33916 // use toolkitSetFrameRate flag to gate the change 33917 ViewRootImpl viewRootImpl = getViewRootImpl(); 33918 if (viewRootImpl == null) { 33919 return; // can't vote if not connected 33920 } 33921 float velocity = mFrameContentVelocity; 33922 final float frameRate = mPreferredFrameRate; 33923 ViewParent parent = mParent; 33924 if (velocity <= 0 && Float.isNaN(frameRate)) { 33925 // The most common case is when nothing is set, so this special case is called 33926 // often. 33927 if (mAttachInfo.mViewVelocityApi 33928 && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == ( 33929 PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft 33930 || mLastFrameTop != mTop) 33931 && viewRootImpl.shouldCheckFrameRate(false) 33932 && parent instanceof View 33933 && ((View) parent).mFrameContentVelocity <= 0) { 33934 viewRootImpl.votePreferredFrameRate(MAX_FRAME_RATE, FRAME_RATE_COMPATIBILITY_GTE); 33935 } 33936 if (viewRootImpl.shouldCheckFrameRateCategory()) { 33937 int frameRateCategory = calculateFrameRateCategory(); 33938 int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK; 33939 int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK; 33940 viewRootImpl.votePreferredFrameRateCategory(category, reason, this); 33941 mLastFrameRateCategory = frameRateCategory; 33942 } 33943 mLastFrameLeft = mLeft; 33944 mLastFrameTop = mTop; 33945 return; 33946 } 33947 if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)) { 33948 float velocityFrameRate = 0f; 33949 if (mAttachInfo.mViewVelocityApi) { 33950 if (velocity < 0f 33951 && ((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == ( 33952 PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft 33953 || mLastFrameTop != mTop) 33954 && mParent instanceof View 33955 && ((View) mParent).mFrameContentVelocity <= 0 33956 ) { 33957 // This current calculation is very simple. If something on the screen 33958 // moved, then it votes for the highest velocity. 33959 velocityFrameRate = MAX_FRAME_RATE; 33960 } else if (velocity > 0f) { 33961 velocityFrameRate = convertVelocityToFrameRate(velocity); 33962 } 33963 } 33964 if (velocityFrameRate > 0f || frameRate > 0f) { 33965 int compatibility; 33966 float frameRateToSet; 33967 if (frameRate >= velocityFrameRate) { 33968 compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 33969 frameRateToSet = frameRate; 33970 } else { 33971 compatibility = FRAME_RATE_COMPATIBILITY_GTE; 33972 frameRateToSet = velocityFrameRate; 33973 } 33974 viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); 33975 } 33976 } 33977 33978 if (viewRootImpl.shouldCheckFrameRateCategory()) { 33979 if (sToolkitMetricsForFrameRateDecisionFlagValue) { 33980 int width = mRight - mLeft; 33981 int height = mBottom - mTop; 33982 float sizePercentage = width * height / mAttachInfo.mDisplayPixelCount; 33983 viewRootImpl.recordViewPercentage(sizePercentage); 33984 } 33985 33986 int frameRateCategory; 33987 if (Float.isNaN(frameRate)) { 33988 frameRateCategory = calculateFrameRateCategory(); 33989 } else if (frameRate < 0) { 33990 switch ((int) frameRate) { 33991 case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE -> 33992 frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE 33993 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 33994 case (int) REQUESTED_FRAME_RATE_CATEGORY_LOW -> 33995 frameRateCategory = FRAME_RATE_CATEGORY_LOW 33996 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 33997 case (int) REQUESTED_FRAME_RATE_CATEGORY_NORMAL -> 33998 frameRateCategory = FRAME_RATE_CATEGORY_NORMAL 33999 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34000 case (int) REQUESTED_FRAME_RATE_CATEGORY_HIGH -> 34001 frameRateCategory = FRAME_RATE_CATEGORY_HIGH 34002 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34003 default -> { 34004 // invalid frame rate, use default 34005 int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue 34006 ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; 34007 frameRateCategory = category 34008 | FRAME_RATE_CATEGORY_REASON_INVALID; 34009 } 34010 } 34011 } else { 34012 // Category doesn't control it. It is directly controlled by frame rate 34013 frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE 34014 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34015 } 34016 34017 int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK; 34018 int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK; 34019 viewRootImpl.votePreferredFrameRateCategory(category, reason, this); 34020 mLastFrameRateCategory = frameRateCategory; 34021 } 34022 mLastFrameLeft = mLeft; 34023 mLastFrameTop = mTop; 34024 } 34025 convertVelocityToFrameRate(float velocityPps)34026 private float convertVelocityToFrameRate(float velocityPps) { 34027 // From UXR study, premium experience is: 34028 // 1500+ dp/s: 120fps 34029 // 0 - 1500 dp/s: 80fps 34030 // OEMs are likely to modify this to balance battery and user experience for their 34031 // specific device. 34032 float density = mAttachInfo.mDensity; 34033 float velocityDps = velocityPps / density; 34034 return (velocityDps >= 1500f) ? MAX_FRAME_RATE : 80f; 34035 } 34036 34037 /** 34038 * Set the current velocity of the View, we only track positive value. 34039 * We will use the velocity information to adjust the frame rate when applicable. 34040 * For example, we could potentially lower the frame rate when 34041 * the velocity of a fling gesture becomes slower. 34042 * Note that this is only valid till the next drawn frame. 34043 * 34044 * @param pixelsPerSecond how many pixels move per second. 34045 */ 34046 @FlaggedApi(FLAG_VIEW_VELOCITY_API) setFrameContentVelocity(float pixelsPerSecond)34047 public void setFrameContentVelocity(float pixelsPerSecond) { 34048 if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) { 34049 mFrameContentVelocity = Math.abs(pixelsPerSecond); 34050 34051 if (sToolkitMetricsForFrameRateDecisionFlagValue) { 34052 Trace.setCounter("Set frame velocity", (long) mFrameContentVelocity); 34053 } 34054 } 34055 } 34056 34057 /** 34058 * Get the current velocity of the View. 34059 * The value should always be greater than or equal to 0. 34060 * Note that this is only valid till the next drawn frame. 34061 * 34062 * @return 0 by default, or value passed to {@link #setFrameContentVelocity(float)}. 34063 */ 34064 @FlaggedApi(FLAG_VIEW_VELOCITY_API) getFrameContentVelocity()34065 public float getFrameContentVelocity() { 34066 if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) { 34067 return Math.max(mFrameContentVelocity, 0f); 34068 } 34069 return 0; 34070 } 34071 34072 /** 34073 * You can set the preferred frame rate for a View using a positive number 34074 * or by specifying the preferred frame rate category using constants, including 34075 * REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE, REQUESTED_FRAME_RATE_CATEGORY_LOW, 34076 * REQUESTED_FRAME_RATE_CATEGORY_NORMAL, REQUESTED_FRAME_RATE_CATEGORY_HIGH. 34077 * Keep in mind that the preferred frame rate affects the frame rate for the next frame, 34078 * so use this method carefully. It's important to note that the preference is valid as 34079 * long as the View is invalidated. 34080 * 34081 * @param frameRate the preferred frame rate of the view. 34082 */ 34083 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) setRequestedFrameRate(float frameRate)34084 public void setRequestedFrameRate(float frameRate) { 34085 if (sToolkitSetFrameRateReadOnlyFlagValue) { 34086 mPreferredFrameRate = frameRate; 34087 } 34088 } 34089 34090 /** 34091 * Get the current preferred frame rate of the View. 34092 * The value could be negative when preferred frame rate category is set 34093 * instead of perferred frame rate. 34094 * The frame rate category includes 34095 * REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE, REQUESTED_FRAME_RATE_CATEGORY_LOW, 34096 * REQUESTED_FRAME_RATE_CATEGORY_NORMAL, and REQUESTED_FRAME_RATE_CATEGORY_HIGH. 34097 * Note that the frame rate value is valid as long as the View is invalidated. 34098 * 34099 * @return REQUESTED_FRAME_RATE_CATEGORY_DEFAULT by default, 34100 * or value passed to {@link #setRequestedFrameRate(float)}. 34101 */ 34102 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) getRequestedFrameRate()34103 public float getRequestedFrameRate() { 34104 if (sToolkitSetFrameRateReadOnlyFlagValue) { 34105 return mPreferredFrameRate; 34106 } 34107 return 0; 34108 } 34109 } 34110