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 java.lang.Math.max; 20 21 import android.animation.AnimatorInflater; 22 import android.animation.StateListAnimator; 23 import android.annotation.CallSuper; 24 import android.annotation.ColorInt; 25 import android.annotation.DrawableRes; 26 import android.annotation.FloatRange; 27 import android.annotation.IdRes; 28 import android.annotation.IntDef; 29 import android.annotation.IntRange; 30 import android.annotation.LayoutRes; 31 import android.annotation.NonNull; 32 import android.annotation.Nullable; 33 import android.annotation.Size; 34 import android.annotation.TestApi; 35 import android.annotation.UiThread; 36 import android.content.ClipData; 37 import android.content.Context; 38 import android.content.ContextWrapper; 39 import android.content.Intent; 40 import android.content.res.ColorStateList; 41 import android.content.res.Configuration; 42 import android.content.res.Resources; 43 import android.content.res.TypedArray; 44 import android.graphics.Bitmap; 45 import android.graphics.Canvas; 46 import android.graphics.Color; 47 import android.graphics.Insets; 48 import android.graphics.Interpolator; 49 import android.graphics.LinearGradient; 50 import android.graphics.Matrix; 51 import android.graphics.Outline; 52 import android.graphics.Paint; 53 import android.graphics.PixelFormat; 54 import android.graphics.Point; 55 import android.graphics.PorterDuff; 56 import android.graphics.PorterDuffXfermode; 57 import android.graphics.Rect; 58 import android.graphics.RectF; 59 import android.graphics.Region; 60 import android.graphics.Shader; 61 import android.graphics.drawable.ColorDrawable; 62 import android.graphics.drawable.Drawable; 63 import android.hardware.display.DisplayManagerGlobal; 64 import android.net.Uri; 65 import android.os.Build; 66 import android.os.Bundle; 67 import android.os.Handler; 68 import android.os.IBinder; 69 import android.os.Message; 70 import android.os.Parcel; 71 import android.os.Parcelable; 72 import android.os.RemoteException; 73 import android.os.SystemClock; 74 import android.os.SystemProperties; 75 import android.os.Trace; 76 import android.text.TextUtils; 77 import android.util.AttributeSet; 78 import android.util.FloatProperty; 79 import android.util.LayoutDirection; 80 import android.util.Log; 81 import android.util.LongSparseLongArray; 82 import android.util.Pools.SynchronizedPool; 83 import android.util.Property; 84 import android.util.SparseArray; 85 import android.util.StateSet; 86 import android.util.SuperNotCalledException; 87 import android.util.TypedValue; 88 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 89 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 90 import android.view.AccessibilityIterators.TextSegmentIterator; 91 import android.view.AccessibilityIterators.WordTextSegmentIterator; 92 import android.view.ContextMenu.ContextMenuInfo; 93 import android.view.accessibility.AccessibilityEvent; 94 import android.view.accessibility.AccessibilityEventSource; 95 import android.view.accessibility.AccessibilityManager; 96 import android.view.accessibility.AccessibilityNodeInfo; 97 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 98 import android.view.accessibility.AccessibilityNodeProvider; 99 import android.view.accessibility.AccessibilityWindowInfo; 100 import android.view.animation.Animation; 101 import android.view.animation.AnimationUtils; 102 import android.view.animation.Transformation; 103 import android.view.autofill.AutofillId; 104 import android.view.autofill.AutofillManager; 105 import android.view.autofill.AutofillValue; 106 import android.view.inputmethod.EditorInfo; 107 import android.view.inputmethod.InputConnection; 108 import android.view.inputmethod.InputMethodManager; 109 import android.widget.Checkable; 110 import android.widget.FrameLayout; 111 import android.widget.ScrollBarDrawable; 112 113 import com.android.internal.R; 114 import com.android.internal.view.TooltipPopup; 115 import com.android.internal.view.menu.MenuBuilder; 116 import com.android.internal.widget.ScrollBarUtils; 117 118 import com.google.android.collect.Lists; 119 import com.google.android.collect.Maps; 120 121 import java.lang.annotation.Retention; 122 import java.lang.annotation.RetentionPolicy; 123 import java.lang.ref.WeakReference; 124 import java.lang.reflect.Field; 125 import java.lang.reflect.InvocationTargetException; 126 import java.lang.reflect.Method; 127 import java.lang.reflect.Modifier; 128 import java.util.ArrayList; 129 import java.util.Arrays; 130 import java.util.Calendar; 131 import java.util.Collection; 132 import java.util.Collections; 133 import java.util.HashMap; 134 import java.util.List; 135 import java.util.Locale; 136 import java.util.Map; 137 import java.util.concurrent.CopyOnWriteArrayList; 138 import java.util.concurrent.atomic.AtomicInteger; 139 import java.util.function.Predicate; 140 141 /** 142 * <p> 143 * This class represents the basic building block for user interface components. A View 144 * occupies a rectangular area on the screen and is responsible for drawing and 145 * event handling. View is the base class for <em>widgets</em>, which are 146 * used to create interactive UI components (buttons, text fields, etc.). The 147 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 148 * are invisible containers that hold other Views (or other ViewGroups) and define 149 * their layout properties. 150 * </p> 151 * 152 * <div class="special reference"> 153 * <h3>Developer Guides</h3> 154 * <p>For information about using this class to develop your application's user interface, 155 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 156 * </div> 157 * 158 * <a name="Using"></a> 159 * <h3>Using Views</h3> 160 * <p> 161 * All of the views in a window are arranged in a single tree. You can add views 162 * either from code or by specifying a tree of views in one or more XML layout 163 * files. There are many specialized subclasses of views that act as controls or 164 * are capable of displaying text, images, or other content. 165 * </p> 166 * <p> 167 * Once you have created a tree of views, there are typically a few types of 168 * common operations you may wish to perform: 169 * <ul> 170 * <li><strong>Set properties:</strong> for example setting the text of a 171 * {@link android.widget.TextView}. The available properties and the methods 172 * that set them will vary among the different subclasses of views. Note that 173 * properties that are known at build time can be set in the XML layout 174 * files.</li> 175 * <li><strong>Set focus:</strong> The framework will handle moving focus in 176 * response to user input. To force focus to a specific view, call 177 * {@link #requestFocus}.</li> 178 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 179 * that will be notified when something interesting happens to the view. For 180 * example, all views will let you set a listener to be notified when the view 181 * gains or loses focus. You can register such a listener using 182 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 183 * Other view subclasses offer more specialized listeners. For example, a Button 184 * exposes a listener to notify clients when the button is clicked.</li> 185 * <li><strong>Set visibility:</strong> You can hide or show views using 186 * {@link #setVisibility(int)}.</li> 187 * </ul> 188 * </p> 189 * <p><em> 190 * Note: The Android framework is responsible for measuring, laying out and 191 * drawing views. You should not call methods that perform these actions on 192 * views yourself unless you are actually implementing a 193 * {@link android.view.ViewGroup}. 194 * </em></p> 195 * 196 * <a name="Lifecycle"></a> 197 * <h3>Implementing a Custom View</h3> 198 * 199 * <p> 200 * To implement a custom view, you will usually begin by providing overrides for 201 * some of the standard methods that the framework calls on all views. You do 202 * not need to override all of these methods. In fact, you can start by just 203 * overriding {@link #onDraw(android.graphics.Canvas)}. 204 * <table border="2" width="85%" align="center" cellpadding="5"> 205 * <thead> 206 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 207 * </thead> 208 * 209 * <tbody> 210 * <tr> 211 * <td rowspan="2">Creation</td> 212 * <td>Constructors</td> 213 * <td>There is a form of the constructor that are called when the view 214 * is created from code and a form that is called when the view is 215 * inflated from a layout file. The second form should parse and apply 216 * any attributes defined in the layout file. 217 * </td> 218 * </tr> 219 * <tr> 220 * <td><code>{@link #onFinishInflate()}</code></td> 221 * <td>Called after a view and all of its children has been inflated 222 * from XML.</td> 223 * </tr> 224 * 225 * <tr> 226 * <td rowspan="3">Layout</td> 227 * <td><code>{@link #onMeasure(int, int)}</code></td> 228 * <td>Called to determine the size requirements for this view and all 229 * of its children. 230 * </td> 231 * </tr> 232 * <tr> 233 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 234 * <td>Called when this view should assign a size and position to all 235 * of its children. 236 * </td> 237 * </tr> 238 * <tr> 239 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 240 * <td>Called when the size of this view has changed. 241 * </td> 242 * </tr> 243 * 244 * <tr> 245 * <td>Drawing</td> 246 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 247 * <td>Called when the view should render its content. 248 * </td> 249 * </tr> 250 * 251 * <tr> 252 * <td rowspan="4">Event processing</td> 253 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 254 * <td>Called when a new hardware key event occurs. 255 * </td> 256 * </tr> 257 * <tr> 258 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 259 * <td>Called when a hardware key up event occurs. 260 * </td> 261 * </tr> 262 * <tr> 263 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 264 * <td>Called when a trackball motion event occurs. 265 * </td> 266 * </tr> 267 * <tr> 268 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 269 * <td>Called when a touch screen motion event occurs. 270 * </td> 271 * </tr> 272 * 273 * <tr> 274 * <td rowspan="2">Focus</td> 275 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 276 * <td>Called when the view gains or loses focus. 277 * </td> 278 * </tr> 279 * 280 * <tr> 281 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 282 * <td>Called when the window containing the view gains or loses focus. 283 * </td> 284 * </tr> 285 * 286 * <tr> 287 * <td rowspan="3">Attaching</td> 288 * <td><code>{@link #onAttachedToWindow()}</code></td> 289 * <td>Called when the view is attached to a window. 290 * </td> 291 * </tr> 292 * 293 * <tr> 294 * <td><code>{@link #onDetachedFromWindow}</code></td> 295 * <td>Called when the view is detached from its window. 296 * </td> 297 * </tr> 298 * 299 * <tr> 300 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 301 * <td>Called when the visibility of the window containing the view 302 * has changed. 303 * </td> 304 * </tr> 305 * </tbody> 306 * 307 * </table> 308 * </p> 309 * 310 * <a name="IDs"></a> 311 * <h3>IDs</h3> 312 * Views may have an integer id associated with them. These ids are typically 313 * assigned in the layout XML files, and are used to find specific views within 314 * the view tree. A common pattern is to: 315 * <ul> 316 * <li>Define a Button in the layout file and assign it a unique ID. 317 * <pre> 318 * <Button 319 * android:id="@+id/my_button" 320 * android:layout_width="wrap_content" 321 * android:layout_height="wrap_content" 322 * android:text="@string/my_button_text"/> 323 * </pre></li> 324 * <li>From the onCreate method of an Activity, find the Button 325 * <pre class="prettyprint"> 326 * Button myButton = findViewById(R.id.my_button); 327 * </pre></li> 328 * </ul> 329 * <p> 330 * View IDs need not be unique throughout the tree, but it is good practice to 331 * ensure that they are at least unique within the part of the tree you are 332 * searching. 333 * </p> 334 * 335 * <a name="Position"></a> 336 * <h3>Position</h3> 337 * <p> 338 * The geometry of a view is that of a rectangle. A view has a location, 339 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 340 * two dimensions, expressed as a width and a height. The unit for location 341 * and dimensions is the pixel. 342 * </p> 343 * 344 * <p> 345 * It is possible to retrieve the location of a view by invoking the methods 346 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 347 * coordinate of the rectangle representing the view. The latter returns the 348 * top, or Y, coordinate of the rectangle representing the view. These methods 349 * both return the location of the view relative to its parent. For instance, 350 * when getLeft() returns 20, that means the view is located 20 pixels to the 351 * right of the left edge of its direct parent. 352 * </p> 353 * 354 * <p> 355 * In addition, several convenience methods are offered to avoid unnecessary 356 * computations, namely {@link #getRight()} and {@link #getBottom()}. 357 * These methods return the coordinates of the right and bottom edges of the 358 * rectangle representing the view. For instance, calling {@link #getRight()} 359 * is similar to the following computation: <code>getLeft() + getWidth()</code> 360 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 361 * </p> 362 * 363 * <a name="SizePaddingMargins"></a> 364 * <h3>Size, padding and margins</h3> 365 * <p> 366 * The size of a view is expressed with a width and a height. A view actually 367 * possess two pairs of width and height values. 368 * </p> 369 * 370 * <p> 371 * The first pair is known as <em>measured width</em> and 372 * <em>measured height</em>. These dimensions define how big a view wants to be 373 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 374 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 375 * and {@link #getMeasuredHeight()}. 376 * </p> 377 * 378 * <p> 379 * The second pair is simply known as <em>width</em> and <em>height</em>, or 380 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 381 * dimensions define the actual size of the view on screen, at drawing time and 382 * after layout. These values may, but do not have to, be different from the 383 * measured width and height. The width and height can be obtained by calling 384 * {@link #getWidth()} and {@link #getHeight()}. 385 * </p> 386 * 387 * <p> 388 * To measure its dimensions, a view takes into account its padding. The padding 389 * is expressed in pixels for the left, top, right and bottom parts of the view. 390 * Padding can be used to offset the content of the view by a specific amount of 391 * pixels. For instance, a left padding of 2 will push the view's content by 392 * 2 pixels to the right of the left edge. Padding can be set using the 393 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 394 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 395 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 396 * {@link #getPaddingEnd()}. 397 * </p> 398 * 399 * <p> 400 * Even though a view can define a padding, it does not provide any support for 401 * margins. However, view groups provide such a support. Refer to 402 * {@link android.view.ViewGroup} and 403 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 404 * </p> 405 * 406 * <a name="Layout"></a> 407 * <h3>Layout</h3> 408 * <p> 409 * Layout is a two pass process: a measure pass and a layout pass. The measuring 410 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 411 * of the view tree. Each view pushes dimension specifications down the tree 412 * during the recursion. At the end of the measure pass, every view has stored 413 * its measurements. The second pass happens in 414 * {@link #layout(int,int,int,int)} and is also top-down. During 415 * this pass each parent is responsible for positioning all of its children 416 * using the sizes computed in the measure pass. 417 * </p> 418 * 419 * <p> 420 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 421 * {@link #getMeasuredHeight()} values must be set, along with those for all of 422 * that view's descendants. A view's measured width and measured height values 423 * must respect the constraints imposed by the view's parents. This guarantees 424 * that at the end of the measure pass, all parents accept all of their 425 * children's measurements. A parent view may call measure() more than once on 426 * its children. For example, the parent may measure each child once with 427 * unspecified dimensions to find out how big they want to be, then call 428 * measure() on them again with actual numbers if the sum of all the children's 429 * unconstrained sizes is too big or too small. 430 * </p> 431 * 432 * <p> 433 * The measure pass uses two classes to communicate dimensions. The 434 * {@link MeasureSpec} class is used by views to tell their parents how they 435 * want to be measured and positioned. The base LayoutParams class just 436 * describes how big the view wants to be for both width and height. For each 437 * dimension, it can specify one of: 438 * <ul> 439 * <li> an exact number 440 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 441 * (minus padding) 442 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 443 * enclose its content (plus padding). 444 * </ul> 445 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 446 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 447 * an X and Y value. 448 * </p> 449 * 450 * <p> 451 * MeasureSpecs are used to push requirements down the tree from parent to 452 * child. A MeasureSpec can be in one of three modes: 453 * <ul> 454 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 455 * of a child view. For example, a LinearLayout may call measure() on its child 456 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 457 * tall the child view wants to be given a width of 240 pixels. 458 * <li>EXACTLY: This is used by the parent to impose an exact size on the 459 * child. The child must use this size, and guarantee that all of its 460 * descendants will fit within this size. 461 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 462 * child. The child must guarantee that it and all of its descendants will fit 463 * within this size. 464 * </ul> 465 * </p> 466 * 467 * <p> 468 * To initiate a layout, call {@link #requestLayout}. This method is typically 469 * called by a view on itself when it believes that is can no longer fit within 470 * its current bounds. 471 * </p> 472 * 473 * <a name="Drawing"></a> 474 * <h3>Drawing</h3> 475 * <p> 476 * Drawing is handled by walking the tree and recording the drawing commands of 477 * any View that needs to update. After this, the drawing commands of the 478 * entire tree are issued to screen, clipped to the newly damaged area. 479 * </p> 480 * 481 * <p> 482 * The tree is largely recorded and drawn in order, with parents drawn before 483 * (i.e., behind) their children, with siblings drawn in the order they appear 484 * in the tree. If you set a background drawable for a View, then the View will 485 * draw it before calling back to its <code>onDraw()</code> method. The child 486 * drawing order can be overridden with 487 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 488 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 489 * </p> 490 * 491 * <p> 492 * To force a view to draw, call {@link #invalidate()}. 493 * </p> 494 * 495 * <a name="EventHandlingThreading"></a> 496 * <h3>Event Handling and Threading</h3> 497 * <p> 498 * The basic cycle of a view is as follows: 499 * <ol> 500 * <li>An event comes in and is dispatched to the appropriate view. The view 501 * handles the event and notifies any listeners.</li> 502 * <li>If in the course of processing the event, the view's bounds may need 503 * to be changed, the view will call {@link #requestLayout()}.</li> 504 * <li>Similarly, if in the course of processing the event the view's appearance 505 * may need to be changed, the view will call {@link #invalidate()}.</li> 506 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 507 * the framework will take care of measuring, laying out, and drawing the tree 508 * as appropriate.</li> 509 * </ol> 510 * </p> 511 * 512 * <p><em>Note: The entire view tree is single threaded. You must always be on 513 * the UI thread when calling any method on any view.</em> 514 * If you are doing work on other threads and want to update the state of a view 515 * from that thread, you should use a {@link Handler}. 516 * </p> 517 * 518 * <a name="FocusHandling"></a> 519 * <h3>Focus Handling</h3> 520 * <p> 521 * The framework will handle routine focus movement in response to user input. 522 * This includes changing the focus as views are removed or hidden, or as new 523 * views become available. Views indicate their willingness to take focus 524 * through the {@link #isFocusable} method. To change whether a view can take 525 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 526 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 527 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 528 * </p> 529 * <p> 530 * Focus movement is based on an algorithm which finds the nearest neighbor in a 531 * given direction. In rare cases, the default algorithm may not match the 532 * intended behavior of the developer. In these situations, you can provide 533 * explicit overrides by using these XML attributes in the layout file: 534 * <pre> 535 * nextFocusDown 536 * nextFocusLeft 537 * nextFocusRight 538 * nextFocusUp 539 * </pre> 540 * </p> 541 * 542 * 543 * <p> 544 * To get a particular view to take focus, call {@link #requestFocus()}. 545 * </p> 546 * 547 * <a name="TouchMode"></a> 548 * <h3>Touch Mode</h3> 549 * <p> 550 * When a user is navigating a user interface via directional keys such as a D-pad, it is 551 * necessary to give focus to actionable items such as buttons so the user can see 552 * what will take input. If the device has touch capabilities, however, and the user 553 * begins interacting with the interface by touching it, it is no longer necessary to 554 * always highlight, or give focus to, a particular view. This motivates a mode 555 * for interaction named 'touch mode'. 556 * </p> 557 * <p> 558 * For a touch capable device, once the user touches the screen, the device 559 * will enter touch mode. From this point onward, only views for which 560 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 561 * Other views that are touchable, like buttons, will not take focus when touched; they will 562 * only fire the on click listeners. 563 * </p> 564 * <p> 565 * Any time a user hits a directional key, such as a D-pad direction, the view device will 566 * exit touch mode, and find a view to take focus, so that the user may resume interacting 567 * with the user interface without touching the screen again. 568 * </p> 569 * <p> 570 * The touch mode state is maintained across {@link android.app.Activity}s. Call 571 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 572 * </p> 573 * 574 * <a name="Scrolling"></a> 575 * <h3>Scrolling</h3> 576 * <p> 577 * The framework provides basic support for views that wish to internally 578 * scroll their content. This includes keeping track of the X and Y scroll 579 * offset as well as mechanisms for drawing scrollbars. See 580 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 581 * {@link #awakenScrollBars()} for more details. 582 * </p> 583 * 584 * <a name="Tags"></a> 585 * <h3>Tags</h3> 586 * <p> 587 * Unlike IDs, tags are not used to identify views. Tags are essentially an 588 * extra piece of information that can be associated with a view. They are most 589 * often used as a convenience to store data related to views in the views 590 * themselves rather than by putting them in a separate structure. 591 * </p> 592 * <p> 593 * Tags may be specified with character sequence values in layout XML as either 594 * a single tag using the {@link android.R.styleable#View_tag android:tag} 595 * attribute or multiple tags using the {@code <tag>} child element: 596 * <pre> 597 * <View ... 598 * android:tag="@string/mytag_value" /> 599 * <View ...> 600 * <tag android:id="@+id/mytag" 601 * android:value="@string/mytag_value" /> 602 * </View> 603 * </pre> 604 * </p> 605 * <p> 606 * Tags may also be specified with arbitrary objects from code using 607 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 608 * </p> 609 * 610 * <a name="Themes"></a> 611 * <h3>Themes</h3> 612 * <p> 613 * By default, Views are created using the theme of the Context object supplied 614 * to their constructor; however, a different theme may be specified by using 615 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 616 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 617 * code. 618 * </p> 619 * <p> 620 * When the {@link android.R.styleable#View_theme android:theme} attribute is 621 * used in XML, the specified theme is applied on top of the inflation 622 * context's theme (see {@link LayoutInflater}) and used for the view itself as 623 * well as any child elements. 624 * </p> 625 * <p> 626 * In the following example, both views will be created using the Material dark 627 * color scheme; however, because an overlay theme is used which only defines a 628 * subset of attributes, the value of 629 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 630 * the inflation context's theme (e.g. the Activity theme) will be preserved. 631 * <pre> 632 * <LinearLayout 633 * ... 634 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 635 * <View ...> 636 * </LinearLayout> 637 * </pre> 638 * </p> 639 * 640 * <a name="Properties"></a> 641 * <h3>Properties</h3> 642 * <p> 643 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 644 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 645 * available both in the {@link Property} form as well as in similarly-named setter/getter 646 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 647 * be used to set persistent state associated with these rendering-related properties on the view. 648 * The properties and methods can also be used in conjunction with 649 * {@link android.animation.Animator Animator}-based animations, described more in the 650 * <a href="#Animation">Animation</a> section. 651 * </p> 652 * 653 * <a name="Animation"></a> 654 * <h3>Animation</h3> 655 * <p> 656 * Starting with Android 3.0, the preferred way of animating views is to use the 657 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 658 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 659 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 660 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 661 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 662 * makes animating these View properties particularly easy and efficient. 663 * </p> 664 * <p> 665 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 666 * You can attach an {@link Animation} object to a view using 667 * {@link #setAnimation(Animation)} or 668 * {@link #startAnimation(Animation)}. The animation can alter the scale, 669 * rotation, translation and alpha of a view over time. If the animation is 670 * attached to a view that has children, the animation will affect the entire 671 * subtree rooted by that node. When an animation is started, the framework will 672 * take care of redrawing the appropriate views until the animation completes. 673 * </p> 674 * 675 * <a name="Security"></a> 676 * <h3>Security</h3> 677 * <p> 678 * Sometimes it is essential that an application be able to verify that an action 679 * is being performed with the full knowledge and consent of the user, such as 680 * granting a permission request, making a purchase or clicking on an advertisement. 681 * Unfortunately, a malicious application could try to spoof the user into 682 * performing these actions, unaware, by concealing the intended purpose of the view. 683 * As a remedy, the framework offers a touch filtering mechanism that can be used to 684 * improve the security of views that provide access to sensitive functionality. 685 * </p><p> 686 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 687 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 688 * will discard touches that are received whenever the view's window is obscured by 689 * another visible window. As a result, the view will not receive touches whenever a 690 * toast, dialog or other window appears above the view's window. 691 * </p><p> 692 * For more fine-grained control over security, consider overriding the 693 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 694 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 695 * </p> 696 * 697 * @attr ref android.R.styleable#View_alpha 698 * @attr ref android.R.styleable#View_background 699 * @attr ref android.R.styleable#View_clickable 700 * @attr ref android.R.styleable#View_contentDescription 701 * @attr ref android.R.styleable#View_drawingCacheQuality 702 * @attr ref android.R.styleable#View_duplicateParentState 703 * @attr ref android.R.styleable#View_id 704 * @attr ref android.R.styleable#View_requiresFadingEdge 705 * @attr ref android.R.styleable#View_fadeScrollbars 706 * @attr ref android.R.styleable#View_fadingEdgeLength 707 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 708 * @attr ref android.R.styleable#View_fitsSystemWindows 709 * @attr ref android.R.styleable#View_isScrollContainer 710 * @attr ref android.R.styleable#View_focusable 711 * @attr ref android.R.styleable#View_focusableInTouchMode 712 * @attr ref android.R.styleable#View_focusedByDefault 713 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 714 * @attr ref android.R.styleable#View_keepScreenOn 715 * @attr ref android.R.styleable#View_keyboardNavigationCluster 716 * @attr ref android.R.styleable#View_layerType 717 * @attr ref android.R.styleable#View_layoutDirection 718 * @attr ref android.R.styleable#View_longClickable 719 * @attr ref android.R.styleable#View_minHeight 720 * @attr ref android.R.styleable#View_minWidth 721 * @attr ref android.R.styleable#View_nextClusterForward 722 * @attr ref android.R.styleable#View_nextFocusDown 723 * @attr ref android.R.styleable#View_nextFocusLeft 724 * @attr ref android.R.styleable#View_nextFocusRight 725 * @attr ref android.R.styleable#View_nextFocusUp 726 * @attr ref android.R.styleable#View_onClick 727 * @attr ref android.R.styleable#View_padding 728 * @attr ref android.R.styleable#View_paddingHorizontal 729 * @attr ref android.R.styleable#View_paddingVertical 730 * @attr ref android.R.styleable#View_paddingBottom 731 * @attr ref android.R.styleable#View_paddingLeft 732 * @attr ref android.R.styleable#View_paddingRight 733 * @attr ref android.R.styleable#View_paddingTop 734 * @attr ref android.R.styleable#View_paddingStart 735 * @attr ref android.R.styleable#View_paddingEnd 736 * @attr ref android.R.styleable#View_saveEnabled 737 * @attr ref android.R.styleable#View_rotation 738 * @attr ref android.R.styleable#View_rotationX 739 * @attr ref android.R.styleable#View_rotationY 740 * @attr ref android.R.styleable#View_scaleX 741 * @attr ref android.R.styleable#View_scaleY 742 * @attr ref android.R.styleable#View_scrollX 743 * @attr ref android.R.styleable#View_scrollY 744 * @attr ref android.R.styleable#View_scrollbarSize 745 * @attr ref android.R.styleable#View_scrollbarStyle 746 * @attr ref android.R.styleable#View_scrollbars 747 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 748 * @attr ref android.R.styleable#View_scrollbarFadeDuration 749 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 750 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 751 * @attr ref android.R.styleable#View_scrollbarThumbVertical 752 * @attr ref android.R.styleable#View_scrollbarTrackVertical 753 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 754 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 755 * @attr ref android.R.styleable#View_stateListAnimator 756 * @attr ref android.R.styleable#View_transitionName 757 * @attr ref android.R.styleable#View_soundEffectsEnabled 758 * @attr ref android.R.styleable#View_tag 759 * @attr ref android.R.styleable#View_textAlignment 760 * @attr ref android.R.styleable#View_textDirection 761 * @attr ref android.R.styleable#View_transformPivotX 762 * @attr ref android.R.styleable#View_transformPivotY 763 * @attr ref android.R.styleable#View_translationX 764 * @attr ref android.R.styleable#View_translationY 765 * @attr ref android.R.styleable#View_translationZ 766 * @attr ref android.R.styleable#View_visibility 767 * @attr ref android.R.styleable#View_theme 768 * 769 * @see android.view.ViewGroup 770 */ 771 @UiThread 772 public class View implements Drawable.Callback, KeyEvent.Callback, 773 AccessibilityEventSource { 774 private static final boolean DBG = false; 775 776 /** @hide */ 777 public static boolean DEBUG_DRAW = false; 778 779 /** 780 * The logging tag used by this class with android.util.Log. 781 */ 782 protected static final String VIEW_LOG_TAG = "View"; 783 784 /** 785 * When set to true, apps will draw debugging information about their layouts. 786 * 787 * @hide 788 */ 789 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 790 791 /** 792 * When set to true, this view will save its attribute data. 793 * 794 * @hide 795 */ 796 public static boolean mDebugViewAttributes = false; 797 798 /** 799 * Used to mark a View that has no ID. 800 */ 801 public static final int NO_ID = -1; 802 803 /** 804 * Last ID that is given to Views that are no part of activities. 805 * 806 * {@hide} 807 */ 808 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 809 810 /** 811 * Attribute to find the autofilled highlight 812 * 813 * @see #getAutofilledDrawable() 814 */ 815 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 816 new int[]{android.R.attr.autofilledHighlight}; 817 818 /** 819 * Signals that compatibility booleans have been initialized according to 820 * target SDK versions. 821 */ 822 private static boolean sCompatibilityDone = false; 823 824 /** 825 * Use the old (broken) way of building MeasureSpecs. 826 */ 827 private static boolean sUseBrokenMakeMeasureSpec = false; 828 829 /** 830 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 831 */ 832 static boolean sUseZeroUnspecifiedMeasureSpec = false; 833 834 /** 835 * Ignore any optimizations using the measure cache. 836 */ 837 private static boolean sIgnoreMeasureCache = false; 838 839 /** 840 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 841 */ 842 private static boolean sAlwaysRemeasureExactly = false; 843 844 /** 845 * Relax constraints around whether setLayoutParams() must be called after 846 * modifying the layout params. 847 */ 848 private static boolean sLayoutParamsAlwaysChanged = false; 849 850 /** 851 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 852 * without throwing 853 */ 854 static boolean sTextureViewIgnoresDrawableSetters = false; 855 856 /** 857 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 858 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 859 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 860 * check is implemented for backwards compatibility. 861 * 862 * {@hide} 863 */ 864 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 865 866 /** 867 * Prior to N, when drag enters into child of a view that has already received an 868 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 869 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 870 * false from its event handler for these events. 871 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 872 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 873 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 874 */ 875 static boolean sCascadedDragDrop; 876 877 /** 878 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 879 * to determine things like whether or not to permit item click events. We can't break 880 * apps that do this just because more things (clickable things) are now auto-focusable 881 * and they would get different results, so give old behavior to old apps. 882 */ 883 static boolean sHasFocusableExcludeAutoFocusable; 884 885 /** 886 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 887 * made focusable by default. As a result, apps could (incorrectly) change the clickable 888 * setting of views off the UI thread. Now that clickable can effect the focusable state, 889 * changing the clickable attribute off the UI thread will cause an exception (since changing 890 * the focusable state checks). In order to prevent apps from crashing, we will handle this 891 * specific case and just not notify parents on new focusables resulting from marking views 892 * clickable from outside the UI thread. 893 */ 894 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 895 896 /** @hide */ 897 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 898 @Retention(RetentionPolicy.SOURCE) 899 public @interface Focusable {} 900 901 /** 902 * This view does not want keystrokes. 903 * <p> 904 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 905 * android:focusable}. 906 */ 907 public static final int NOT_FOCUSABLE = 0x00000000; 908 909 /** 910 * This view wants keystrokes. 911 * <p> 912 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 913 * android:focusable}. 914 */ 915 public static final int FOCUSABLE = 0x00000001; 916 917 /** 918 * This view determines focusability automatically. This is the default. 919 * <p> 920 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 921 * android:focusable}. 922 */ 923 public static final int FOCUSABLE_AUTO = 0x00000010; 924 925 /** 926 * Mask for use with setFlags indicating bits used for focus. 927 */ 928 private static final int FOCUSABLE_MASK = 0x00000011; 929 930 /** 931 * This view will adjust its padding to fit sytem windows (e.g. status bar) 932 */ 933 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 934 935 /** @hide */ 936 @IntDef({VISIBLE, INVISIBLE, GONE}) 937 @Retention(RetentionPolicy.SOURCE) 938 public @interface Visibility {} 939 940 /** 941 * This view is visible. 942 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 943 * android:visibility}. 944 */ 945 public static final int VISIBLE = 0x00000000; 946 947 /** 948 * This view is invisible, but it still takes up space for layout purposes. 949 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 950 * android:visibility}. 951 */ 952 public static final int INVISIBLE = 0x00000004; 953 954 /** 955 * This view is invisible, and it doesn't take any space for layout 956 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 957 * android:visibility}. 958 */ 959 public static final int GONE = 0x00000008; 960 961 /** 962 * Mask for use with setFlags indicating bits used for visibility. 963 * {@hide} 964 */ 965 static final int VISIBILITY_MASK = 0x0000000C; 966 967 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 968 969 /** 970 * Hint indicating that this view can be autofilled with an email address. 971 * 972 * <p>Can be used with either {@link #setAutofillHints(String[])} or 973 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 974 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 975 * 976 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 977 */ 978 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 979 980 /** 981 * Hint indicating that this view can be autofilled with a user's real name. 982 * 983 * <p>Can be used with either {@link #setAutofillHints(String[])} or 984 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 985 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 986 * 987 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 988 */ 989 public static final String AUTOFILL_HINT_NAME = "name"; 990 991 /** 992 * Hint indicating that this view can be autofilled with a username. 993 * 994 * <p>Can be used with either {@link #setAutofillHints(String[])} or 995 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 996 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 997 * 998 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 999 */ 1000 public static final String AUTOFILL_HINT_USERNAME = "username"; 1001 1002 /** 1003 * Hint indicating that this view can be autofilled with a password. 1004 * 1005 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1006 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1007 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1008 * 1009 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1010 */ 1011 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1012 1013 /** 1014 * Hint indicating that this view can be autofilled with a phone number. 1015 * 1016 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1017 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1018 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1019 * 1020 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1021 */ 1022 public static final String AUTOFILL_HINT_PHONE = "phone"; 1023 1024 /** 1025 * Hint indicating that this view can be autofilled with a postal address. 1026 * 1027 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1028 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1029 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1030 * 1031 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1032 */ 1033 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1034 1035 /** 1036 * Hint indicating that this view can be autofilled with a postal code. 1037 * 1038 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1039 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1040 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1041 * 1042 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1043 */ 1044 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1045 1046 /** 1047 * Hint indicating that this view can be autofilled with a credit card number. 1048 * 1049 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1050 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1051 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1052 * 1053 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1054 */ 1055 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1056 1057 /** 1058 * Hint indicating that this view can be autofilled with a credit card security code. 1059 * 1060 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1061 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1062 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1063 * 1064 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1065 */ 1066 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1067 1068 /** 1069 * Hint indicating that this view can be autofilled with a credit card expiration date. 1070 * 1071 * <p>It should be used when the credit card expiration date is represented by just one view; 1072 * if it is represented by more than one (for example, one view for the month and another view 1073 * for the year), then each of these views should use the hint specific for the unit 1074 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1075 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1076 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1077 * 1078 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1079 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1080 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1081 * 1082 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1083 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1084 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1085 * the following options: 1086 * 1087 * <ul> 1088 * <li>{@code "04/2020"} 1089 * <li>{@code "4/2020"} 1090 * <li>{@code "2020/04"} 1091 * <li>{@code "2020/4"} 1092 * <li>{@code "April/2020"} 1093 * <li>{@code "Apr/2020"} 1094 * </ul> 1095 * 1096 * <p>You define a date autofill value for the view by overriding the following methods: 1097 * 1098 * <ol> 1099 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1100 * <li>{@link #getAutofillValue()} to return a 1101 * {@link AutofillValue#forDate(long) date autofillvalue}. 1102 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1103 * </ol> 1104 * 1105 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1106 */ 1107 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1108 "creditCardExpirationDate"; 1109 1110 /** 1111 * Hint indicating that this view can be autofilled with a credit card expiration month. 1112 * 1113 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1114 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1115 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1116 * 1117 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1118 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1119 * ambiguity when the autofill service provides a value for it. To understand why a 1120 * value can be ambiguous, consider "January", which could be represented as either of 1121 * 1122 * <ul> 1123 * <li>{@code "1"}: recommended way. 1124 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1125 * <li>{@code "January"}: full name, in English. 1126 * <li>{@code "jan"}: abbreviated name, in English. 1127 * <li>{@code "Janeiro"}: full name, in another language. 1128 * </ul> 1129 * 1130 * <p>Another recommended approach is to use a date autofill value - see 1131 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1132 * 1133 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1134 */ 1135 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1136 "creditCardExpirationMonth"; 1137 1138 /** 1139 * Hint indicating that this view can be autofilled with a credit card expiration year. 1140 * 1141 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1142 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1143 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1144 * 1145 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1146 */ 1147 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1148 "creditCardExpirationYear"; 1149 1150 /** 1151 * Hint indicating that this view can be autofilled with a credit card expiration day. 1152 * 1153 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1154 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1155 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1156 * 1157 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1158 */ 1159 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1160 1161 /** 1162 * Hints for the autofill services that describes the content of the view. 1163 */ 1164 private @Nullable String[] mAutofillHints; 1165 1166 /** 1167 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1168 */ 1169 private AutofillId mAutofillId; 1170 1171 /** @hide */ 1172 @IntDef({ 1173 AUTOFILL_TYPE_NONE, 1174 AUTOFILL_TYPE_TEXT, 1175 AUTOFILL_TYPE_TOGGLE, 1176 AUTOFILL_TYPE_LIST, 1177 AUTOFILL_TYPE_DATE 1178 }) 1179 @Retention(RetentionPolicy.SOURCE) 1180 public @interface AutofillType {} 1181 1182 /** 1183 * Autofill type for views that cannot be autofilled. 1184 * 1185 * <p>Typically used when the view is read-only; for example, a text label. 1186 * 1187 * @see #getAutofillType() 1188 */ 1189 public static final int AUTOFILL_TYPE_NONE = 0; 1190 1191 /** 1192 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1193 * 1194 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1195 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1196 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1197 * 1198 * @see #getAutofillType() 1199 */ 1200 public static final int AUTOFILL_TYPE_TEXT = 1; 1201 1202 /** 1203 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1204 * 1205 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1206 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1207 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1208 * 1209 * @see #getAutofillType() 1210 */ 1211 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1212 1213 /** 1214 * Autofill type for a selection list field, which is filled by an {@code int} 1215 * representing the element index inside the list (starting at {@code 0}). 1216 * 1217 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1218 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1219 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1220 * 1221 * <p>The available options in the selection list are typically provided by 1222 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1223 * 1224 * @see #getAutofillType() 1225 */ 1226 public static final int AUTOFILL_TYPE_LIST = 3; 1227 1228 1229 /** 1230 * Autofill type for a field that contains a date, which is represented by a long representing 1231 * the number of milliseconds since the standard base time known as "the epoch", namely 1232 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1233 * 1234 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1235 * {@link AutofillValue#forDate(long)}, and the values passed to 1236 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1237 * 1238 * @see #getAutofillType() 1239 */ 1240 public static final int AUTOFILL_TYPE_DATE = 4; 1241 1242 /** @hide */ 1243 @IntDef({ 1244 IMPORTANT_FOR_AUTOFILL_AUTO, 1245 IMPORTANT_FOR_AUTOFILL_YES, 1246 IMPORTANT_FOR_AUTOFILL_NO, 1247 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1248 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1249 }) 1250 @Retention(RetentionPolicy.SOURCE) 1251 public @interface AutofillImportance {} 1252 1253 /** 1254 * Automatically determine whether a view is important for autofill. 1255 * 1256 * @see #isImportantForAutofill() 1257 * @see #setImportantForAutofill(int) 1258 */ 1259 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1260 1261 /** 1262 * The view is important for autofill, and its children (if any) will be traversed. 1263 * 1264 * @see #isImportantForAutofill() 1265 * @see #setImportantForAutofill(int) 1266 */ 1267 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1268 1269 /** 1270 * The view is not important for autofill, but its children (if any) will be traversed. 1271 * 1272 * @see #isImportantForAutofill() 1273 * @see #setImportantForAutofill(int) 1274 */ 1275 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1276 1277 /** 1278 * The view is important for autofill, but its children (if any) will not be traversed. 1279 * 1280 * @see #isImportantForAutofill() 1281 * @see #setImportantForAutofill(int) 1282 */ 1283 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1284 1285 /** 1286 * The view is not important for autofill, and its children (if any) will not be traversed. 1287 * 1288 * @see #isImportantForAutofill() 1289 * @see #setImportantForAutofill(int) 1290 */ 1291 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1292 1293 /** @hide */ 1294 @IntDef( 1295 flag = true, 1296 value = {AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}) 1297 @Retention(RetentionPolicy.SOURCE) 1298 public @interface AutofillFlags {} 1299 1300 /** 1301 * Flag requesting you to add views that are marked as not important for autofill 1302 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1303 */ 1304 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1305 1306 /** 1307 * This view is enabled. Interpretation varies by subclass. 1308 * Use with ENABLED_MASK when calling setFlags. 1309 * {@hide} 1310 */ 1311 static final int ENABLED = 0x00000000; 1312 1313 /** 1314 * This view is disabled. Interpretation varies by subclass. 1315 * Use with ENABLED_MASK when calling setFlags. 1316 * {@hide} 1317 */ 1318 static final int DISABLED = 0x00000020; 1319 1320 /** 1321 * Mask for use with setFlags indicating bits used for indicating whether 1322 * this view is enabled 1323 * {@hide} 1324 */ 1325 static final int ENABLED_MASK = 0x00000020; 1326 1327 /** 1328 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1329 * called and further optimizations will be performed. It is okay to have 1330 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1331 * {@hide} 1332 */ 1333 static final int WILL_NOT_DRAW = 0x00000080; 1334 1335 /** 1336 * Mask for use with setFlags indicating bits used for indicating whether 1337 * this view is will draw 1338 * {@hide} 1339 */ 1340 static final int DRAW_MASK = 0x00000080; 1341 1342 /** 1343 * <p>This view doesn't show scrollbars.</p> 1344 * {@hide} 1345 */ 1346 static final int SCROLLBARS_NONE = 0x00000000; 1347 1348 /** 1349 * <p>This view shows horizontal scrollbars.</p> 1350 * {@hide} 1351 */ 1352 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1353 1354 /** 1355 * <p>This view shows vertical scrollbars.</p> 1356 * {@hide} 1357 */ 1358 static final int SCROLLBARS_VERTICAL = 0x00000200; 1359 1360 /** 1361 * <p>Mask for use with setFlags indicating bits used for indicating which 1362 * scrollbars are enabled.</p> 1363 * {@hide} 1364 */ 1365 static final int SCROLLBARS_MASK = 0x00000300; 1366 1367 /** 1368 * Indicates that the view should filter touches when its window is obscured. 1369 * Refer to the class comments for more information about this security feature. 1370 * {@hide} 1371 */ 1372 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1373 1374 /** 1375 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1376 * that they are optional and should be skipped if the window has 1377 * requested system UI flags that ignore those insets for layout. 1378 */ 1379 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1380 1381 /** 1382 * <p>This view doesn't show fading edges.</p> 1383 * {@hide} 1384 */ 1385 static final int FADING_EDGE_NONE = 0x00000000; 1386 1387 /** 1388 * <p>This view shows horizontal fading edges.</p> 1389 * {@hide} 1390 */ 1391 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1392 1393 /** 1394 * <p>This view shows vertical fading edges.</p> 1395 * {@hide} 1396 */ 1397 static final int FADING_EDGE_VERTICAL = 0x00002000; 1398 1399 /** 1400 * <p>Mask for use with setFlags indicating bits used for indicating which 1401 * fading edges are enabled.</p> 1402 * {@hide} 1403 */ 1404 static final int FADING_EDGE_MASK = 0x00003000; 1405 1406 /** 1407 * <p>Indicates this view can be clicked. When clickable, a View reacts 1408 * to clicks by notifying the OnClickListener.<p> 1409 * {@hide} 1410 */ 1411 static final int CLICKABLE = 0x00004000; 1412 1413 /** 1414 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1415 * {@hide} 1416 */ 1417 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1418 1419 /** 1420 * <p>Indicates that no icicle should be saved for this view.<p> 1421 * {@hide} 1422 */ 1423 static final int SAVE_DISABLED = 0x000010000; 1424 1425 /** 1426 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1427 * property.</p> 1428 * {@hide} 1429 */ 1430 static final int SAVE_DISABLED_MASK = 0x000010000; 1431 1432 /** 1433 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1434 * {@hide} 1435 */ 1436 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1437 1438 /** 1439 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1440 * {@hide} 1441 */ 1442 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1443 1444 /** @hide */ 1445 @Retention(RetentionPolicy.SOURCE) 1446 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1447 public @interface DrawingCacheQuality {} 1448 1449 /** 1450 * <p>Enables low quality mode for the drawing cache.</p> 1451 */ 1452 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1453 1454 /** 1455 * <p>Enables high quality mode for the drawing cache.</p> 1456 */ 1457 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1458 1459 /** 1460 * <p>Enables automatic quality mode for the drawing cache.</p> 1461 */ 1462 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1463 1464 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1465 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1466 }; 1467 1468 /** 1469 * <p>Mask for use with setFlags indicating bits used for the cache 1470 * quality property.</p> 1471 * {@hide} 1472 */ 1473 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1474 1475 /** 1476 * <p> 1477 * Indicates this view can be long clicked. When long clickable, a View 1478 * reacts to long clicks by notifying the OnLongClickListener or showing a 1479 * context menu. 1480 * </p> 1481 * {@hide} 1482 */ 1483 static final int LONG_CLICKABLE = 0x00200000; 1484 1485 /** 1486 * <p>Indicates that this view gets its drawable states from its direct parent 1487 * and ignores its original internal states.</p> 1488 * 1489 * @hide 1490 */ 1491 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1492 1493 /** 1494 * <p> 1495 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1496 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1497 * OnContextClickListener. 1498 * </p> 1499 * {@hide} 1500 */ 1501 static final int CONTEXT_CLICKABLE = 0x00800000; 1502 1503 1504 /** @hide */ 1505 @IntDef({ 1506 SCROLLBARS_INSIDE_OVERLAY, 1507 SCROLLBARS_INSIDE_INSET, 1508 SCROLLBARS_OUTSIDE_OVERLAY, 1509 SCROLLBARS_OUTSIDE_INSET 1510 }) 1511 @Retention(RetentionPolicy.SOURCE) 1512 public @interface ScrollBarStyle {} 1513 1514 /** 1515 * The scrollbar style to display the scrollbars inside the content area, 1516 * without increasing the padding. The scrollbars will be overlaid with 1517 * translucency on the view's content. 1518 */ 1519 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1520 1521 /** 1522 * The scrollbar style to display the scrollbars inside the padded area, 1523 * increasing the padding of the view. The scrollbars will not overlap the 1524 * content area of the view. 1525 */ 1526 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1527 1528 /** 1529 * The scrollbar style to display the scrollbars at the edge of the view, 1530 * without increasing the padding. The scrollbars will be overlaid with 1531 * translucency. 1532 */ 1533 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1534 1535 /** 1536 * The scrollbar style to display the scrollbars at the edge of the view, 1537 * increasing the padding of the view. The scrollbars will only overlap the 1538 * background, if any. 1539 */ 1540 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1541 1542 /** 1543 * Mask to check if the scrollbar style is overlay or inset. 1544 * {@hide} 1545 */ 1546 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1547 1548 /** 1549 * Mask to check if the scrollbar style is inside or outside. 1550 * {@hide} 1551 */ 1552 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1553 1554 /** 1555 * Mask for scrollbar style. 1556 * {@hide} 1557 */ 1558 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1559 1560 /** 1561 * View flag indicating that the screen should remain on while the 1562 * window containing this view is visible to the user. This effectively 1563 * takes care of automatically setting the WindowManager's 1564 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1565 */ 1566 public static final int KEEP_SCREEN_ON = 0x04000000; 1567 1568 /** 1569 * View flag indicating whether this view should have sound effects enabled 1570 * for events such as clicking and touching. 1571 */ 1572 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1573 1574 /** 1575 * View flag indicating whether this view should have haptic feedback 1576 * enabled for events such as long presses. 1577 */ 1578 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1579 1580 /** 1581 * <p>Indicates that the view hierarchy should stop saving state when 1582 * it reaches this view. If state saving is initiated immediately at 1583 * the view, it will be allowed. 1584 * {@hide} 1585 */ 1586 static final int PARENT_SAVE_DISABLED = 0x20000000; 1587 1588 /** 1589 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1590 * {@hide} 1591 */ 1592 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1593 1594 private static Paint sDebugPaint; 1595 1596 /** 1597 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1598 * {@hide} 1599 */ 1600 static final int TOOLTIP = 0x40000000; 1601 1602 /** @hide */ 1603 @IntDef(flag = true, 1604 value = { 1605 FOCUSABLES_ALL, 1606 FOCUSABLES_TOUCH_MODE 1607 }) 1608 @Retention(RetentionPolicy.SOURCE) 1609 public @interface FocusableMode {} 1610 1611 /** 1612 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1613 * should add all focusable Views regardless if they are focusable in touch mode. 1614 */ 1615 public static final int FOCUSABLES_ALL = 0x00000000; 1616 1617 /** 1618 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1619 * should add only Views focusable in touch mode. 1620 */ 1621 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1622 1623 /** @hide */ 1624 @IntDef({ 1625 FOCUS_BACKWARD, 1626 FOCUS_FORWARD, 1627 FOCUS_LEFT, 1628 FOCUS_UP, 1629 FOCUS_RIGHT, 1630 FOCUS_DOWN 1631 }) 1632 @Retention(RetentionPolicy.SOURCE) 1633 public @interface FocusDirection {} 1634 1635 /** @hide */ 1636 @IntDef({ 1637 FOCUS_LEFT, 1638 FOCUS_UP, 1639 FOCUS_RIGHT, 1640 FOCUS_DOWN 1641 }) 1642 @Retention(RetentionPolicy.SOURCE) 1643 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1644 1645 /** 1646 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1647 * item. 1648 */ 1649 public static final int FOCUS_BACKWARD = 0x00000001; 1650 1651 /** 1652 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1653 * item. 1654 */ 1655 public static final int FOCUS_FORWARD = 0x00000002; 1656 1657 /** 1658 * Use with {@link #focusSearch(int)}. Move focus to the left. 1659 */ 1660 public static final int FOCUS_LEFT = 0x00000011; 1661 1662 /** 1663 * Use with {@link #focusSearch(int)}. Move focus up. 1664 */ 1665 public static final int FOCUS_UP = 0x00000021; 1666 1667 /** 1668 * Use with {@link #focusSearch(int)}. Move focus to the right. 1669 */ 1670 public static final int FOCUS_RIGHT = 0x00000042; 1671 1672 /** 1673 * Use with {@link #focusSearch(int)}. Move focus down. 1674 */ 1675 public static final int FOCUS_DOWN = 0x00000082; 1676 1677 /** 1678 * Bits of {@link #getMeasuredWidthAndState()} and 1679 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1680 */ 1681 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1682 1683 /** 1684 * Bits of {@link #getMeasuredWidthAndState()} and 1685 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1686 */ 1687 public static final int MEASURED_STATE_MASK = 0xff000000; 1688 1689 /** 1690 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1691 * for functions that combine both width and height into a single int, 1692 * such as {@link #getMeasuredState()} and the childState argument of 1693 * {@link #resolveSizeAndState(int, int, int)}. 1694 */ 1695 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1696 1697 /** 1698 * Bit of {@link #getMeasuredWidthAndState()} and 1699 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1700 * is smaller that the space the view would like to have. 1701 */ 1702 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1703 1704 /** 1705 * Base View state sets 1706 */ 1707 // Singles 1708 /** 1709 * Indicates the view has no states set. States are used with 1710 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1711 * view depending on its state. 1712 * 1713 * @see android.graphics.drawable.Drawable 1714 * @see #getDrawableState() 1715 */ 1716 protected static final int[] EMPTY_STATE_SET; 1717 /** 1718 * Indicates the view is enabled. States are used with 1719 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1720 * view depending on its state. 1721 * 1722 * @see android.graphics.drawable.Drawable 1723 * @see #getDrawableState() 1724 */ 1725 protected static final int[] ENABLED_STATE_SET; 1726 /** 1727 * Indicates the view is focused. States are used with 1728 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1729 * view depending on its state. 1730 * 1731 * @see android.graphics.drawable.Drawable 1732 * @see #getDrawableState() 1733 */ 1734 protected static final int[] FOCUSED_STATE_SET; 1735 /** 1736 * Indicates the view is selected. States are used with 1737 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1738 * view depending on its state. 1739 * 1740 * @see android.graphics.drawable.Drawable 1741 * @see #getDrawableState() 1742 */ 1743 protected static final int[] SELECTED_STATE_SET; 1744 /** 1745 * Indicates the view is pressed. States are used with 1746 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1747 * view depending on its state. 1748 * 1749 * @see android.graphics.drawable.Drawable 1750 * @see #getDrawableState() 1751 */ 1752 protected static final int[] PRESSED_STATE_SET; 1753 /** 1754 * Indicates the view's window has focus. States are used with 1755 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1756 * view depending on its state. 1757 * 1758 * @see android.graphics.drawable.Drawable 1759 * @see #getDrawableState() 1760 */ 1761 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1762 // Doubles 1763 /** 1764 * Indicates the view is enabled and has the focus. 1765 * 1766 * @see #ENABLED_STATE_SET 1767 * @see #FOCUSED_STATE_SET 1768 */ 1769 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1770 /** 1771 * Indicates the view is enabled and selected. 1772 * 1773 * @see #ENABLED_STATE_SET 1774 * @see #SELECTED_STATE_SET 1775 */ 1776 protected static final int[] ENABLED_SELECTED_STATE_SET; 1777 /** 1778 * Indicates the view is enabled and that its window has focus. 1779 * 1780 * @see #ENABLED_STATE_SET 1781 * @see #WINDOW_FOCUSED_STATE_SET 1782 */ 1783 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1784 /** 1785 * Indicates the view is focused and selected. 1786 * 1787 * @see #FOCUSED_STATE_SET 1788 * @see #SELECTED_STATE_SET 1789 */ 1790 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1791 /** 1792 * Indicates the view has the focus and that its window has the focus. 1793 * 1794 * @see #FOCUSED_STATE_SET 1795 * @see #WINDOW_FOCUSED_STATE_SET 1796 */ 1797 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1798 /** 1799 * Indicates the view is selected and that its window has the focus. 1800 * 1801 * @see #SELECTED_STATE_SET 1802 * @see #WINDOW_FOCUSED_STATE_SET 1803 */ 1804 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1805 // Triples 1806 /** 1807 * Indicates the view is enabled, focused and selected. 1808 * 1809 * @see #ENABLED_STATE_SET 1810 * @see #FOCUSED_STATE_SET 1811 * @see #SELECTED_STATE_SET 1812 */ 1813 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1814 /** 1815 * Indicates the view is enabled, focused and its window has the focus. 1816 * 1817 * @see #ENABLED_STATE_SET 1818 * @see #FOCUSED_STATE_SET 1819 * @see #WINDOW_FOCUSED_STATE_SET 1820 */ 1821 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1822 /** 1823 * Indicates the view is enabled, selected and its window has the focus. 1824 * 1825 * @see #ENABLED_STATE_SET 1826 * @see #SELECTED_STATE_SET 1827 * @see #WINDOW_FOCUSED_STATE_SET 1828 */ 1829 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1830 /** 1831 * Indicates the view is focused, selected and its window has the focus. 1832 * 1833 * @see #FOCUSED_STATE_SET 1834 * @see #SELECTED_STATE_SET 1835 * @see #WINDOW_FOCUSED_STATE_SET 1836 */ 1837 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1838 /** 1839 * Indicates the view is enabled, focused, selected and its window 1840 * has the focus. 1841 * 1842 * @see #ENABLED_STATE_SET 1843 * @see #FOCUSED_STATE_SET 1844 * @see #SELECTED_STATE_SET 1845 * @see #WINDOW_FOCUSED_STATE_SET 1846 */ 1847 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1848 /** 1849 * Indicates the view is pressed and its window has the focus. 1850 * 1851 * @see #PRESSED_STATE_SET 1852 * @see #WINDOW_FOCUSED_STATE_SET 1853 */ 1854 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1855 /** 1856 * Indicates the view is pressed and selected. 1857 * 1858 * @see #PRESSED_STATE_SET 1859 * @see #SELECTED_STATE_SET 1860 */ 1861 protected static final int[] PRESSED_SELECTED_STATE_SET; 1862 /** 1863 * Indicates the view is pressed, selected and its window has the focus. 1864 * 1865 * @see #PRESSED_STATE_SET 1866 * @see #SELECTED_STATE_SET 1867 * @see #WINDOW_FOCUSED_STATE_SET 1868 */ 1869 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1870 /** 1871 * Indicates the view is pressed and focused. 1872 * 1873 * @see #PRESSED_STATE_SET 1874 * @see #FOCUSED_STATE_SET 1875 */ 1876 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1877 /** 1878 * Indicates the view is pressed, focused and its window has the focus. 1879 * 1880 * @see #PRESSED_STATE_SET 1881 * @see #FOCUSED_STATE_SET 1882 * @see #WINDOW_FOCUSED_STATE_SET 1883 */ 1884 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1885 /** 1886 * Indicates the view is pressed, focused and selected. 1887 * 1888 * @see #PRESSED_STATE_SET 1889 * @see #SELECTED_STATE_SET 1890 * @see #FOCUSED_STATE_SET 1891 */ 1892 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1893 /** 1894 * Indicates the view is pressed, focused, selected and its window has the focus. 1895 * 1896 * @see #PRESSED_STATE_SET 1897 * @see #FOCUSED_STATE_SET 1898 * @see #SELECTED_STATE_SET 1899 * @see #WINDOW_FOCUSED_STATE_SET 1900 */ 1901 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1902 /** 1903 * Indicates the view is pressed and enabled. 1904 * 1905 * @see #PRESSED_STATE_SET 1906 * @see #ENABLED_STATE_SET 1907 */ 1908 protected static final int[] PRESSED_ENABLED_STATE_SET; 1909 /** 1910 * Indicates the view is pressed, enabled and its window has the focus. 1911 * 1912 * @see #PRESSED_STATE_SET 1913 * @see #ENABLED_STATE_SET 1914 * @see #WINDOW_FOCUSED_STATE_SET 1915 */ 1916 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1917 /** 1918 * Indicates the view is pressed, enabled and selected. 1919 * 1920 * @see #PRESSED_STATE_SET 1921 * @see #ENABLED_STATE_SET 1922 * @see #SELECTED_STATE_SET 1923 */ 1924 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1925 /** 1926 * Indicates the view is pressed, enabled, selected and its window has the 1927 * focus. 1928 * 1929 * @see #PRESSED_STATE_SET 1930 * @see #ENABLED_STATE_SET 1931 * @see #SELECTED_STATE_SET 1932 * @see #WINDOW_FOCUSED_STATE_SET 1933 */ 1934 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1935 /** 1936 * Indicates the view is pressed, enabled and focused. 1937 * 1938 * @see #PRESSED_STATE_SET 1939 * @see #ENABLED_STATE_SET 1940 * @see #FOCUSED_STATE_SET 1941 */ 1942 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1943 /** 1944 * Indicates the view is pressed, enabled, focused and its window has the 1945 * focus. 1946 * 1947 * @see #PRESSED_STATE_SET 1948 * @see #ENABLED_STATE_SET 1949 * @see #FOCUSED_STATE_SET 1950 * @see #WINDOW_FOCUSED_STATE_SET 1951 */ 1952 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1953 /** 1954 * Indicates the view is pressed, enabled, focused and selected. 1955 * 1956 * @see #PRESSED_STATE_SET 1957 * @see #ENABLED_STATE_SET 1958 * @see #SELECTED_STATE_SET 1959 * @see #FOCUSED_STATE_SET 1960 */ 1961 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1962 /** 1963 * Indicates the view is pressed, enabled, focused, selected and its window 1964 * has the focus. 1965 * 1966 * @see #PRESSED_STATE_SET 1967 * @see #ENABLED_STATE_SET 1968 * @see #SELECTED_STATE_SET 1969 * @see #FOCUSED_STATE_SET 1970 * @see #WINDOW_FOCUSED_STATE_SET 1971 */ 1972 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1973 1974 static { 1975 EMPTY_STATE_SET = StateSet.get(0); 1976 1977 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1978 1979 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1980 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1981 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1982 1983 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1984 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1985 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1986 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1987 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1988 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1989 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1990 | StateSet.VIEW_STATE_FOCUSED); 1991 1992 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1993 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1994 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1995 ENABLED_SELECTED_STATE_SET = StateSet.get( 1996 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1997 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1998 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1999 | StateSet.VIEW_STATE_ENABLED); 2000 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2001 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2002 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2003 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2004 | StateSet.VIEW_STATE_ENABLED); 2005 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2006 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2007 | StateSet.VIEW_STATE_ENABLED); 2008 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2009 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2010 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2011 2012 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2013 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2014 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2015 PRESSED_SELECTED_STATE_SET = StateSet.get( 2016 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2017 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2018 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2019 | StateSet.VIEW_STATE_PRESSED); 2020 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2021 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2022 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2023 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2024 | StateSet.VIEW_STATE_PRESSED); 2025 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2026 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2027 | StateSet.VIEW_STATE_PRESSED); 2028 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2029 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2030 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2031 PRESSED_ENABLED_STATE_SET = StateSet.get( 2032 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2033 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2034 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2035 | StateSet.VIEW_STATE_PRESSED); 2036 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2037 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2038 | StateSet.VIEW_STATE_PRESSED); 2039 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2040 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2041 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2042 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2043 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2044 | StateSet.VIEW_STATE_PRESSED); 2045 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2046 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2047 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2048 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2049 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2050 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2051 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2052 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2053 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2054 | StateSet.VIEW_STATE_PRESSED); 2055 } 2056 2057 /** 2058 * Accessibility event types that are dispatched for text population. 2059 */ 2060 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2061 AccessibilityEvent.TYPE_VIEW_CLICKED 2062 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2063 | AccessibilityEvent.TYPE_VIEW_SELECTED 2064 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2065 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2066 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2067 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2068 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2069 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2070 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2071 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2072 2073 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2074 2075 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2076 2077 /** 2078 * Temporary Rect currently for use in setBackground(). This will probably 2079 * be extended in the future to hold our own class with more than just 2080 * a Rect. :) 2081 */ 2082 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2083 2084 /** 2085 * Map used to store views' tags. 2086 */ 2087 private SparseArray<Object> mKeyedTags; 2088 2089 /** 2090 * The next available accessibility id. 2091 */ 2092 private static int sNextAccessibilityViewId; 2093 2094 /** 2095 * The animation currently associated with this view. 2096 * @hide 2097 */ 2098 protected Animation mCurrentAnimation = null; 2099 2100 /** 2101 * Width as measured during measure pass. 2102 * {@hide} 2103 */ 2104 @ViewDebug.ExportedProperty(category = "measurement") 2105 int mMeasuredWidth; 2106 2107 /** 2108 * Height as measured during measure pass. 2109 * {@hide} 2110 */ 2111 @ViewDebug.ExportedProperty(category = "measurement") 2112 int mMeasuredHeight; 2113 2114 /** 2115 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2116 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2117 * its display list. This flag, used only when hw accelerated, allows us to clear the 2118 * flag while retaining this information until it's needed (at getDisplayList() time and 2119 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2120 * 2121 * {@hide} 2122 */ 2123 boolean mRecreateDisplayList = false; 2124 2125 /** 2126 * The view's identifier. 2127 * {@hide} 2128 * 2129 * @see #setId(int) 2130 * @see #getId() 2131 */ 2132 @IdRes 2133 @ViewDebug.ExportedProperty(resolveId = true) 2134 int mID = NO_ID; 2135 2136 /** The ID of this view for autofill purposes. 2137 * <ul> 2138 * <li>== {@link #NO_ID}: ID has not been assigned yet 2139 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2140 * unique in the process. This might change 2141 * over activity lifecycle events. 2142 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2143 * unique in the activity. This stays the same 2144 * over activity lifecycle events. 2145 */ 2146 private int mAutofillViewId = NO_ID; 2147 2148 // ID for accessibility purposes. This ID must be unique for every window 2149 private int mAccessibilityViewId = NO_ID; 2150 2151 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2152 2153 /** 2154 * The view's tag. 2155 * {@hide} 2156 * 2157 * @see #setTag(Object) 2158 * @see #getTag() 2159 */ 2160 protected Object mTag = null; 2161 2162 // for mPrivateFlags: 2163 /** {@hide} */ 2164 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2165 /** {@hide} */ 2166 static final int PFLAG_FOCUSED = 0x00000002; 2167 /** {@hide} */ 2168 static final int PFLAG_SELECTED = 0x00000004; 2169 /** {@hide} */ 2170 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2171 /** {@hide} */ 2172 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2173 /** {@hide} */ 2174 static final int PFLAG_DRAWN = 0x00000020; 2175 /** 2176 * When this flag is set, this view is running an animation on behalf of its 2177 * children and should therefore not cancel invalidate requests, even if they 2178 * lie outside of this view's bounds. 2179 * 2180 * {@hide} 2181 */ 2182 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2183 /** {@hide} */ 2184 static final int PFLAG_SKIP_DRAW = 0x00000080; 2185 /** {@hide} */ 2186 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2187 /** {@hide} */ 2188 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2189 /** {@hide} */ 2190 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2191 /** {@hide} */ 2192 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2193 /** {@hide} */ 2194 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2195 2196 private static final int PFLAG_PRESSED = 0x00004000; 2197 2198 /** {@hide} */ 2199 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2200 /** 2201 * Flag used to indicate that this view should be drawn once more (and only once 2202 * more) after its animation has completed. 2203 * {@hide} 2204 */ 2205 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2206 2207 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2208 2209 /** 2210 * Indicates that the View returned true when onSetAlpha() was called and that 2211 * the alpha must be restored. 2212 * {@hide} 2213 */ 2214 static final int PFLAG_ALPHA_SET = 0x00040000; 2215 2216 /** 2217 * Set by {@link #setScrollContainer(boolean)}. 2218 */ 2219 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2220 2221 /** 2222 * Set by {@link #setScrollContainer(boolean)}. 2223 */ 2224 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2225 2226 /** 2227 * View flag indicating whether this view was invalidated (fully or partially.) 2228 * 2229 * @hide 2230 */ 2231 static final int PFLAG_DIRTY = 0x00200000; 2232 2233 /** 2234 * View flag indicating whether this view was invalidated by an opaque 2235 * invalidate request. 2236 * 2237 * @hide 2238 */ 2239 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 2240 2241 /** 2242 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 2243 * 2244 * @hide 2245 */ 2246 static final int PFLAG_DIRTY_MASK = 0x00600000; 2247 2248 /** 2249 * Indicates whether the background is opaque. 2250 * 2251 * @hide 2252 */ 2253 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2254 2255 /** 2256 * Indicates whether the scrollbars are opaque. 2257 * 2258 * @hide 2259 */ 2260 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2261 2262 /** 2263 * Indicates whether the view is opaque. 2264 * 2265 * @hide 2266 */ 2267 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2268 2269 /** 2270 * Indicates a prepressed state; 2271 * the short time between ACTION_DOWN and recognizing 2272 * a 'real' press. Prepressed is used to recognize quick taps 2273 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2274 * 2275 * @hide 2276 */ 2277 private static final int PFLAG_PREPRESSED = 0x02000000; 2278 2279 /** 2280 * Indicates whether the view is temporarily detached. 2281 * 2282 * @hide 2283 */ 2284 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2285 2286 /** 2287 * Indicates that we should awaken scroll bars once attached 2288 * 2289 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2290 * during window attachment and it is no longer needed. Feel free to repurpose it. 2291 * 2292 * @hide 2293 */ 2294 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2295 2296 /** 2297 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2298 * @hide 2299 */ 2300 private static final int PFLAG_HOVERED = 0x10000000; 2301 2302 /** 2303 * no longer needed, should be reused 2304 */ 2305 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 2306 2307 /** {@hide} */ 2308 static final int PFLAG_ACTIVATED = 0x40000000; 2309 2310 /** 2311 * Indicates that this view was specifically invalidated, not just dirtied because some 2312 * child view was invalidated. The flag is used to determine when we need to recreate 2313 * a view's display list (as opposed to just returning a reference to its existing 2314 * display list). 2315 * 2316 * @hide 2317 */ 2318 static final int PFLAG_INVALIDATED = 0x80000000; 2319 2320 /** 2321 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2322 * 2323 * |-------|-------|-------|-------| 2324 * 1 PFLAG2_DRAG_CAN_ACCEPT 2325 * 1 PFLAG2_DRAG_HOVERED 2326 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2327 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2328 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2329 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2330 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2331 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2332 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2333 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2334 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2335 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2336 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2337 * 111 PFLAG2_TEXT_DIRECTION_MASK 2338 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2339 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2340 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2341 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2342 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2343 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2344 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2345 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2346 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2347 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2348 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2349 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2350 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2351 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2352 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2353 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2354 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2355 * 1 PFLAG2_VIEW_QUICK_REJECTED 2356 * 1 PFLAG2_PADDING_RESOLVED 2357 * 1 PFLAG2_DRAWABLE_RESOLVED 2358 * 1 PFLAG2_HAS_TRANSIENT_STATE 2359 * |-------|-------|-------|-------| 2360 */ 2361 2362 /** 2363 * Indicates that this view has reported that it can accept the current drag's content. 2364 * Cleared when the drag operation concludes. 2365 * @hide 2366 */ 2367 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2368 2369 /** 2370 * Indicates that this view is currently directly under the drag location in a 2371 * drag-and-drop operation involving content that it can accept. Cleared when 2372 * the drag exits the view, or when the drag operation concludes. 2373 * @hide 2374 */ 2375 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2376 2377 /** @hide */ 2378 @IntDef({ 2379 LAYOUT_DIRECTION_LTR, 2380 LAYOUT_DIRECTION_RTL, 2381 LAYOUT_DIRECTION_INHERIT, 2382 LAYOUT_DIRECTION_LOCALE 2383 }) 2384 @Retention(RetentionPolicy.SOURCE) 2385 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2386 public @interface LayoutDir {} 2387 2388 /** @hide */ 2389 @IntDef({ 2390 LAYOUT_DIRECTION_LTR, 2391 LAYOUT_DIRECTION_RTL 2392 }) 2393 @Retention(RetentionPolicy.SOURCE) 2394 public @interface ResolvedLayoutDir {} 2395 2396 /** 2397 * A flag to indicate that the layout direction of this view has not been defined yet. 2398 * @hide 2399 */ 2400 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2401 2402 /** 2403 * Horizontal layout direction of this view is from Left to Right. 2404 * Use with {@link #setLayoutDirection}. 2405 */ 2406 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2407 2408 /** 2409 * Horizontal layout direction of this view is from Right to Left. 2410 * Use with {@link #setLayoutDirection}. 2411 */ 2412 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2413 2414 /** 2415 * Horizontal layout direction of this view is inherited from its parent. 2416 * Use with {@link #setLayoutDirection}. 2417 */ 2418 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2419 2420 /** 2421 * Horizontal layout direction of this view is from deduced from the default language 2422 * script for the locale. Use with {@link #setLayoutDirection}. 2423 */ 2424 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2425 2426 /** 2427 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2428 * @hide 2429 */ 2430 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2431 2432 /** 2433 * Mask for use with private flags indicating bits used for horizontal layout direction. 2434 * @hide 2435 */ 2436 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2437 2438 /** 2439 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2440 * right-to-left direction. 2441 * @hide 2442 */ 2443 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2444 2445 /** 2446 * Indicates whether the view horizontal layout direction has been resolved. 2447 * @hide 2448 */ 2449 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2450 2451 /** 2452 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2453 * @hide 2454 */ 2455 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2456 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2457 2458 /* 2459 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2460 * flag value. 2461 * @hide 2462 */ 2463 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2464 LAYOUT_DIRECTION_LTR, 2465 LAYOUT_DIRECTION_RTL, 2466 LAYOUT_DIRECTION_INHERIT, 2467 LAYOUT_DIRECTION_LOCALE 2468 }; 2469 2470 /** 2471 * Default horizontal layout direction. 2472 */ 2473 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2474 2475 /** 2476 * Default horizontal layout direction. 2477 * @hide 2478 */ 2479 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2480 2481 /** 2482 * Text direction is inherited through {@link ViewGroup} 2483 */ 2484 public static final int TEXT_DIRECTION_INHERIT = 0; 2485 2486 /** 2487 * Text direction is using "first strong algorithm". The first strong directional character 2488 * determines the paragraph direction. If there is no strong directional character, the 2489 * paragraph direction is the view's resolved layout direction. 2490 */ 2491 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2492 2493 /** 2494 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2495 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2496 * If there are neither, the paragraph direction is the view's resolved layout direction. 2497 */ 2498 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2499 2500 /** 2501 * Text direction is forced to LTR. 2502 */ 2503 public static final int TEXT_DIRECTION_LTR = 3; 2504 2505 /** 2506 * Text direction is forced to RTL. 2507 */ 2508 public static final int TEXT_DIRECTION_RTL = 4; 2509 2510 /** 2511 * Text direction is coming from the system Locale. 2512 */ 2513 public static final int TEXT_DIRECTION_LOCALE = 5; 2514 2515 /** 2516 * Text direction is using "first strong algorithm". The first strong directional character 2517 * determines the paragraph direction. If there is no strong directional character, the 2518 * paragraph direction is LTR. 2519 */ 2520 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2521 2522 /** 2523 * Text direction is using "first strong algorithm". The first strong directional character 2524 * determines the paragraph direction. If there is no strong directional character, the 2525 * paragraph direction is RTL. 2526 */ 2527 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2528 2529 /** 2530 * Default text direction is inherited 2531 */ 2532 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2533 2534 /** 2535 * Default resolved text direction 2536 * @hide 2537 */ 2538 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2539 2540 /** 2541 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2542 * @hide 2543 */ 2544 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2545 2546 /** 2547 * Mask for use with private flags indicating bits used for text direction. 2548 * @hide 2549 */ 2550 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2551 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2552 2553 /** 2554 * Array of text direction flags for mapping attribute "textDirection" to correct 2555 * flag value. 2556 * @hide 2557 */ 2558 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2559 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2560 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2561 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2562 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2563 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2564 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2565 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2566 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2567 }; 2568 2569 /** 2570 * Indicates whether the view text direction has been resolved. 2571 * @hide 2572 */ 2573 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2574 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2575 2576 /** 2577 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2578 * @hide 2579 */ 2580 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2581 2582 /** 2583 * Mask for use with private flags indicating bits used for resolved text direction. 2584 * @hide 2585 */ 2586 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2587 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2588 2589 /** 2590 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2591 * @hide 2592 */ 2593 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2594 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2595 2596 /** @hide */ 2597 @IntDef({ 2598 TEXT_ALIGNMENT_INHERIT, 2599 TEXT_ALIGNMENT_GRAVITY, 2600 TEXT_ALIGNMENT_CENTER, 2601 TEXT_ALIGNMENT_TEXT_START, 2602 TEXT_ALIGNMENT_TEXT_END, 2603 TEXT_ALIGNMENT_VIEW_START, 2604 TEXT_ALIGNMENT_VIEW_END 2605 }) 2606 @Retention(RetentionPolicy.SOURCE) 2607 public @interface TextAlignment {} 2608 2609 /** 2610 * Default text alignment. The text alignment of this View is inherited from its parent. 2611 * Use with {@link #setTextAlignment(int)} 2612 */ 2613 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2614 2615 /** 2616 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2617 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2618 * 2619 * Use with {@link #setTextAlignment(int)} 2620 */ 2621 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2622 2623 /** 2624 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2625 * 2626 * Use with {@link #setTextAlignment(int)} 2627 */ 2628 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2629 2630 /** 2631 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2632 * 2633 * Use with {@link #setTextAlignment(int)} 2634 */ 2635 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2636 2637 /** 2638 * Center the paragraph, e.g. ALIGN_CENTER. 2639 * 2640 * Use with {@link #setTextAlignment(int)} 2641 */ 2642 public static final int TEXT_ALIGNMENT_CENTER = 4; 2643 2644 /** 2645 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2646 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2647 * 2648 * Use with {@link #setTextAlignment(int)} 2649 */ 2650 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2651 2652 /** 2653 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2654 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2655 * 2656 * Use with {@link #setTextAlignment(int)} 2657 */ 2658 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2659 2660 /** 2661 * Default text alignment is inherited 2662 */ 2663 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2664 2665 /** 2666 * Default resolved text alignment 2667 * @hide 2668 */ 2669 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2670 2671 /** 2672 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2673 * @hide 2674 */ 2675 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2676 2677 /** 2678 * Mask for use with private flags indicating bits used for text alignment. 2679 * @hide 2680 */ 2681 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2682 2683 /** 2684 * Array of text direction flags for mapping attribute "textAlignment" to correct 2685 * flag value. 2686 * @hide 2687 */ 2688 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2689 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2690 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2691 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2692 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2693 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2694 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2695 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2696 }; 2697 2698 /** 2699 * Indicates whether the view text alignment has been resolved. 2700 * @hide 2701 */ 2702 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2703 2704 /** 2705 * Bit shift to get the resolved text alignment. 2706 * @hide 2707 */ 2708 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2709 2710 /** 2711 * Mask for use with private flags indicating bits used for text alignment. 2712 * @hide 2713 */ 2714 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2715 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2716 2717 /** 2718 * Indicates whether if the view text alignment has been resolved to gravity 2719 */ 2720 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2721 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2722 2723 // Accessiblity constants for mPrivateFlags2 2724 2725 /** 2726 * Shift for the bits in {@link #mPrivateFlags2} related to the 2727 * "importantForAccessibility" attribute. 2728 */ 2729 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2730 2731 /** 2732 * Automatically determine whether a view is important for accessibility. 2733 */ 2734 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2735 2736 /** 2737 * The view is important for accessibility. 2738 */ 2739 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2740 2741 /** 2742 * The view is not important for accessibility. 2743 */ 2744 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2745 2746 /** 2747 * The view is not important for accessibility, nor are any of its 2748 * descendant views. 2749 */ 2750 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2751 2752 /** 2753 * The default whether the view is important for accessibility. 2754 */ 2755 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2756 2757 /** 2758 * Mask for obtaining the bits which specify how to determine 2759 * whether a view is important for accessibility. 2760 */ 2761 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2762 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2763 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2764 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2765 2766 /** 2767 * Shift for the bits in {@link #mPrivateFlags2} related to the 2768 * "accessibilityLiveRegion" attribute. 2769 */ 2770 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2771 2772 /** 2773 * Live region mode specifying that accessibility services should not 2774 * automatically announce changes to this view. This is the default live 2775 * region mode for most views. 2776 * <p> 2777 * Use with {@link #setAccessibilityLiveRegion(int)}. 2778 */ 2779 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2780 2781 /** 2782 * Live region mode specifying that accessibility services should announce 2783 * changes to this view. 2784 * <p> 2785 * Use with {@link #setAccessibilityLiveRegion(int)}. 2786 */ 2787 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2788 2789 /** 2790 * Live region mode specifying that accessibility services should interrupt 2791 * ongoing speech to immediately announce changes to this view. 2792 * <p> 2793 * Use with {@link #setAccessibilityLiveRegion(int)}. 2794 */ 2795 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2796 2797 /** 2798 * The default whether the view is important for accessibility. 2799 */ 2800 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2801 2802 /** 2803 * Mask for obtaining the bits which specify a view's accessibility live 2804 * region mode. 2805 */ 2806 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2807 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2808 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2809 2810 /** 2811 * Flag indicating whether a view has accessibility focus. 2812 */ 2813 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2814 2815 /** 2816 * Flag whether the accessibility state of the subtree rooted at this view changed. 2817 */ 2818 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2819 2820 /** 2821 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2822 * is used to check whether later changes to the view's transform should invalidate the 2823 * view to force the quickReject test to run again. 2824 */ 2825 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2826 2827 /** 2828 * Flag indicating that start/end padding has been resolved into left/right padding 2829 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2830 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2831 * during measurement. In some special cases this is required such as when an adapter-based 2832 * view measures prospective children without attaching them to a window. 2833 */ 2834 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2835 2836 /** 2837 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2838 */ 2839 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2840 2841 /** 2842 * Indicates that the view is tracking some sort of transient state 2843 * that the app should not need to be aware of, but that the framework 2844 * should take special care to preserve. 2845 */ 2846 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2847 2848 /** 2849 * Group of bits indicating that RTL properties resolution is done. 2850 */ 2851 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2852 PFLAG2_TEXT_DIRECTION_RESOLVED | 2853 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2854 PFLAG2_PADDING_RESOLVED | 2855 PFLAG2_DRAWABLE_RESOLVED; 2856 2857 // There are a couple of flags left in mPrivateFlags2 2858 2859 /* End of masks for mPrivateFlags2 */ 2860 2861 /** 2862 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2863 * 2864 * |-------|-------|-------|-------| 2865 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2866 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2867 * 1 PFLAG3_IS_LAID_OUT 2868 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2869 * 1 PFLAG3_CALLED_SUPER 2870 * 1 PFLAG3_APPLYING_INSETS 2871 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2872 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2873 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2874 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2875 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2876 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2877 * 1 PFLAG3_SCROLL_INDICATOR_START 2878 * 1 PFLAG3_SCROLL_INDICATOR_END 2879 * 1 PFLAG3_ASSIST_BLOCKED 2880 * 1 PFLAG3_CLUSTER 2881 * 1 PFLAG3_IS_AUTOFILLED 2882 * 1 PFLAG3_FINGER_DOWN 2883 * 1 PFLAG3_FOCUSED_BY_DEFAULT 2884 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 2885 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2886 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2887 * 1 PFLAG3_TEMPORARY_DETACH 2888 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2889 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 2890 * |-------|-------|-------|-------| 2891 */ 2892 2893 /** 2894 * Flag indicating that view has a transform animation set on it. This is used to track whether 2895 * an animation is cleared between successive frames, in order to tell the associated 2896 * DisplayList to clear its animation matrix. 2897 */ 2898 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2899 2900 /** 2901 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2902 * animation is cleared between successive frames, in order to tell the associated 2903 * DisplayList to restore its alpha value. 2904 */ 2905 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2906 2907 /** 2908 * Flag indicating that the view has been through at least one layout since it 2909 * was last attached to a window. 2910 */ 2911 static final int PFLAG3_IS_LAID_OUT = 0x4; 2912 2913 /** 2914 * Flag indicating that a call to measure() was skipped and should be done 2915 * instead when layout() is invoked. 2916 */ 2917 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2918 2919 /** 2920 * Flag indicating that an overridden method correctly called down to 2921 * the superclass implementation as required by the API spec. 2922 */ 2923 static final int PFLAG3_CALLED_SUPER = 0x10; 2924 2925 /** 2926 * Flag indicating that we're in the process of applying window insets. 2927 */ 2928 static final int PFLAG3_APPLYING_INSETS = 0x20; 2929 2930 /** 2931 * Flag indicating that we're in the process of fitting system windows using the old method. 2932 */ 2933 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2934 2935 /** 2936 * Flag indicating that nested scrolling is enabled for this view. 2937 * The view will optionally cooperate with views up its parent chain to allow for 2938 * integrated nested scrolling along the same axis. 2939 */ 2940 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2941 2942 /** 2943 * Flag indicating that the bottom scroll indicator should be displayed 2944 * when this view can scroll up. 2945 */ 2946 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2947 2948 /** 2949 * Flag indicating that the bottom scroll indicator should be displayed 2950 * when this view can scroll down. 2951 */ 2952 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2953 2954 /** 2955 * Flag indicating that the left scroll indicator should be displayed 2956 * when this view can scroll left. 2957 */ 2958 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2959 2960 /** 2961 * Flag indicating that the right scroll indicator should be displayed 2962 * when this view can scroll right. 2963 */ 2964 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2965 2966 /** 2967 * Flag indicating that the start scroll indicator should be displayed 2968 * when this view can scroll in the start direction. 2969 */ 2970 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2971 2972 /** 2973 * Flag indicating that the end scroll indicator should be displayed 2974 * when this view can scroll in the end direction. 2975 */ 2976 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2977 2978 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2979 2980 static final int SCROLL_INDICATORS_NONE = 0x0000; 2981 2982 /** 2983 * Mask for use with setFlags indicating bits used for indicating which 2984 * scroll indicators are enabled. 2985 */ 2986 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2987 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2988 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2989 | PFLAG3_SCROLL_INDICATOR_END; 2990 2991 /** 2992 * Left-shift required to translate between public scroll indicator flags 2993 * and internal PFLAGS3 flags. When used as a right-shift, translates 2994 * PFLAGS3 flags to public flags. 2995 */ 2996 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2997 2998 /** @hide */ 2999 @Retention(RetentionPolicy.SOURCE) 3000 @IntDef(flag = true, 3001 value = { 3002 SCROLL_INDICATOR_TOP, 3003 SCROLL_INDICATOR_BOTTOM, 3004 SCROLL_INDICATOR_LEFT, 3005 SCROLL_INDICATOR_RIGHT, 3006 SCROLL_INDICATOR_START, 3007 SCROLL_INDICATOR_END, 3008 }) 3009 public @interface ScrollIndicators {} 3010 3011 /** 3012 * Scroll indicator direction for the top edge of the view. 3013 * 3014 * @see #setScrollIndicators(int) 3015 * @see #setScrollIndicators(int, int) 3016 * @see #getScrollIndicators() 3017 */ 3018 public static final int SCROLL_INDICATOR_TOP = 3019 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3020 3021 /** 3022 * Scroll indicator direction for the bottom edge of the view. 3023 * 3024 * @see #setScrollIndicators(int) 3025 * @see #setScrollIndicators(int, int) 3026 * @see #getScrollIndicators() 3027 */ 3028 public static final int SCROLL_INDICATOR_BOTTOM = 3029 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3030 3031 /** 3032 * Scroll indicator direction for the left edge of the view. 3033 * 3034 * @see #setScrollIndicators(int) 3035 * @see #setScrollIndicators(int, int) 3036 * @see #getScrollIndicators() 3037 */ 3038 public static final int SCROLL_INDICATOR_LEFT = 3039 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3040 3041 /** 3042 * Scroll indicator direction for the right edge of the view. 3043 * 3044 * @see #setScrollIndicators(int) 3045 * @see #setScrollIndicators(int, int) 3046 * @see #getScrollIndicators() 3047 */ 3048 public static final int SCROLL_INDICATOR_RIGHT = 3049 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3050 3051 /** 3052 * Scroll indicator direction for the starting edge of the view. 3053 * <p> 3054 * Resolved according to the view's layout direction, see 3055 * {@link #getLayoutDirection()} for more information. 3056 * 3057 * @see #setScrollIndicators(int) 3058 * @see #setScrollIndicators(int, int) 3059 * @see #getScrollIndicators() 3060 */ 3061 public static final int SCROLL_INDICATOR_START = 3062 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3063 3064 /** 3065 * Scroll indicator direction for the ending edge of the view. 3066 * <p> 3067 * Resolved according to the view's layout direction, see 3068 * {@link #getLayoutDirection()} for more information. 3069 * 3070 * @see #setScrollIndicators(int) 3071 * @see #setScrollIndicators(int, int) 3072 * @see #getScrollIndicators() 3073 */ 3074 public static final int SCROLL_INDICATOR_END = 3075 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3076 3077 /** 3078 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3079 * into this view.<p> 3080 */ 3081 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3082 3083 /** 3084 * Flag indicating that the view is a root of a keyboard navigation cluster. 3085 * 3086 * @see #isKeyboardNavigationCluster() 3087 * @see #setKeyboardNavigationCluster(boolean) 3088 */ 3089 private static final int PFLAG3_CLUSTER = 0x8000; 3090 3091 /** 3092 * Flag indicating that the view is autofilled 3093 * 3094 * @see #isAutofilled() 3095 * @see #setAutofilled(boolean) 3096 */ 3097 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3098 3099 /** 3100 * Indicates that the user is currently touching the screen. 3101 * Currently used for the tooltip positioning only. 3102 */ 3103 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3104 3105 /** 3106 * Flag indicating that this view is the default-focus view. 3107 * 3108 * @see #isFocusedByDefault() 3109 * @see #setFocusedByDefault(boolean) 3110 */ 3111 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3112 3113 /** 3114 * Shift for the bits in {@link #mPrivateFlags3} related to the 3115 * "importantForAutofill" attribute. 3116 */ 3117 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3118 3119 /** 3120 * Mask for obtaining the bits which specify how to determine 3121 * whether a view is important for autofill. 3122 */ 3123 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3124 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3125 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3126 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3127 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3128 3129 /** 3130 * Whether this view has rendered elements that overlap (see {@link 3131 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3132 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3133 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3134 * determined by whatever {@link #hasOverlappingRendering()} returns. 3135 */ 3136 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3137 3138 /** 3139 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3140 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3141 */ 3142 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3143 3144 /** 3145 * Flag indicating that the view is temporarily detached from the parent view. 3146 * 3147 * @see #onStartTemporaryDetach() 3148 * @see #onFinishTemporaryDetach() 3149 */ 3150 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3151 3152 /** 3153 * Flag indicating that the view does not wish to be revealed within its parent 3154 * hierarchy when it gains focus. Expressed in the negative since the historical 3155 * default behavior is to reveal on focus; this flag suppresses that behavior. 3156 * 3157 * @see #setRevealOnFocusHint(boolean) 3158 * @see #getRevealOnFocusHint() 3159 */ 3160 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3161 3162 /** 3163 * Flag indicating that when layout is completed we should notify 3164 * that the view was entered for autofill purposes. To minimize 3165 * showing autofill for views not visible to the user we evaluate 3166 * user visibility which cannot be done until the view is laid out. 3167 */ 3168 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3169 3170 /* End of masks for mPrivateFlags3 */ 3171 3172 /** 3173 * Always allow a user to over-scroll this view, provided it is a 3174 * view that can scroll. 3175 * 3176 * @see #getOverScrollMode() 3177 * @see #setOverScrollMode(int) 3178 */ 3179 public static final int OVER_SCROLL_ALWAYS = 0; 3180 3181 /** 3182 * Allow a user to over-scroll this view only if the content is large 3183 * enough to meaningfully scroll, provided it is a view that can scroll. 3184 * 3185 * @see #getOverScrollMode() 3186 * @see #setOverScrollMode(int) 3187 */ 3188 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3189 3190 /** 3191 * Never allow a user to over-scroll this view. 3192 * 3193 * @see #getOverScrollMode() 3194 * @see #setOverScrollMode(int) 3195 */ 3196 public static final int OVER_SCROLL_NEVER = 2; 3197 3198 /** 3199 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3200 * requested the system UI (status bar) to be visible (the default). 3201 * 3202 * @see #setSystemUiVisibility(int) 3203 */ 3204 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3205 3206 /** 3207 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3208 * system UI to enter an unobtrusive "low profile" mode. 3209 * 3210 * <p>This is for use in games, book readers, video players, or any other 3211 * "immersive" application where the usual system chrome is deemed too distracting. 3212 * 3213 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3214 * 3215 * @see #setSystemUiVisibility(int) 3216 */ 3217 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3218 3219 /** 3220 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3221 * system navigation be temporarily hidden. 3222 * 3223 * <p>This is an even less obtrusive state than that called for by 3224 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3225 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3226 * those to disappear. This is useful (in conjunction with the 3227 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3228 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3229 * window flags) for displaying content using every last pixel on the display. 3230 * 3231 * <p>There is a limitation: because navigation controls are so important, the least user 3232 * interaction will cause them to reappear immediately. When this happens, both 3233 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3234 * so that both elements reappear at the same time. 3235 * 3236 * @see #setSystemUiVisibility(int) 3237 */ 3238 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3239 3240 /** 3241 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3242 * into the normal fullscreen mode so that its content can take over the screen 3243 * while still allowing the user to interact with the application. 3244 * 3245 * <p>This has the same visual effect as 3246 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3247 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3248 * meaning that non-critical screen decorations (such as the status bar) will be 3249 * hidden while the user is in the View's window, focusing the experience on 3250 * that content. Unlike the window flag, if you are using ActionBar in 3251 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3252 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3253 * hide the action bar. 3254 * 3255 * <p>This approach to going fullscreen is best used over the window flag when 3256 * it is a transient state -- that is, the application does this at certain 3257 * points in its user interaction where it wants to allow the user to focus 3258 * on content, but not as a continuous state. For situations where the application 3259 * would like to simply stay full screen the entire time (such as a game that 3260 * wants to take over the screen), the 3261 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3262 * is usually a better approach. The state set here will be removed by the system 3263 * in various situations (such as the user moving to another application) like 3264 * the other system UI states. 3265 * 3266 * <p>When using this flag, the application should provide some easy facility 3267 * for the user to go out of it. A common example would be in an e-book 3268 * reader, where tapping on the screen brings back whatever screen and UI 3269 * decorations that had been hidden while the user was immersed in reading 3270 * the book. 3271 * 3272 * @see #setSystemUiVisibility(int) 3273 */ 3274 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3275 3276 /** 3277 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3278 * flags, we would like a stable view of the content insets given to 3279 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3280 * will always represent the worst case that the application can expect 3281 * as a continuous state. In the stock Android UI this is the space for 3282 * the system bar, nav bar, and status bar, but not more transient elements 3283 * such as an input method. 3284 * 3285 * The stable layout your UI sees is based on the system UI modes you can 3286 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3287 * then you will get a stable layout for changes of the 3288 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3289 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3290 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3291 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3292 * with a stable layout. (Note that you should avoid using 3293 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3294 * 3295 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3296 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3297 * then a hidden status bar will be considered a "stable" state for purposes 3298 * here. This allows your UI to continually hide the status bar, while still 3299 * using the system UI flags to hide the action bar while still retaining 3300 * a stable layout. Note that changing the window fullscreen flag will never 3301 * provide a stable layout for a clean transition. 3302 * 3303 * <p>If you are using ActionBar in 3304 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3305 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3306 * insets it adds to those given to the application. 3307 */ 3308 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3309 3310 /** 3311 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3312 * to be laid out as if it has requested 3313 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3314 * allows it to avoid artifacts when switching in and out of that mode, at 3315 * the expense that some of its user interface may be covered by screen 3316 * decorations when they are shown. You can perform layout of your inner 3317 * UI elements to account for the navigation system UI through the 3318 * {@link #fitSystemWindows(Rect)} method. 3319 */ 3320 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3321 3322 /** 3323 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3324 * to be laid out as if it has requested 3325 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3326 * allows it to avoid artifacts when switching in and out of that mode, at 3327 * the expense that some of its user interface may be covered by screen 3328 * decorations when they are shown. You can perform layout of your inner 3329 * UI elements to account for non-fullscreen system UI through the 3330 * {@link #fitSystemWindows(Rect)} method. 3331 */ 3332 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3333 3334 /** 3335 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3336 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3337 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3338 * user interaction. 3339 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3340 * has an effect when used in combination with that flag.</p> 3341 */ 3342 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3343 3344 /** 3345 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3346 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3347 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3348 * experience while also hiding the system bars. If this flag is not set, 3349 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3350 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3351 * if the user swipes from the top of the screen. 3352 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3353 * system gestures, such as swiping from the top of the screen. These transient system bars 3354 * will overlay app’s content, may have some degree of transparency, and will automatically 3355 * hide after a short timeout. 3356 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3357 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3358 * with one or both of those flags.</p> 3359 */ 3360 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3361 3362 /** 3363 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3364 * is compatible with light status bar backgrounds. 3365 * 3366 * <p>For this to take effect, the window must request 3367 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3368 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3369 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3370 * FLAG_TRANSLUCENT_STATUS}. 3371 * 3372 * @see android.R.attr#windowLightStatusBar 3373 */ 3374 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3375 3376 /** 3377 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3378 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3379 */ 3380 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3381 3382 /** 3383 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3384 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3385 */ 3386 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3387 3388 /** 3389 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3390 * that is compatible with light navigation bar backgrounds. 3391 * 3392 * <p>For this to take effect, the window must request 3393 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3394 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3395 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3396 * FLAG_TRANSLUCENT_NAVIGATION}. 3397 */ 3398 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3399 3400 /** 3401 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3402 */ 3403 @Deprecated 3404 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3405 3406 /** 3407 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3408 */ 3409 @Deprecated 3410 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3411 3412 /** 3413 * @hide 3414 * 3415 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3416 * out of the public fields to keep the undefined bits out of the developer's way. 3417 * 3418 * Flag to make the status bar not expandable. Unless you also 3419 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3420 */ 3421 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3422 3423 /** 3424 * @hide 3425 * 3426 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3427 * out of the public fields to keep the undefined bits out of the developer's way. 3428 * 3429 * Flag to hide notification icons and scrolling ticker text. 3430 */ 3431 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3432 3433 /** 3434 * @hide 3435 * 3436 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3437 * out of the public fields to keep the undefined bits out of the developer's way. 3438 * 3439 * Flag to disable incoming notification alerts. This will not block 3440 * icons, but it will block sound, vibrating and other visual or aural notifications. 3441 */ 3442 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3443 3444 /** 3445 * @hide 3446 * 3447 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3448 * out of the public fields to keep the undefined bits out of the developer's way. 3449 * 3450 * Flag to hide only the scrolling ticker. Note that 3451 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3452 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3453 */ 3454 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3455 3456 /** 3457 * @hide 3458 * 3459 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3460 * out of the public fields to keep the undefined bits out of the developer's way. 3461 * 3462 * Flag to hide the center system info area. 3463 */ 3464 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3465 3466 /** 3467 * @hide 3468 * 3469 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3470 * out of the public fields to keep the undefined bits out of the developer's way. 3471 * 3472 * Flag to hide only the home button. Don't use this 3473 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3474 */ 3475 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3476 3477 /** 3478 * @hide 3479 * 3480 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3481 * out of the public fields to keep the undefined bits out of the developer's way. 3482 * 3483 * Flag to hide only the back button. Don't use this 3484 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3485 */ 3486 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3487 3488 /** 3489 * @hide 3490 * 3491 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3492 * out of the public fields to keep the undefined bits out of the developer's way. 3493 * 3494 * Flag to hide only the clock. You might use this if your activity has 3495 * its own clock making the status bar's clock redundant. 3496 */ 3497 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3498 3499 /** 3500 * @hide 3501 * 3502 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3503 * out of the public fields to keep the undefined bits out of the developer's way. 3504 * 3505 * Flag to hide only the recent apps button. Don't use this 3506 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3507 */ 3508 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3509 3510 /** 3511 * @hide 3512 * 3513 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3514 * out of the public fields to keep the undefined bits out of the developer's way. 3515 * 3516 * Flag to disable the global search gesture. Don't use this 3517 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3518 */ 3519 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3520 3521 /** 3522 * @hide 3523 * 3524 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3525 * out of the public fields to keep the undefined bits out of the developer's way. 3526 * 3527 * Flag to specify that the status bar is displayed in transient mode. 3528 */ 3529 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3530 3531 /** 3532 * @hide 3533 * 3534 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3535 * out of the public fields to keep the undefined bits out of the developer's way. 3536 * 3537 * Flag to specify that the navigation bar is displayed in transient mode. 3538 */ 3539 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3540 3541 /** 3542 * @hide 3543 * 3544 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3545 * out of the public fields to keep the undefined bits out of the developer's way. 3546 * 3547 * Flag to specify that the hidden status bar would like to be shown. 3548 */ 3549 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3550 3551 /** 3552 * @hide 3553 * 3554 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3555 * out of the public fields to keep the undefined bits out of the developer's way. 3556 * 3557 * Flag to specify that the hidden navigation bar would like to be shown. 3558 */ 3559 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3560 3561 /** 3562 * @hide 3563 * 3564 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3565 * out of the public fields to keep the undefined bits out of the developer's way. 3566 * 3567 * Flag to specify that the status bar is displayed in translucent mode. 3568 */ 3569 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3570 3571 /** 3572 * @hide 3573 * 3574 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3575 * out of the public fields to keep the undefined bits out of the developer's way. 3576 * 3577 * Flag to specify that the navigation bar is displayed in translucent mode. 3578 */ 3579 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3580 3581 /** 3582 * @hide 3583 * 3584 * Makes navigation bar transparent (but not the status bar). 3585 */ 3586 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3587 3588 /** 3589 * @hide 3590 * 3591 * Makes status bar transparent (but not the navigation bar). 3592 */ 3593 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3594 3595 /** 3596 * @hide 3597 * 3598 * Makes both status bar and navigation bar transparent. 3599 */ 3600 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3601 | STATUS_BAR_TRANSPARENT; 3602 3603 /** 3604 * @hide 3605 */ 3606 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3607 3608 /** 3609 * These are the system UI flags that can be cleared by events outside 3610 * of an application. Currently this is just the ability to tap on the 3611 * screen while hiding the navigation bar to have it return. 3612 * @hide 3613 */ 3614 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3615 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3616 | SYSTEM_UI_FLAG_FULLSCREEN; 3617 3618 /** 3619 * Flags that can impact the layout in relation to system UI. 3620 */ 3621 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3622 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3623 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3624 3625 /** @hide */ 3626 @IntDef(flag = true, 3627 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3628 @Retention(RetentionPolicy.SOURCE) 3629 public @interface FindViewFlags {} 3630 3631 /** 3632 * Find views that render the specified text. 3633 * 3634 * @see #findViewsWithText(ArrayList, CharSequence, int) 3635 */ 3636 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3637 3638 /** 3639 * Find find views that contain the specified content description. 3640 * 3641 * @see #findViewsWithText(ArrayList, CharSequence, int) 3642 */ 3643 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3644 3645 /** 3646 * Find views that contain {@link AccessibilityNodeProvider}. Such 3647 * a View is a root of virtual view hierarchy and may contain the searched 3648 * text. If this flag is set Views with providers are automatically 3649 * added and it is a responsibility of the client to call the APIs of 3650 * the provider to determine whether the virtual tree rooted at this View 3651 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3652 * representing the virtual views with this text. 3653 * 3654 * @see #findViewsWithText(ArrayList, CharSequence, int) 3655 * 3656 * @hide 3657 */ 3658 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3659 3660 /** 3661 * The undefined cursor position. 3662 * 3663 * @hide 3664 */ 3665 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3666 3667 /** 3668 * Indicates that the screen has changed state and is now off. 3669 * 3670 * @see #onScreenStateChanged(int) 3671 */ 3672 public static final int SCREEN_STATE_OFF = 0x0; 3673 3674 /** 3675 * Indicates that the screen has changed state and is now on. 3676 * 3677 * @see #onScreenStateChanged(int) 3678 */ 3679 public static final int SCREEN_STATE_ON = 0x1; 3680 3681 /** 3682 * Indicates no axis of view scrolling. 3683 */ 3684 public static final int SCROLL_AXIS_NONE = 0; 3685 3686 /** 3687 * Indicates scrolling along the horizontal axis. 3688 */ 3689 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3690 3691 /** 3692 * Indicates scrolling along the vertical axis. 3693 */ 3694 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3695 3696 /** 3697 * Controls the over-scroll mode for this view. 3698 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3699 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3700 * and {@link #OVER_SCROLL_NEVER}. 3701 */ 3702 private int mOverScrollMode; 3703 3704 /** 3705 * The parent this view is attached to. 3706 * {@hide} 3707 * 3708 * @see #getParent() 3709 */ 3710 protected ViewParent mParent; 3711 3712 /** 3713 * {@hide} 3714 */ 3715 AttachInfo mAttachInfo; 3716 3717 /** 3718 * {@hide} 3719 */ 3720 @ViewDebug.ExportedProperty(flagMapping = { 3721 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3722 name = "FORCE_LAYOUT"), 3723 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3724 name = "LAYOUT_REQUIRED"), 3725 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3726 name = "DRAWING_CACHE_INVALID", outputIf = false), 3727 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3728 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3729 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3730 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3731 }, formatToHexString = true) 3732 3733 /* @hide */ 3734 public int mPrivateFlags; 3735 int mPrivateFlags2; 3736 int mPrivateFlags3; 3737 3738 /** 3739 * This view's request for the visibility of the status bar. 3740 * @hide 3741 */ 3742 @ViewDebug.ExportedProperty(flagMapping = { 3743 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3744 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3745 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3746 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3747 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3748 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3749 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3750 equals = SYSTEM_UI_FLAG_VISIBLE, 3751 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3752 }, formatToHexString = true) 3753 int mSystemUiVisibility; 3754 3755 /** 3756 * Reference count for transient state. 3757 * @see #setHasTransientState(boolean) 3758 */ 3759 int mTransientStateCount = 0; 3760 3761 /** 3762 * Count of how many windows this view has been attached to. 3763 */ 3764 int mWindowAttachCount; 3765 3766 /** 3767 * The layout parameters associated with this view and used by the parent 3768 * {@link android.view.ViewGroup} to determine how this view should be 3769 * laid out. 3770 * {@hide} 3771 */ 3772 protected ViewGroup.LayoutParams mLayoutParams; 3773 3774 /** 3775 * The view flags hold various views states. 3776 * {@hide} 3777 */ 3778 @ViewDebug.ExportedProperty(formatToHexString = true) 3779 int mViewFlags; 3780 3781 static class TransformationInfo { 3782 /** 3783 * The transform matrix for the View. This transform is calculated internally 3784 * based on the translation, rotation, and scale properties. 3785 * 3786 * Do *not* use this variable directly; instead call getMatrix(), which will 3787 * load the value from the View's RenderNode. 3788 */ 3789 private final Matrix mMatrix = new Matrix(); 3790 3791 /** 3792 * The inverse transform matrix for the View. This transform is calculated 3793 * internally based on the translation, rotation, and scale properties. 3794 * 3795 * Do *not* use this variable directly; instead call getInverseMatrix(), 3796 * which will load the value from the View's RenderNode. 3797 */ 3798 private Matrix mInverseMatrix; 3799 3800 /** 3801 * The opacity of the View. This is a value from 0 to 1, where 0 means 3802 * completely transparent and 1 means completely opaque. 3803 */ 3804 @ViewDebug.ExportedProperty 3805 float mAlpha = 1f; 3806 3807 /** 3808 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3809 * property only used by transitions, which is composited with the other alpha 3810 * values to calculate the final visual alpha value. 3811 */ 3812 float mTransitionAlpha = 1f; 3813 } 3814 3815 /** @hide */ 3816 public TransformationInfo mTransformationInfo; 3817 3818 /** 3819 * Current clip bounds. to which all drawing of this view are constrained. 3820 */ 3821 Rect mClipBounds = null; 3822 3823 private boolean mLastIsOpaque; 3824 3825 /** 3826 * The distance in pixels from the left edge of this view's parent 3827 * to the left edge of this view. 3828 * {@hide} 3829 */ 3830 @ViewDebug.ExportedProperty(category = "layout") 3831 protected int mLeft; 3832 /** 3833 * The distance in pixels from the left edge of this view's parent 3834 * to the right edge of this view. 3835 * {@hide} 3836 */ 3837 @ViewDebug.ExportedProperty(category = "layout") 3838 protected int mRight; 3839 /** 3840 * The distance in pixels from the top edge of this view's parent 3841 * to the top edge of this view. 3842 * {@hide} 3843 */ 3844 @ViewDebug.ExportedProperty(category = "layout") 3845 protected int mTop; 3846 /** 3847 * The distance in pixels from the top edge of this view's parent 3848 * to the bottom edge of this view. 3849 * {@hide} 3850 */ 3851 @ViewDebug.ExportedProperty(category = "layout") 3852 protected int mBottom; 3853 3854 /** 3855 * The offset, in pixels, by which the content of this view is scrolled 3856 * horizontally. 3857 * {@hide} 3858 */ 3859 @ViewDebug.ExportedProperty(category = "scrolling") 3860 protected int mScrollX; 3861 /** 3862 * The offset, in pixels, by which the content of this view is scrolled 3863 * vertically. 3864 * {@hide} 3865 */ 3866 @ViewDebug.ExportedProperty(category = "scrolling") 3867 protected int mScrollY; 3868 3869 /** 3870 * The left padding in pixels, that is the distance in pixels between the 3871 * left edge of this view and the left edge of its content. 3872 * {@hide} 3873 */ 3874 @ViewDebug.ExportedProperty(category = "padding") 3875 protected int mPaddingLeft = 0; 3876 /** 3877 * The right padding in pixels, that is the distance in pixels between the 3878 * right edge of this view and the right edge of its content. 3879 * {@hide} 3880 */ 3881 @ViewDebug.ExportedProperty(category = "padding") 3882 protected int mPaddingRight = 0; 3883 /** 3884 * The top padding in pixels, that is the distance in pixels between the 3885 * top edge of this view and the top edge of its content. 3886 * {@hide} 3887 */ 3888 @ViewDebug.ExportedProperty(category = "padding") 3889 protected int mPaddingTop; 3890 /** 3891 * The bottom padding in pixels, that is the distance in pixels between the 3892 * bottom edge of this view and the bottom edge of its content. 3893 * {@hide} 3894 */ 3895 @ViewDebug.ExportedProperty(category = "padding") 3896 protected int mPaddingBottom; 3897 3898 /** 3899 * The layout insets in pixels, that is the distance in pixels between the 3900 * visible edges of this view its bounds. 3901 */ 3902 private Insets mLayoutInsets; 3903 3904 /** 3905 * Briefly describes the view and is primarily used for accessibility support. 3906 */ 3907 private CharSequence mContentDescription; 3908 3909 /** 3910 * Specifies the id of a view for which this view serves as a label for 3911 * accessibility purposes. 3912 */ 3913 private int mLabelForId = View.NO_ID; 3914 3915 /** 3916 * Predicate for matching labeled view id with its label for 3917 * accessibility purposes. 3918 */ 3919 private MatchLabelForPredicate mMatchLabelForPredicate; 3920 3921 /** 3922 * Specifies a view before which this one is visited in accessibility traversal. 3923 */ 3924 private int mAccessibilityTraversalBeforeId = NO_ID; 3925 3926 /** 3927 * Specifies a view after which this one is visited in accessibility traversal. 3928 */ 3929 private int mAccessibilityTraversalAfterId = NO_ID; 3930 3931 /** 3932 * Predicate for matching a view by its id. 3933 */ 3934 private MatchIdPredicate mMatchIdPredicate; 3935 3936 /** 3937 * Cache the paddingRight set by the user to append to the scrollbar's size. 3938 * 3939 * @hide 3940 */ 3941 @ViewDebug.ExportedProperty(category = "padding") 3942 protected int mUserPaddingRight; 3943 3944 /** 3945 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3946 * 3947 * @hide 3948 */ 3949 @ViewDebug.ExportedProperty(category = "padding") 3950 protected int mUserPaddingBottom; 3951 3952 /** 3953 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3954 * 3955 * @hide 3956 */ 3957 @ViewDebug.ExportedProperty(category = "padding") 3958 protected int mUserPaddingLeft; 3959 3960 /** 3961 * Cache the paddingStart set by the user to append to the scrollbar's size. 3962 * 3963 */ 3964 @ViewDebug.ExportedProperty(category = "padding") 3965 int mUserPaddingStart; 3966 3967 /** 3968 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3969 * 3970 */ 3971 @ViewDebug.ExportedProperty(category = "padding") 3972 int mUserPaddingEnd; 3973 3974 /** 3975 * Cache initial left padding. 3976 * 3977 * @hide 3978 */ 3979 int mUserPaddingLeftInitial; 3980 3981 /** 3982 * Cache initial right padding. 3983 * 3984 * @hide 3985 */ 3986 int mUserPaddingRightInitial; 3987 3988 /** 3989 * Default undefined padding 3990 */ 3991 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3992 3993 /** 3994 * Cache if a left padding has been defined 3995 */ 3996 private boolean mLeftPaddingDefined = false; 3997 3998 /** 3999 * Cache if a right padding has been defined 4000 */ 4001 private boolean mRightPaddingDefined = false; 4002 4003 /** 4004 * @hide 4005 */ 4006 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4007 /** 4008 * @hide 4009 */ 4010 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4011 4012 private LongSparseLongArray mMeasureCache; 4013 4014 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4015 private Drawable mBackground; 4016 private TintInfo mBackgroundTint; 4017 4018 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4019 private ForegroundInfo mForegroundInfo; 4020 4021 private Drawable mScrollIndicatorDrawable; 4022 4023 /** 4024 * RenderNode used for backgrounds. 4025 * <p> 4026 * When non-null and valid, this is expected to contain an up-to-date copy 4027 * of the background drawable. It is cleared on temporary detach, and reset 4028 * on cleanup. 4029 */ 4030 private RenderNode mBackgroundRenderNode; 4031 4032 private int mBackgroundResource; 4033 private boolean mBackgroundSizeChanged; 4034 4035 /** The default focus highlight. 4036 * @see #mDefaultFocusHighlightEnabled 4037 * @see Drawable#hasFocusStateSpecified() 4038 */ 4039 private Drawable mDefaultFocusHighlight; 4040 private Drawable mDefaultFocusHighlightCache; 4041 private boolean mDefaultFocusHighlightSizeChanged; 4042 /** 4043 * True if the default focus highlight is needed on the target device. 4044 */ 4045 private static boolean sUseDefaultFocusHighlight; 4046 4047 private String mTransitionName; 4048 4049 static class TintInfo { 4050 ColorStateList mTintList; 4051 PorterDuff.Mode mTintMode; 4052 boolean mHasTintMode; 4053 boolean mHasTintList; 4054 } 4055 4056 private static class ForegroundInfo { 4057 private Drawable mDrawable; 4058 private TintInfo mTintInfo; 4059 private int mGravity = Gravity.FILL; 4060 private boolean mInsidePadding = true; 4061 private boolean mBoundsChanged = true; 4062 private final Rect mSelfBounds = new Rect(); 4063 private final Rect mOverlayBounds = new Rect(); 4064 } 4065 4066 static class ListenerInfo { 4067 /** 4068 * Listener used to dispatch focus change events. 4069 * This field should be made private, so it is hidden from the SDK. 4070 * {@hide} 4071 */ 4072 protected OnFocusChangeListener mOnFocusChangeListener; 4073 4074 /** 4075 * Listeners for layout change events. 4076 */ 4077 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4078 4079 protected OnScrollChangeListener mOnScrollChangeListener; 4080 4081 /** 4082 * Listeners for attach events. 4083 */ 4084 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4085 4086 /** 4087 * Listener used to dispatch click events. 4088 * This field should be made private, so it is hidden from the SDK. 4089 * {@hide} 4090 */ 4091 public OnClickListener mOnClickListener; 4092 4093 /** 4094 * Listener used to dispatch long click events. 4095 * This field should be made private, so it is hidden from the SDK. 4096 * {@hide} 4097 */ 4098 protected OnLongClickListener mOnLongClickListener; 4099 4100 /** 4101 * Listener used to dispatch context click events. This field should be made private, so it 4102 * is hidden from the SDK. 4103 * {@hide} 4104 */ 4105 protected OnContextClickListener mOnContextClickListener; 4106 4107 /** 4108 * Listener used to build the context menu. 4109 * This field should be made private, so it is hidden from the SDK. 4110 * {@hide} 4111 */ 4112 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4113 4114 private OnKeyListener mOnKeyListener; 4115 4116 private OnTouchListener mOnTouchListener; 4117 4118 private OnHoverListener mOnHoverListener; 4119 4120 private OnGenericMotionListener mOnGenericMotionListener; 4121 4122 private OnDragListener mOnDragListener; 4123 4124 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4125 4126 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4127 4128 OnCapturedPointerListener mOnCapturedPointerListener; 4129 } 4130 4131 ListenerInfo mListenerInfo; 4132 4133 private static class TooltipInfo { 4134 /** 4135 * Text to be displayed in a tooltip popup. 4136 */ 4137 @Nullable 4138 CharSequence mTooltipText; 4139 4140 /** 4141 * View-relative position of the tooltip anchor point. 4142 */ 4143 int mAnchorX; 4144 int mAnchorY; 4145 4146 /** 4147 * The tooltip popup. 4148 */ 4149 @Nullable 4150 TooltipPopup mTooltipPopup; 4151 4152 /** 4153 * Set to true if the tooltip was shown as a result of a long click. 4154 */ 4155 boolean mTooltipFromLongClick; 4156 4157 /** 4158 * Keep these Runnables so that they can be used to reschedule. 4159 */ 4160 Runnable mShowTooltipRunnable; 4161 Runnable mHideTooltipRunnable; 4162 } 4163 4164 TooltipInfo mTooltipInfo; 4165 4166 // Temporary values used to hold (x,y) coordinates when delegating from the 4167 // two-arg performLongClick() method to the legacy no-arg version. 4168 private float mLongClickX = Float.NaN; 4169 private float mLongClickY = Float.NaN; 4170 4171 /** 4172 * The application environment this view lives in. 4173 * This field should be made private, so it is hidden from the SDK. 4174 * {@hide} 4175 */ 4176 @ViewDebug.ExportedProperty(deepExport = true) 4177 protected Context mContext; 4178 4179 private final Resources mResources; 4180 4181 private ScrollabilityCache mScrollCache; 4182 4183 private int[] mDrawableState = null; 4184 4185 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4186 4187 /** 4188 * Animator that automatically runs based on state changes. 4189 */ 4190 private StateListAnimator mStateListAnimator; 4191 4192 /** 4193 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4194 * the user may specify which view to go to next. 4195 */ 4196 private int mNextFocusLeftId = View.NO_ID; 4197 4198 /** 4199 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4200 * the user may specify which view to go to next. 4201 */ 4202 private int mNextFocusRightId = View.NO_ID; 4203 4204 /** 4205 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4206 * the user may specify which view to go to next. 4207 */ 4208 private int mNextFocusUpId = View.NO_ID; 4209 4210 /** 4211 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4212 * the user may specify which view to go to next. 4213 */ 4214 private int mNextFocusDownId = View.NO_ID; 4215 4216 /** 4217 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4218 * the user may specify which view to go to next. 4219 */ 4220 int mNextFocusForwardId = View.NO_ID; 4221 4222 /** 4223 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4224 * 4225 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4226 */ 4227 int mNextClusterForwardId = View.NO_ID; 4228 4229 /** 4230 * Whether this View should use a default focus highlight when it gets focused but doesn't 4231 * have {@link android.R.attr#state_focused} defined in its background. 4232 */ 4233 boolean mDefaultFocusHighlightEnabled = true; 4234 4235 private CheckForLongPress mPendingCheckForLongPress; 4236 private CheckForTap mPendingCheckForTap = null; 4237 private PerformClick mPerformClick; 4238 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4239 4240 private UnsetPressedState mUnsetPressedState; 4241 4242 /** 4243 * Whether the long press's action has been invoked. The tap's action is invoked on the 4244 * up event while a long press is invoked as soon as the long press duration is reached, so 4245 * a long press could be performed before the tap is checked, in which case the tap's action 4246 * should not be invoked. 4247 */ 4248 private boolean mHasPerformedLongPress; 4249 4250 /** 4251 * Whether a context click button is currently pressed down. This is true when the stylus is 4252 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4253 * pressed. This is false once the button is released or if the stylus has been lifted. 4254 */ 4255 private boolean mInContextButtonPress; 4256 4257 /** 4258 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4259 * true after a stylus button press has occured, when the next up event should not be recognized 4260 * as a tap. 4261 */ 4262 private boolean mIgnoreNextUpEvent; 4263 4264 /** 4265 * The minimum height of the view. We'll try our best to have the height 4266 * of this view to at least this amount. 4267 */ 4268 @ViewDebug.ExportedProperty(category = "measurement") 4269 private int mMinHeight; 4270 4271 /** 4272 * The minimum width of the view. We'll try our best to have the width 4273 * of this view to at least this amount. 4274 */ 4275 @ViewDebug.ExportedProperty(category = "measurement") 4276 private int mMinWidth; 4277 4278 /** 4279 * The delegate to handle touch events that are physically in this view 4280 * but should be handled by another view. 4281 */ 4282 private TouchDelegate mTouchDelegate = null; 4283 4284 /** 4285 * Solid color to use as a background when creating the drawing cache. Enables 4286 * the cache to use 16 bit bitmaps instead of 32 bit. 4287 */ 4288 private int mDrawingCacheBackgroundColor = 0; 4289 4290 /** 4291 * Special tree observer used when mAttachInfo is null. 4292 */ 4293 private ViewTreeObserver mFloatingTreeObserver; 4294 4295 /** 4296 * Cache the touch slop from the context that created the view. 4297 */ 4298 private int mTouchSlop; 4299 4300 /** 4301 * Object that handles automatic animation of view properties. 4302 */ 4303 private ViewPropertyAnimator mAnimator = null; 4304 4305 /** 4306 * List of registered FrameMetricsObservers. 4307 */ 4308 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4309 4310 /** 4311 * Flag indicating that a drag can cross window boundaries. When 4312 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4313 * with this flag set, all visible applications with targetSdkVersion >= 4314 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4315 * in the drag operation and receive the dragged content. 4316 * 4317 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4318 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4319 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4320 */ 4321 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4322 4323 /** 4324 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4325 * request read access to the content URI(s) contained in the {@link ClipData} object. 4326 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4327 */ 4328 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4329 4330 /** 4331 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4332 * request write access to the content URI(s) contained in the {@link ClipData} object. 4333 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4334 */ 4335 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4336 4337 /** 4338 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4339 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4340 * reboots until explicitly revoked with 4341 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4342 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4343 */ 4344 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4345 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4346 4347 /** 4348 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4349 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4350 * match against the original granted URI. 4351 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4352 */ 4353 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4354 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4355 4356 /** 4357 * Flag indicating that the drag shadow will be opaque. When 4358 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4359 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4360 */ 4361 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4362 4363 /** 4364 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4365 */ 4366 private float mVerticalScrollFactor; 4367 4368 /** 4369 * Position of the vertical scroll bar. 4370 */ 4371 private int mVerticalScrollbarPosition; 4372 4373 /** 4374 * Position the scroll bar at the default position as determined by the system. 4375 */ 4376 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4377 4378 /** 4379 * Position the scroll bar along the left edge. 4380 */ 4381 public static final int SCROLLBAR_POSITION_LEFT = 1; 4382 4383 /** 4384 * Position the scroll bar along the right edge. 4385 */ 4386 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4387 4388 /** 4389 * Indicates that the view does not have a layer. 4390 * 4391 * @see #getLayerType() 4392 * @see #setLayerType(int, android.graphics.Paint) 4393 * @see #LAYER_TYPE_SOFTWARE 4394 * @see #LAYER_TYPE_HARDWARE 4395 */ 4396 public static final int LAYER_TYPE_NONE = 0; 4397 4398 /** 4399 * <p>Indicates that the view has a software layer. A software layer is backed 4400 * by a bitmap and causes the view to be rendered using Android's software 4401 * rendering pipeline, even if hardware acceleration is enabled.</p> 4402 * 4403 * <p>Software layers have various usages:</p> 4404 * <p>When the application is not using hardware acceleration, a software layer 4405 * is useful to apply a specific color filter and/or blending mode and/or 4406 * translucency to a view and all its children.</p> 4407 * <p>When the application is using hardware acceleration, a software layer 4408 * is useful to render drawing primitives not supported by the hardware 4409 * accelerated pipeline. It can also be used to cache a complex view tree 4410 * into a texture and reduce the complexity of drawing operations. For instance, 4411 * when animating a complex view tree with a translation, a software layer can 4412 * be used to render the view tree only once.</p> 4413 * <p>Software layers should be avoided when the affected view tree updates 4414 * often. Every update will require to re-render the software layer, which can 4415 * potentially be slow (particularly when hardware acceleration is turned on 4416 * since the layer will have to be uploaded into a hardware texture after every 4417 * update.)</p> 4418 * 4419 * @see #getLayerType() 4420 * @see #setLayerType(int, android.graphics.Paint) 4421 * @see #LAYER_TYPE_NONE 4422 * @see #LAYER_TYPE_HARDWARE 4423 */ 4424 public static final int LAYER_TYPE_SOFTWARE = 1; 4425 4426 /** 4427 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4428 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4429 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4430 * rendering pipeline, but only if hardware acceleration is turned on for the 4431 * view hierarchy. When hardware acceleration is turned off, hardware layers 4432 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4433 * 4434 * <p>A hardware layer is useful to apply a specific color filter and/or 4435 * blending mode and/or translucency to a view and all its children.</p> 4436 * <p>A hardware layer can be used to cache a complex view tree into a 4437 * texture and reduce the complexity of drawing operations. For instance, 4438 * when animating a complex view tree with a translation, a hardware layer can 4439 * be used to render the view tree only once.</p> 4440 * <p>A hardware layer can also be used to increase the rendering quality when 4441 * rotation transformations are applied on a view. It can also be used to 4442 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4443 * 4444 * @see #getLayerType() 4445 * @see #setLayerType(int, android.graphics.Paint) 4446 * @see #LAYER_TYPE_NONE 4447 * @see #LAYER_TYPE_SOFTWARE 4448 */ 4449 public static final int LAYER_TYPE_HARDWARE = 2; 4450 4451 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4452 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4453 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4454 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4455 }) 4456 int mLayerType = LAYER_TYPE_NONE; 4457 Paint mLayerPaint; 4458 4459 /** 4460 * Set to true when drawing cache is enabled and cannot be created. 4461 * 4462 * @hide 4463 */ 4464 public boolean mCachingFailed; 4465 private Bitmap mDrawingCache; 4466 private Bitmap mUnscaledDrawingCache; 4467 4468 /** 4469 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4470 * <p> 4471 * When non-null and valid, this is expected to contain an up-to-date copy 4472 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4473 * cleanup. 4474 */ 4475 final RenderNode mRenderNode; 4476 4477 /** 4478 * Set to true when the view is sending hover accessibility events because it 4479 * is the innermost hovered view. 4480 */ 4481 private boolean mSendingHoverAccessibilityEvents; 4482 4483 /** 4484 * Delegate for injecting accessibility functionality. 4485 */ 4486 AccessibilityDelegate mAccessibilityDelegate; 4487 4488 /** 4489 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4490 * and add/remove objects to/from the overlay directly through the Overlay methods. 4491 */ 4492 ViewOverlay mOverlay; 4493 4494 /** 4495 * The currently active parent view for receiving delegated nested scrolling events. 4496 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4497 * by {@link #stopNestedScroll()} at the same point where we clear 4498 * requestDisallowInterceptTouchEvent. 4499 */ 4500 private ViewParent mNestedScrollingParent; 4501 4502 /** 4503 * Consistency verifier for debugging purposes. 4504 * @hide 4505 */ 4506 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4507 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4508 new InputEventConsistencyVerifier(this, 0) : null; 4509 4510 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4511 4512 private int[] mTempNestedScrollConsumed; 4513 4514 /** 4515 * An overlay is going to draw this View instead of being drawn as part of this 4516 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4517 * when this view is invalidated. 4518 */ 4519 GhostView mGhostView; 4520 4521 /** 4522 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4523 * @hide 4524 */ 4525 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4526 public String[] mAttributes; 4527 4528 /** 4529 * Maps a Resource id to its name. 4530 */ 4531 private static SparseArray<String> mAttributeMap; 4532 4533 /** 4534 * Queue of pending runnables. Used to postpone calls to post() until this 4535 * view is attached and has a handler. 4536 */ 4537 private HandlerActionQueue mRunQueue; 4538 4539 /** 4540 * The pointer icon when the mouse hovers on this view. The default is null. 4541 */ 4542 private PointerIcon mPointerIcon; 4543 4544 /** 4545 * @hide 4546 */ 4547 String mStartActivityRequestWho; 4548 4549 @Nullable 4550 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4551 4552 /** Used to delay visibility updates sent to the autofill manager */ 4553 private Handler mVisibilityChangeForAutofillHandler; 4554 4555 /** 4556 * Simple constructor to use when creating a view from code. 4557 * 4558 * @param context The Context the view is running in, through which it can 4559 * access the current theme, resources, etc. 4560 */ View(Context context)4561 public View(Context context) { 4562 mContext = context; 4563 mResources = context != null ? context.getResources() : null; 4564 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 4565 // Set some flags defaults 4566 mPrivateFlags2 = 4567 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4568 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4569 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4570 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4571 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4572 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4573 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4574 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4575 mUserPaddingStart = UNDEFINED_PADDING; 4576 mUserPaddingEnd = UNDEFINED_PADDING; 4577 mRenderNode = RenderNode.create(getClass().getName(), this); 4578 4579 if (!sCompatibilityDone && context != null) { 4580 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4581 4582 // Older apps may need this compatibility hack for measurement. 4583 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 4584 4585 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4586 // of whether a layout was requested on that View. 4587 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 4588 4589 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 4590 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 4591 4592 // In M and newer, our widgets can pass a "hint" value in the size 4593 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4594 // know what the expected parent size is going to be, so e.g. list items can size 4595 // themselves at 1/3 the size of their container. It breaks older apps though, 4596 // specifically apps that use some popular open source libraries. 4597 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 4598 4599 // Old versions of the platform would give different results from 4600 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4601 // modes, so we always need to run an additional EXACTLY pass. 4602 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 4603 4604 // Prior to N, layout params could change without requiring a 4605 // subsequent call to setLayoutParams() and they would usually 4606 // work. Partial layout breaks this assumption. 4607 sLayoutParamsAlwaysChanged = targetSdkVersion <= Build.VERSION_CODES.M; 4608 4609 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4610 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4611 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 4612 4613 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4614 // in apps so we target check it to avoid breaking existing apps. 4615 sPreserveMarginParamsInLayoutParamConversion = 4616 targetSdkVersion >= Build.VERSION_CODES.N; 4617 4618 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 4619 4620 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 4621 4622 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 4623 4624 sUseDefaultFocusHighlight = context.getResources().getBoolean( 4625 com.android.internal.R.bool.config_useDefaultFocusHighlight); 4626 4627 sCompatibilityDone = true; 4628 } 4629 } 4630 4631 /** 4632 * Constructor that is called when inflating a view from XML. This is called 4633 * when a view is being constructed from an XML file, supplying attributes 4634 * that were specified in the XML file. This version uses a default style of 4635 * 0, so the only attribute values applied are those in the Context's Theme 4636 * and the given AttributeSet. 4637 * 4638 * <p> 4639 * The method onFinishInflate() will be called after all children have been 4640 * added. 4641 * 4642 * @param context The Context the view is running in, through which it can 4643 * access the current theme, resources, etc. 4644 * @param attrs The attributes of the XML tag that is inflating the view. 4645 * @see #View(Context, AttributeSet, int) 4646 */ 4647 public View(Context context, @Nullable AttributeSet attrs) { 4648 this(context, attrs, 0); 4649 } 4650 4651 /** 4652 * Perform inflation from XML and apply a class-specific base style from a 4653 * theme attribute. This constructor of View allows subclasses to use their 4654 * own base style when they are inflating. For example, a Button class's 4655 * constructor would call this version of the super class constructor and 4656 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4657 * allows the theme's button style to modify all of the base view attributes 4658 * (in particular its background) as well as the Button class's attributes. 4659 * 4660 * @param context The Context the view is running in, through which it can 4661 * access the current theme, resources, etc. 4662 * @param attrs The attributes of the XML tag that is inflating the view. 4663 * @param defStyleAttr An attribute in the current theme that contains a 4664 * reference to a style resource that supplies default values for 4665 * the view. Can be 0 to not look for defaults. 4666 * @see #View(Context, AttributeSet) 4667 */ 4668 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4669 this(context, attrs, defStyleAttr, 0); 4670 } 4671 4672 /** 4673 * Perform inflation from XML and apply a class-specific base style from a 4674 * theme attribute or style resource. This constructor of View allows 4675 * subclasses to use their own base style when they are inflating. 4676 * <p> 4677 * When determining the final value of a particular attribute, there are 4678 * four inputs that come into play: 4679 * <ol> 4680 * <li>Any attribute values in the given AttributeSet. 4681 * <li>The style resource specified in the AttributeSet (named "style"). 4682 * <li>The default style specified by <var>defStyleAttr</var>. 4683 * <li>The default style specified by <var>defStyleRes</var>. 4684 * <li>The base values in this theme. 4685 * </ol> 4686 * <p> 4687 * Each of these inputs is considered in-order, with the first listed taking 4688 * precedence over the following ones. In other words, if in the 4689 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4690 * , then the button's text will <em>always</em> be black, regardless of 4691 * what is specified in any of the styles. 4692 * 4693 * @param context The Context the view is running in, through which it can 4694 * access the current theme, resources, etc. 4695 * @param attrs The attributes of the XML tag that is inflating the view. 4696 * @param defStyleAttr An attribute in the current theme that contains a 4697 * reference to a style resource that supplies default values for 4698 * the view. Can be 0 to not look for defaults. 4699 * @param defStyleRes A resource identifier of a style resource that 4700 * supplies default values for the view, used only if 4701 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4702 * to not look for defaults. 4703 * @see #View(Context, AttributeSet, int) 4704 */ 4705 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4706 this(context); 4707 4708 final TypedArray a = context.obtainStyledAttributes( 4709 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4710 4711 if (mDebugViewAttributes) { 4712 saveAttributeData(attrs, a); 4713 } 4714 4715 Drawable background = null; 4716 4717 int leftPadding = -1; 4718 int topPadding = -1; 4719 int rightPadding = -1; 4720 int bottomPadding = -1; 4721 int startPadding = UNDEFINED_PADDING; 4722 int endPadding = UNDEFINED_PADDING; 4723 4724 int padding = -1; 4725 int paddingHorizontal = -1; 4726 int paddingVertical = -1; 4727 4728 int viewFlagValues = 0; 4729 int viewFlagMasks = 0; 4730 4731 boolean setScrollContainer = false; 4732 4733 int x = 0; 4734 int y = 0; 4735 4736 float tx = 0; 4737 float ty = 0; 4738 float tz = 0; 4739 float elevation = 0; 4740 float rotation = 0; 4741 float rotationX = 0; 4742 float rotationY = 0; 4743 float sx = 1f; 4744 float sy = 1f; 4745 boolean transformSet = false; 4746 4747 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4748 int overScrollMode = mOverScrollMode; 4749 boolean initializeScrollbars = false; 4750 boolean initializeScrollIndicators = false; 4751 4752 boolean startPaddingDefined = false; 4753 boolean endPaddingDefined = false; 4754 boolean leftPaddingDefined = false; 4755 boolean rightPaddingDefined = false; 4756 4757 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4758 4759 // Set default values. 4760 viewFlagValues |= FOCUSABLE_AUTO; 4761 viewFlagMasks |= FOCUSABLE_AUTO; 4762 4763 final int N = a.getIndexCount(); 4764 for (int i = 0; i < N; i++) { 4765 int attr = a.getIndex(i); 4766 switch (attr) { 4767 case com.android.internal.R.styleable.View_background: 4768 background = a.getDrawable(attr); 4769 break; 4770 case com.android.internal.R.styleable.View_padding: 4771 padding = a.getDimensionPixelSize(attr, -1); 4772 mUserPaddingLeftInitial = padding; 4773 mUserPaddingRightInitial = padding; 4774 leftPaddingDefined = true; 4775 rightPaddingDefined = true; 4776 break; 4777 case com.android.internal.R.styleable.View_paddingHorizontal: 4778 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 4779 mUserPaddingLeftInitial = paddingHorizontal; 4780 mUserPaddingRightInitial = paddingHorizontal; 4781 leftPaddingDefined = true; 4782 rightPaddingDefined = true; 4783 break; 4784 case com.android.internal.R.styleable.View_paddingVertical: 4785 paddingVertical = a.getDimensionPixelSize(attr, -1); 4786 break; 4787 case com.android.internal.R.styleable.View_paddingLeft: 4788 leftPadding = a.getDimensionPixelSize(attr, -1); 4789 mUserPaddingLeftInitial = leftPadding; 4790 leftPaddingDefined = true; 4791 break; 4792 case com.android.internal.R.styleable.View_paddingTop: 4793 topPadding = a.getDimensionPixelSize(attr, -1); 4794 break; 4795 case com.android.internal.R.styleable.View_paddingRight: 4796 rightPadding = a.getDimensionPixelSize(attr, -1); 4797 mUserPaddingRightInitial = rightPadding; 4798 rightPaddingDefined = true; 4799 break; 4800 case com.android.internal.R.styleable.View_paddingBottom: 4801 bottomPadding = a.getDimensionPixelSize(attr, -1); 4802 break; 4803 case com.android.internal.R.styleable.View_paddingStart: 4804 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4805 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4806 break; 4807 case com.android.internal.R.styleable.View_paddingEnd: 4808 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4809 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4810 break; 4811 case com.android.internal.R.styleable.View_scrollX: 4812 x = a.getDimensionPixelOffset(attr, 0); 4813 break; 4814 case com.android.internal.R.styleable.View_scrollY: 4815 y = a.getDimensionPixelOffset(attr, 0); 4816 break; 4817 case com.android.internal.R.styleable.View_alpha: 4818 setAlpha(a.getFloat(attr, 1f)); 4819 break; 4820 case com.android.internal.R.styleable.View_transformPivotX: 4821 setPivotX(a.getDimension(attr, 0)); 4822 break; 4823 case com.android.internal.R.styleable.View_transformPivotY: 4824 setPivotY(a.getDimension(attr, 0)); 4825 break; 4826 case com.android.internal.R.styleable.View_translationX: 4827 tx = a.getDimension(attr, 0); 4828 transformSet = true; 4829 break; 4830 case com.android.internal.R.styleable.View_translationY: 4831 ty = a.getDimension(attr, 0); 4832 transformSet = true; 4833 break; 4834 case com.android.internal.R.styleable.View_translationZ: 4835 tz = a.getDimension(attr, 0); 4836 transformSet = true; 4837 break; 4838 case com.android.internal.R.styleable.View_elevation: 4839 elevation = a.getDimension(attr, 0); 4840 transformSet = true; 4841 break; 4842 case com.android.internal.R.styleable.View_rotation: 4843 rotation = a.getFloat(attr, 0); 4844 transformSet = true; 4845 break; 4846 case com.android.internal.R.styleable.View_rotationX: 4847 rotationX = a.getFloat(attr, 0); 4848 transformSet = true; 4849 break; 4850 case com.android.internal.R.styleable.View_rotationY: 4851 rotationY = a.getFloat(attr, 0); 4852 transformSet = true; 4853 break; 4854 case com.android.internal.R.styleable.View_scaleX: 4855 sx = a.getFloat(attr, 1f); 4856 transformSet = true; 4857 break; 4858 case com.android.internal.R.styleable.View_scaleY: 4859 sy = a.getFloat(attr, 1f); 4860 transformSet = true; 4861 break; 4862 case com.android.internal.R.styleable.View_id: 4863 mID = a.getResourceId(attr, NO_ID); 4864 break; 4865 case com.android.internal.R.styleable.View_tag: 4866 mTag = a.getText(attr); 4867 break; 4868 case com.android.internal.R.styleable.View_fitsSystemWindows: 4869 if (a.getBoolean(attr, false)) { 4870 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4871 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4872 } 4873 break; 4874 case com.android.internal.R.styleable.View_focusable: 4875 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 4876 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 4877 viewFlagMasks |= FOCUSABLE_MASK; 4878 } 4879 break; 4880 case com.android.internal.R.styleable.View_focusableInTouchMode: 4881 if (a.getBoolean(attr, false)) { 4882 // unset auto focus since focusableInTouchMode implies explicit focusable 4883 viewFlagValues &= ~FOCUSABLE_AUTO; 4884 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4885 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4886 } 4887 break; 4888 case com.android.internal.R.styleable.View_clickable: 4889 if (a.getBoolean(attr, false)) { 4890 viewFlagValues |= CLICKABLE; 4891 viewFlagMasks |= CLICKABLE; 4892 } 4893 break; 4894 case com.android.internal.R.styleable.View_longClickable: 4895 if (a.getBoolean(attr, false)) { 4896 viewFlagValues |= LONG_CLICKABLE; 4897 viewFlagMasks |= LONG_CLICKABLE; 4898 } 4899 break; 4900 case com.android.internal.R.styleable.View_contextClickable: 4901 if (a.getBoolean(attr, false)) { 4902 viewFlagValues |= CONTEXT_CLICKABLE; 4903 viewFlagMasks |= CONTEXT_CLICKABLE; 4904 } 4905 break; 4906 case com.android.internal.R.styleable.View_saveEnabled: 4907 if (!a.getBoolean(attr, true)) { 4908 viewFlagValues |= SAVE_DISABLED; 4909 viewFlagMasks |= SAVE_DISABLED_MASK; 4910 } 4911 break; 4912 case com.android.internal.R.styleable.View_duplicateParentState: 4913 if (a.getBoolean(attr, false)) { 4914 viewFlagValues |= DUPLICATE_PARENT_STATE; 4915 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4916 } 4917 break; 4918 case com.android.internal.R.styleable.View_visibility: 4919 final int visibility = a.getInt(attr, 0); 4920 if (visibility != 0) { 4921 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4922 viewFlagMasks |= VISIBILITY_MASK; 4923 } 4924 break; 4925 case com.android.internal.R.styleable.View_layoutDirection: 4926 // Clear any layout direction flags (included resolved bits) already set 4927 mPrivateFlags2 &= 4928 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4929 // Set the layout direction flags depending on the value of the attribute 4930 final int layoutDirection = a.getInt(attr, -1); 4931 final int value = (layoutDirection != -1) ? 4932 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4933 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4934 break; 4935 case com.android.internal.R.styleable.View_drawingCacheQuality: 4936 final int cacheQuality = a.getInt(attr, 0); 4937 if (cacheQuality != 0) { 4938 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4939 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4940 } 4941 break; 4942 case com.android.internal.R.styleable.View_contentDescription: 4943 setContentDescription(a.getString(attr)); 4944 break; 4945 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4946 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4947 break; 4948 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4949 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4950 break; 4951 case com.android.internal.R.styleable.View_labelFor: 4952 setLabelFor(a.getResourceId(attr, NO_ID)); 4953 break; 4954 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4955 if (!a.getBoolean(attr, true)) { 4956 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4957 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4958 } 4959 break; 4960 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4961 if (!a.getBoolean(attr, true)) { 4962 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4963 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4964 } 4965 break; 4966 case R.styleable.View_scrollbars: 4967 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4968 if (scrollbars != SCROLLBARS_NONE) { 4969 viewFlagValues |= scrollbars; 4970 viewFlagMasks |= SCROLLBARS_MASK; 4971 initializeScrollbars = true; 4972 } 4973 break; 4974 //noinspection deprecation 4975 case R.styleable.View_fadingEdge: 4976 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 4977 // Ignore the attribute starting with ICS 4978 break; 4979 } 4980 // With builds < ICS, fall through and apply fading edges 4981 case R.styleable.View_requiresFadingEdge: 4982 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4983 if (fadingEdge != FADING_EDGE_NONE) { 4984 viewFlagValues |= fadingEdge; 4985 viewFlagMasks |= FADING_EDGE_MASK; 4986 initializeFadingEdgeInternal(a); 4987 } 4988 break; 4989 case R.styleable.View_scrollbarStyle: 4990 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4991 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4992 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4993 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4994 } 4995 break; 4996 case R.styleable.View_isScrollContainer: 4997 setScrollContainer = true; 4998 if (a.getBoolean(attr, false)) { 4999 setScrollContainer(true); 5000 } 5001 break; 5002 case com.android.internal.R.styleable.View_keepScreenOn: 5003 if (a.getBoolean(attr, false)) { 5004 viewFlagValues |= KEEP_SCREEN_ON; 5005 viewFlagMasks |= KEEP_SCREEN_ON; 5006 } 5007 break; 5008 case R.styleable.View_filterTouchesWhenObscured: 5009 if (a.getBoolean(attr, false)) { 5010 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5011 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5012 } 5013 break; 5014 case R.styleable.View_nextFocusLeft: 5015 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5016 break; 5017 case R.styleable.View_nextFocusRight: 5018 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5019 break; 5020 case R.styleable.View_nextFocusUp: 5021 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5022 break; 5023 case R.styleable.View_nextFocusDown: 5024 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5025 break; 5026 case R.styleable.View_nextFocusForward: 5027 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5028 break; 5029 case R.styleable.View_nextClusterForward: 5030 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5031 break; 5032 case R.styleable.View_minWidth: 5033 mMinWidth = a.getDimensionPixelSize(attr, 0); 5034 break; 5035 case R.styleable.View_minHeight: 5036 mMinHeight = a.getDimensionPixelSize(attr, 0); 5037 break; 5038 case R.styleable.View_onClick: 5039 if (context.isRestricted()) { 5040 throw new IllegalStateException("The android:onClick attribute cannot " 5041 + "be used within a restricted context"); 5042 } 5043 5044 final String handlerName = a.getString(attr); 5045 if (handlerName != null) { 5046 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5047 } 5048 break; 5049 case R.styleable.View_overScrollMode: 5050 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5051 break; 5052 case R.styleable.View_verticalScrollbarPosition: 5053 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5054 break; 5055 case R.styleable.View_layerType: 5056 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5057 break; 5058 case R.styleable.View_textDirection: 5059 // Clear any text direction flag already set 5060 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5061 // Set the text direction flags depending on the value of the attribute 5062 final int textDirection = a.getInt(attr, -1); 5063 if (textDirection != -1) { 5064 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5065 } 5066 break; 5067 case R.styleable.View_textAlignment: 5068 // Clear any text alignment flag already set 5069 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5070 // Set the text alignment flag depending on the value of the attribute 5071 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5072 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5073 break; 5074 case R.styleable.View_importantForAccessibility: 5075 setImportantForAccessibility(a.getInt(attr, 5076 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5077 break; 5078 case R.styleable.View_accessibilityLiveRegion: 5079 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5080 break; 5081 case R.styleable.View_transitionName: 5082 setTransitionName(a.getString(attr)); 5083 break; 5084 case R.styleable.View_nestedScrollingEnabled: 5085 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5086 break; 5087 case R.styleable.View_stateListAnimator: 5088 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5089 a.getResourceId(attr, 0))); 5090 break; 5091 case R.styleable.View_backgroundTint: 5092 // This will get applied later during setBackground(). 5093 if (mBackgroundTint == null) { 5094 mBackgroundTint = new TintInfo(); 5095 } 5096 mBackgroundTint.mTintList = a.getColorStateList( 5097 R.styleable.View_backgroundTint); 5098 mBackgroundTint.mHasTintList = true; 5099 break; 5100 case R.styleable.View_backgroundTintMode: 5101 // This will get applied later during setBackground(). 5102 if (mBackgroundTint == null) { 5103 mBackgroundTint = new TintInfo(); 5104 } 5105 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 5106 R.styleable.View_backgroundTintMode, -1), null); 5107 mBackgroundTint.mHasTintMode = true; 5108 break; 5109 case R.styleable.View_outlineProvider: 5110 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5111 PROVIDER_BACKGROUND)); 5112 break; 5113 case R.styleable.View_foreground: 5114 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5115 setForeground(a.getDrawable(attr)); 5116 } 5117 break; 5118 case R.styleable.View_foregroundGravity: 5119 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5120 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5121 } 5122 break; 5123 case R.styleable.View_foregroundTintMode: 5124 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5125 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 5126 } 5127 break; 5128 case R.styleable.View_foregroundTint: 5129 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5130 setForegroundTintList(a.getColorStateList(attr)); 5131 } 5132 break; 5133 case R.styleable.View_foregroundInsidePadding: 5134 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5135 if (mForegroundInfo == null) { 5136 mForegroundInfo = new ForegroundInfo(); 5137 } 5138 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5139 mForegroundInfo.mInsidePadding); 5140 } 5141 break; 5142 case R.styleable.View_scrollIndicators: 5143 final int scrollIndicators = 5144 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5145 & SCROLL_INDICATORS_PFLAG3_MASK; 5146 if (scrollIndicators != 0) { 5147 mPrivateFlags3 |= scrollIndicators; 5148 initializeScrollIndicators = true; 5149 } 5150 break; 5151 case R.styleable.View_pointerIcon: 5152 final int resourceId = a.getResourceId(attr, 0); 5153 if (resourceId != 0) { 5154 setPointerIcon(PointerIcon.load( 5155 context.getResources(), resourceId)); 5156 } else { 5157 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5158 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5159 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5160 } 5161 } 5162 break; 5163 case R.styleable.View_forceHasOverlappingRendering: 5164 if (a.peekValue(attr) != null) { 5165 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5166 } 5167 break; 5168 case R.styleable.View_tooltipText: 5169 setTooltipText(a.getText(attr)); 5170 break; 5171 case R.styleable.View_keyboardNavigationCluster: 5172 if (a.peekValue(attr) != null) { 5173 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5174 } 5175 break; 5176 case R.styleable.View_focusedByDefault: 5177 if (a.peekValue(attr) != null) { 5178 setFocusedByDefault(a.getBoolean(attr, true)); 5179 } 5180 break; 5181 case R.styleable.View_autofillHints: 5182 if (a.peekValue(attr) != null) { 5183 CharSequence[] rawHints = null; 5184 String rawString = null; 5185 5186 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5187 int resId = a.getResourceId(attr, 0); 5188 5189 try { 5190 rawHints = a.getTextArray(attr); 5191 } catch (Resources.NotFoundException e) { 5192 rawString = getResources().getString(resId); 5193 } 5194 } else { 5195 rawString = a.getString(attr); 5196 } 5197 5198 if (rawHints == null) { 5199 if (rawString == null) { 5200 throw new IllegalArgumentException( 5201 "Could not resolve autofillHints"); 5202 } else { 5203 rawHints = rawString.split(","); 5204 } 5205 } 5206 5207 String[] hints = new String[rawHints.length]; 5208 5209 int numHints = rawHints.length; 5210 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5211 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5212 } 5213 setAutofillHints(hints); 5214 } 5215 break; 5216 case R.styleable.View_importantForAutofill: 5217 if (a.peekValue(attr) != null) { 5218 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5219 } 5220 break; 5221 case R.styleable.View_defaultFocusHighlightEnabled: 5222 if (a.peekValue(attr) != null) { 5223 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5224 } 5225 break; 5226 } 5227 } 5228 5229 setOverScrollMode(overScrollMode); 5230 5231 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 5232 // the resolved layout direction). Those cached values will be used later during padding 5233 // resolution. 5234 mUserPaddingStart = startPadding; 5235 mUserPaddingEnd = endPadding; 5236 5237 if (background != null) { 5238 setBackground(background); 5239 } 5240 5241 // setBackground above will record that padding is currently provided by the background. 5242 // If we have padding specified via xml, record that here instead and use it. 5243 mLeftPaddingDefined = leftPaddingDefined; 5244 mRightPaddingDefined = rightPaddingDefined; 5245 5246 if (padding >= 0) { 5247 leftPadding = padding; 5248 topPadding = padding; 5249 rightPadding = padding; 5250 bottomPadding = padding; 5251 mUserPaddingLeftInitial = padding; 5252 mUserPaddingRightInitial = padding; 5253 } else { 5254 if (paddingHorizontal >= 0) { 5255 leftPadding = paddingHorizontal; 5256 rightPadding = paddingHorizontal; 5257 mUserPaddingLeftInitial = paddingHorizontal; 5258 mUserPaddingRightInitial = paddingHorizontal; 5259 } 5260 if (paddingVertical >= 0) { 5261 topPadding = paddingVertical; 5262 bottomPadding = paddingVertical; 5263 } 5264 } 5265 5266 if (isRtlCompatibilityMode()) { 5267 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5268 // left / right padding are used if defined (meaning here nothing to do). If they are not 5269 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5270 // start / end and resolve them as left / right (layout direction is not taken into account). 5271 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5272 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5273 // defined. 5274 if (!mLeftPaddingDefined && startPaddingDefined) { 5275 leftPadding = startPadding; 5276 } 5277 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5278 if (!mRightPaddingDefined && endPaddingDefined) { 5279 rightPadding = endPadding; 5280 } 5281 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5282 } else { 5283 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5284 // values defined. Otherwise, left /right values are used. 5285 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5286 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5287 // defined. 5288 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5289 5290 if (mLeftPaddingDefined && !hasRelativePadding) { 5291 mUserPaddingLeftInitial = leftPadding; 5292 } 5293 if (mRightPaddingDefined && !hasRelativePadding) { 5294 mUserPaddingRightInitial = rightPadding; 5295 } 5296 } 5297 5298 internalSetPadding( 5299 mUserPaddingLeftInitial, 5300 topPadding >= 0 ? topPadding : mPaddingTop, 5301 mUserPaddingRightInitial, 5302 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5303 5304 if (viewFlagMasks != 0) { 5305 setFlags(viewFlagValues, viewFlagMasks); 5306 } 5307 5308 if (initializeScrollbars) { 5309 initializeScrollbarsInternal(a); 5310 } 5311 5312 if (initializeScrollIndicators) { 5313 initializeScrollIndicatorsInternal(); 5314 } 5315 5316 a.recycle(); 5317 5318 // Needs to be called after mViewFlags is set 5319 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5320 recomputePadding(); 5321 } 5322 5323 if (x != 0 || y != 0) { 5324 scrollTo(x, y); 5325 } 5326 5327 if (transformSet) { 5328 setTranslationX(tx); 5329 setTranslationY(ty); 5330 setTranslationZ(tz); 5331 setElevation(elevation); 5332 setRotation(rotation); 5333 setRotationX(rotationX); 5334 setRotationY(rotationY); 5335 setScaleX(sx); 5336 setScaleY(sy); 5337 } 5338 5339 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5340 setScrollContainer(true); 5341 } 5342 5343 computeOpaqueFlags(); 5344 } 5345 5346 /** 5347 * An implementation of OnClickListener that attempts to lazily load a 5348 * named click handling method from a parent or ancestor context. 5349 */ 5350 private static class DeclaredOnClickListener implements OnClickListener { 5351 private final View mHostView; 5352 private final String mMethodName; 5353 5354 private Method mResolvedMethod; 5355 private Context mResolvedContext; 5356 5357 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5358 mHostView = hostView; 5359 mMethodName = methodName; 5360 } 5361 5362 @Override 5363 public void onClick(@NonNull View v) { 5364 if (mResolvedMethod == null) { 5365 resolveMethod(mHostView.getContext(), mMethodName); 5366 } 5367 5368 try { 5369 mResolvedMethod.invoke(mResolvedContext, v); 5370 } catch (IllegalAccessException e) { 5371 throw new IllegalStateException( 5372 "Could not execute non-public method for android:onClick", e); 5373 } catch (InvocationTargetException e) { 5374 throw new IllegalStateException( 5375 "Could not execute method for android:onClick", e); 5376 } 5377 } 5378 5379 @NonNull 5380 private void resolveMethod(@Nullable Context context, @NonNull String name) { 5381 while (context != null) { 5382 try { 5383 if (!context.isRestricted()) { 5384 final Method method = context.getClass().getMethod(mMethodName, View.class); 5385 if (method != null) { 5386 mResolvedMethod = method; 5387 mResolvedContext = context; 5388 return; 5389 } 5390 } 5391 } catch (NoSuchMethodException e) { 5392 // Failed to find method, keep searching up the hierarchy. 5393 } 5394 5395 if (context instanceof ContextWrapper) { 5396 context = ((ContextWrapper) context).getBaseContext(); 5397 } else { 5398 // Can't search up the hierarchy, null out and fail. 5399 context = null; 5400 } 5401 } 5402 5403 final int id = mHostView.getId(); 5404 final String idText = id == NO_ID ? "" : " with id '" 5405 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 5406 throw new IllegalStateException("Could not find method " + mMethodName 5407 + "(View) in a parent or ancestor Context for android:onClick " 5408 + "attribute defined on view " + mHostView.getClass() + idText); 5409 } 5410 } 5411 5412 /** 5413 * Non-public constructor for use in testing 5414 */ 5415 View() { 5416 mResources = null; 5417 mRenderNode = RenderNode.create(getClass().getName(), this); 5418 } 5419 5420 final boolean debugDraw() { 5421 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 5422 } 5423 5424 private static SparseArray<String> getAttributeMap() { 5425 if (mAttributeMap == null) { 5426 mAttributeMap = new SparseArray<>(); 5427 } 5428 return mAttributeMap; 5429 } 5430 5431 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 5432 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 5433 final int indexCount = t.getIndexCount(); 5434 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 5435 5436 int i = 0; 5437 5438 // Store raw XML attributes. 5439 for (int j = 0; j < attrsCount; ++j) { 5440 attributes[i] = attrs.getAttributeName(j); 5441 attributes[i + 1] = attrs.getAttributeValue(j); 5442 i += 2; 5443 } 5444 5445 // Store resolved styleable attributes. 5446 final Resources res = t.getResources(); 5447 final SparseArray<String> attributeMap = getAttributeMap(); 5448 for (int j = 0; j < indexCount; ++j) { 5449 final int index = t.getIndex(j); 5450 if (!t.hasValueOrEmpty(index)) { 5451 // Value is undefined. Skip it. 5452 continue; 5453 } 5454 5455 final int resourceId = t.getResourceId(index, 0); 5456 if (resourceId == 0) { 5457 // Value is not a reference. Skip it. 5458 continue; 5459 } 5460 5461 String resourceName = attributeMap.get(resourceId); 5462 if (resourceName == null) { 5463 try { 5464 resourceName = res.getResourceName(resourceId); 5465 } catch (Resources.NotFoundException e) { 5466 resourceName = "0x" + Integer.toHexString(resourceId); 5467 } 5468 attributeMap.put(resourceId, resourceName); 5469 } 5470 5471 attributes[i] = resourceName; 5472 attributes[i + 1] = t.getString(index); 5473 i += 2; 5474 } 5475 5476 // Trim to fit contents. 5477 final String[] trimmed = new String[i]; 5478 System.arraycopy(attributes, 0, trimmed, 0, i); 5479 mAttributes = trimmed; 5480 } 5481 5482 public String toString() { 5483 StringBuilder out = new StringBuilder(128); 5484 out.append(getClass().getName()); 5485 out.append('{'); 5486 out.append(Integer.toHexString(System.identityHashCode(this))); 5487 out.append(' '); 5488 switch (mViewFlags&VISIBILITY_MASK) { 5489 case VISIBLE: out.append('V'); break; 5490 case INVISIBLE: out.append('I'); break; 5491 case GONE: out.append('G'); break; 5492 default: out.append('.'); break; 5493 } 5494 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 5495 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 5496 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 5497 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 5498 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 5499 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 5500 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 5501 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 5502 out.append(' '); 5503 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 5504 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 5505 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 5506 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 5507 out.append('p'); 5508 } else { 5509 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 5510 } 5511 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 5512 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 5513 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 5514 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 5515 out.append(' '); 5516 out.append(mLeft); 5517 out.append(','); 5518 out.append(mTop); 5519 out.append('-'); 5520 out.append(mRight); 5521 out.append(','); 5522 out.append(mBottom); 5523 final int id = getId(); 5524 if (id != NO_ID) { 5525 out.append(" #"); 5526 out.append(Integer.toHexString(id)); 5527 final Resources r = mResources; 5528 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 5529 try { 5530 String pkgname; 5531 switch (id&0xff000000) { 5532 case 0x7f000000: 5533 pkgname="app"; 5534 break; 5535 case 0x01000000: 5536 pkgname="android"; 5537 break; 5538 default: 5539 pkgname = r.getResourcePackageName(id); 5540 break; 5541 } 5542 String typename = r.getResourceTypeName(id); 5543 String entryname = r.getResourceEntryName(id); 5544 out.append(" "); 5545 out.append(pkgname); 5546 out.append(":"); 5547 out.append(typename); 5548 out.append("/"); 5549 out.append(entryname); 5550 } catch (Resources.NotFoundException e) { 5551 } 5552 } 5553 } 5554 out.append("}"); 5555 return out.toString(); 5556 } 5557 5558 /** 5559 * <p> 5560 * Initializes the fading edges from a given set of styled attributes. This 5561 * method should be called by subclasses that need fading edges and when an 5562 * instance of these subclasses is created programmatically rather than 5563 * being inflated from XML. This method is automatically called when the XML 5564 * is inflated. 5565 * </p> 5566 * 5567 * @param a the styled attributes set to initialize the fading edges from 5568 * 5569 * @removed 5570 */ 5571 protected void initializeFadingEdge(TypedArray a) { 5572 // This method probably shouldn't have been included in the SDK to begin with. 5573 // It relies on 'a' having been initialized using an attribute filter array that is 5574 // not publicly available to the SDK. The old method has been renamed 5575 // to initializeFadingEdgeInternal and hidden for framework use only; 5576 // this one initializes using defaults to make it safe to call for apps. 5577 5578 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5579 5580 initializeFadingEdgeInternal(arr); 5581 5582 arr.recycle(); 5583 } 5584 5585 /** 5586 * <p> 5587 * Initializes the fading edges from a given set of styled attributes. This 5588 * method should be called by subclasses that need fading edges and when an 5589 * instance of these subclasses is created programmatically rather than 5590 * being inflated from XML. This method is automatically called when the XML 5591 * is inflated. 5592 * </p> 5593 * 5594 * @param a the styled attributes set to initialize the fading edges from 5595 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 5596 */ 5597 protected void initializeFadingEdgeInternal(TypedArray a) { 5598 initScrollCache(); 5599 5600 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 5601 R.styleable.View_fadingEdgeLength, 5602 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 5603 } 5604 5605 /** 5606 * Returns the size of the vertical faded edges used to indicate that more 5607 * content in this view is visible. 5608 * 5609 * @return The size in pixels of the vertical faded edge or 0 if vertical 5610 * faded edges are not enabled for this view. 5611 * @attr ref android.R.styleable#View_fadingEdgeLength 5612 */ 5613 public int getVerticalFadingEdgeLength() { 5614 if (isVerticalFadingEdgeEnabled()) { 5615 ScrollabilityCache cache = mScrollCache; 5616 if (cache != null) { 5617 return cache.fadingEdgeLength; 5618 } 5619 } 5620 return 0; 5621 } 5622 5623 /** 5624 * Set the size of the faded edge used to indicate that more content in this 5625 * view is available. Will not change whether the fading edge is enabled; use 5626 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 5627 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 5628 * for the vertical or horizontal fading edges. 5629 * 5630 * @param length The size in pixels of the faded edge used to indicate that more 5631 * content in this view is visible. 5632 */ 5633 public void setFadingEdgeLength(int length) { 5634 initScrollCache(); 5635 mScrollCache.fadingEdgeLength = length; 5636 } 5637 5638 /** 5639 * Returns the size of the horizontal faded edges used to indicate that more 5640 * content in this view is visible. 5641 * 5642 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 5643 * faded edges are not enabled for this view. 5644 * @attr ref android.R.styleable#View_fadingEdgeLength 5645 */ 5646 public int getHorizontalFadingEdgeLength() { 5647 if (isHorizontalFadingEdgeEnabled()) { 5648 ScrollabilityCache cache = mScrollCache; 5649 if (cache != null) { 5650 return cache.fadingEdgeLength; 5651 } 5652 } 5653 return 0; 5654 } 5655 5656 /** 5657 * Returns the width of the vertical scrollbar. 5658 * 5659 * @return The width in pixels of the vertical scrollbar or 0 if there 5660 * is no vertical scrollbar. 5661 */ 5662 public int getVerticalScrollbarWidth() { 5663 ScrollabilityCache cache = mScrollCache; 5664 if (cache != null) { 5665 ScrollBarDrawable scrollBar = cache.scrollBar; 5666 if (scrollBar != null) { 5667 int size = scrollBar.getSize(true); 5668 if (size <= 0) { 5669 size = cache.scrollBarSize; 5670 } 5671 return size; 5672 } 5673 return 0; 5674 } 5675 return 0; 5676 } 5677 5678 /** 5679 * Returns the height of the horizontal scrollbar. 5680 * 5681 * @return The height in pixels of the horizontal scrollbar or 0 if 5682 * there is no horizontal scrollbar. 5683 */ 5684 protected int getHorizontalScrollbarHeight() { 5685 ScrollabilityCache cache = mScrollCache; 5686 if (cache != null) { 5687 ScrollBarDrawable scrollBar = cache.scrollBar; 5688 if (scrollBar != null) { 5689 int size = scrollBar.getSize(false); 5690 if (size <= 0) { 5691 size = cache.scrollBarSize; 5692 } 5693 return size; 5694 } 5695 return 0; 5696 } 5697 return 0; 5698 } 5699 5700 /** 5701 * <p> 5702 * Initializes the scrollbars from a given set of styled attributes. This 5703 * method should be called by subclasses that need scrollbars and when an 5704 * instance of these subclasses is created programmatically rather than 5705 * being inflated from XML. This method is automatically called when the XML 5706 * is inflated. 5707 * </p> 5708 * 5709 * @param a the styled attributes set to initialize the scrollbars from 5710 * 5711 * @removed 5712 */ 5713 protected void initializeScrollbars(TypedArray a) { 5714 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5715 // using the View filter array which is not available to the SDK. As such, internal 5716 // framework usage now uses initializeScrollbarsInternal and we grab a default 5717 // TypedArray with the right filter instead here. 5718 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5719 5720 initializeScrollbarsInternal(arr); 5721 5722 // We ignored the method parameter. Recycle the one we actually did use. 5723 arr.recycle(); 5724 } 5725 5726 /** 5727 * <p> 5728 * Initializes the scrollbars from a given set of styled attributes. This 5729 * method should be called by subclasses that need scrollbars and when an 5730 * instance of these subclasses is created programmatically rather than 5731 * being inflated from XML. This method is automatically called when the XML 5732 * is inflated. 5733 * </p> 5734 * 5735 * @param a the styled attributes set to initialize the scrollbars from 5736 * @hide 5737 */ 5738 protected void initializeScrollbarsInternal(TypedArray a) { 5739 initScrollCache(); 5740 5741 final ScrollabilityCache scrollabilityCache = mScrollCache; 5742 5743 if (scrollabilityCache.scrollBar == null) { 5744 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5745 scrollabilityCache.scrollBar.setState(getDrawableState()); 5746 scrollabilityCache.scrollBar.setCallback(this); 5747 } 5748 5749 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5750 5751 if (!fadeScrollbars) { 5752 scrollabilityCache.state = ScrollabilityCache.ON; 5753 } 5754 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5755 5756 5757 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5758 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5759 .getScrollBarFadeDuration()); 5760 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5761 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5762 ViewConfiguration.getScrollDefaultDelay()); 5763 5764 5765 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5766 com.android.internal.R.styleable.View_scrollbarSize, 5767 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5768 5769 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5770 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5771 5772 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5773 if (thumb != null) { 5774 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5775 } 5776 5777 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5778 false); 5779 if (alwaysDraw) { 5780 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5781 } 5782 5783 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5784 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5785 5786 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5787 if (thumb != null) { 5788 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5789 } 5790 5791 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5792 false); 5793 if (alwaysDraw) { 5794 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5795 } 5796 5797 // Apply layout direction to the new Drawables if needed 5798 final int layoutDirection = getLayoutDirection(); 5799 if (track != null) { 5800 track.setLayoutDirection(layoutDirection); 5801 } 5802 if (thumb != null) { 5803 thumb.setLayoutDirection(layoutDirection); 5804 } 5805 5806 // Re-apply user/background padding so that scrollbar(s) get added 5807 resolvePadding(); 5808 } 5809 5810 private void initializeScrollIndicatorsInternal() { 5811 // Some day maybe we'll break this into top/left/start/etc. and let the 5812 // client control it. Until then, you can have any scroll indicator you 5813 // want as long as it's a 1dp foreground-colored rectangle. 5814 if (mScrollIndicatorDrawable == null) { 5815 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5816 } 5817 } 5818 5819 /** 5820 * <p> 5821 * Initalizes the scrollability cache if necessary. 5822 * </p> 5823 */ 5824 private void initScrollCache() { 5825 if (mScrollCache == null) { 5826 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5827 } 5828 } 5829 5830 private ScrollabilityCache getScrollCache() { 5831 initScrollCache(); 5832 return mScrollCache; 5833 } 5834 5835 /** 5836 * Set the position of the vertical scroll bar. Should be one of 5837 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5838 * {@link #SCROLLBAR_POSITION_RIGHT}. 5839 * 5840 * @param position Where the vertical scroll bar should be positioned. 5841 */ 5842 public void setVerticalScrollbarPosition(int position) { 5843 if (mVerticalScrollbarPosition != position) { 5844 mVerticalScrollbarPosition = position; 5845 computeOpaqueFlags(); 5846 resolvePadding(); 5847 } 5848 } 5849 5850 /** 5851 * @return The position where the vertical scroll bar will show, if applicable. 5852 * @see #setVerticalScrollbarPosition(int) 5853 */ 5854 public int getVerticalScrollbarPosition() { 5855 return mVerticalScrollbarPosition; 5856 } 5857 5858 boolean isOnScrollbar(float x, float y) { 5859 if (mScrollCache == null) { 5860 return false; 5861 } 5862 x += getScrollX(); 5863 y += getScrollY(); 5864 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5865 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5866 getVerticalScrollBarBounds(null, touchBounds); 5867 if (touchBounds.contains((int) x, (int) y)) { 5868 return true; 5869 } 5870 } 5871 if (isHorizontalScrollBarEnabled()) { 5872 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5873 getHorizontalScrollBarBounds(null, touchBounds); 5874 if (touchBounds.contains((int) x, (int) y)) { 5875 return true; 5876 } 5877 } 5878 return false; 5879 } 5880 5881 boolean isOnScrollbarThumb(float x, float y) { 5882 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5883 } 5884 5885 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5886 if (mScrollCache == null) { 5887 return false; 5888 } 5889 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5890 x += getScrollX(); 5891 y += getScrollY(); 5892 final Rect bounds = mScrollCache.mScrollBarBounds; 5893 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5894 getVerticalScrollBarBounds(bounds, touchBounds); 5895 final int range = computeVerticalScrollRange(); 5896 final int offset = computeVerticalScrollOffset(); 5897 final int extent = computeVerticalScrollExtent(); 5898 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5899 extent, range); 5900 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5901 extent, range, offset); 5902 final int thumbTop = bounds.top + thumbOffset; 5903 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5904 if (x >= touchBounds.left && x <= touchBounds.right 5905 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 5906 return true; 5907 } 5908 } 5909 return false; 5910 } 5911 5912 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5913 if (mScrollCache == null) { 5914 return false; 5915 } 5916 if (isHorizontalScrollBarEnabled()) { 5917 x += getScrollX(); 5918 y += getScrollY(); 5919 final Rect bounds = mScrollCache.mScrollBarBounds; 5920 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 5921 getHorizontalScrollBarBounds(bounds, touchBounds); 5922 final int range = computeHorizontalScrollRange(); 5923 final int offset = computeHorizontalScrollOffset(); 5924 final int extent = computeHorizontalScrollExtent(); 5925 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5926 extent, range); 5927 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5928 extent, range, offset); 5929 final int thumbLeft = bounds.left + thumbOffset; 5930 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 5931 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 5932 && y >= touchBounds.top && y <= touchBounds.bottom) { 5933 return true; 5934 } 5935 } 5936 return false; 5937 } 5938 5939 boolean isDraggingScrollBar() { 5940 return mScrollCache != null 5941 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5942 } 5943 5944 /** 5945 * Sets the state of all scroll indicators. 5946 * <p> 5947 * See {@link #setScrollIndicators(int, int)} for usage information. 5948 * 5949 * @param indicators a bitmask of indicators that should be enabled, or 5950 * {@code 0} to disable all indicators 5951 * @see #setScrollIndicators(int, int) 5952 * @see #getScrollIndicators() 5953 * @attr ref android.R.styleable#View_scrollIndicators 5954 */ 5955 public void setScrollIndicators(@ScrollIndicators int indicators) { 5956 setScrollIndicators(indicators, 5957 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5958 } 5959 5960 /** 5961 * Sets the state of the scroll indicators specified by the mask. To change 5962 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5963 * <p> 5964 * When a scroll indicator is enabled, it will be displayed if the view 5965 * can scroll in the direction of the indicator. 5966 * <p> 5967 * Multiple indicator types may be enabled or disabled by passing the 5968 * logical OR of the desired types. If multiple types are specified, they 5969 * will all be set to the same enabled state. 5970 * <p> 5971 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5972 * 5973 * @param indicators the indicator direction, or the logical OR of multiple 5974 * indicator directions. One or more of: 5975 * <ul> 5976 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5977 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5978 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5979 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5980 * <li>{@link #SCROLL_INDICATOR_START}</li> 5981 * <li>{@link #SCROLL_INDICATOR_END}</li> 5982 * </ul> 5983 * @see #setScrollIndicators(int) 5984 * @see #getScrollIndicators() 5985 * @attr ref android.R.styleable#View_scrollIndicators 5986 */ 5987 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5988 // Shift and sanitize mask. 5989 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5990 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5991 5992 // Shift and mask indicators. 5993 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5994 indicators &= mask; 5995 5996 // Merge with non-masked flags. 5997 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5998 5999 if (mPrivateFlags3 != updatedFlags) { 6000 mPrivateFlags3 = updatedFlags; 6001 6002 if (indicators != 0) { 6003 initializeScrollIndicatorsInternal(); 6004 } 6005 invalidate(); 6006 } 6007 } 6008 6009 /** 6010 * Returns a bitmask representing the enabled scroll indicators. 6011 * <p> 6012 * For example, if the top and left scroll indicators are enabled and all 6013 * other indicators are disabled, the return value will be 6014 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 6015 * <p> 6016 * To check whether the bottom scroll indicator is enabled, use the value 6017 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 6018 * 6019 * @return a bitmask representing the enabled scroll indicators 6020 */ 6021 @ScrollIndicators 6022 public int getScrollIndicators() { 6023 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 6024 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6025 } 6026 6027 ListenerInfo getListenerInfo() { 6028 if (mListenerInfo != null) { 6029 return mListenerInfo; 6030 } 6031 mListenerInfo = new ListenerInfo(); 6032 return mListenerInfo; 6033 } 6034 6035 /** 6036 * Register a callback to be invoked when the scroll X or Y positions of 6037 * this view change. 6038 * <p> 6039 * <b>Note:</b> Some views handle scrolling independently from View and may 6040 * have their own separate listeners for scroll-type events. For example, 6041 * {@link android.widget.ListView ListView} allows clients to register an 6042 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 6043 * to listen for changes in list scroll position. 6044 * 6045 * @param l The listener to notify when the scroll X or Y position changes. 6046 * @see android.view.View#getScrollX() 6047 * @see android.view.View#getScrollY() 6048 */ 6049 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6050 getListenerInfo().mOnScrollChangeListener = l; 6051 } 6052 6053 /** 6054 * Register a callback to be invoked when focus of this view changed. 6055 * 6056 * @param l The callback that will run. 6057 */ 6058 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6059 getListenerInfo().mOnFocusChangeListener = l; 6060 } 6061 6062 /** 6063 * Add a listener that will be called when the bounds of the view change due to 6064 * layout processing. 6065 * 6066 * @param listener The listener that will be called when layout bounds change. 6067 */ 6068 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6069 ListenerInfo li = getListenerInfo(); 6070 if (li.mOnLayoutChangeListeners == null) { 6071 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6072 } 6073 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6074 li.mOnLayoutChangeListeners.add(listener); 6075 } 6076 } 6077 6078 /** 6079 * Remove a listener for layout changes. 6080 * 6081 * @param listener The listener for layout bounds change. 6082 */ 6083 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 6084 ListenerInfo li = mListenerInfo; 6085 if (li == null || li.mOnLayoutChangeListeners == null) { 6086 return; 6087 } 6088 li.mOnLayoutChangeListeners.remove(listener); 6089 } 6090 6091 /** 6092 * Add a listener for attach state changes. 6093 * 6094 * This listener will be called whenever this view is attached or detached 6095 * from a window. Remove the listener using 6096 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 6097 * 6098 * @param listener Listener to attach 6099 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 6100 */ 6101 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6102 ListenerInfo li = getListenerInfo(); 6103 if (li.mOnAttachStateChangeListeners == null) { 6104 li.mOnAttachStateChangeListeners 6105 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 6106 } 6107 li.mOnAttachStateChangeListeners.add(listener); 6108 } 6109 6110 /** 6111 * Remove a listener for attach state changes. The listener will receive no further 6112 * notification of window attach/detach events. 6113 * 6114 * @param listener Listener to remove 6115 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 6116 */ 6117 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6118 ListenerInfo li = mListenerInfo; 6119 if (li == null || li.mOnAttachStateChangeListeners == null) { 6120 return; 6121 } 6122 li.mOnAttachStateChangeListeners.remove(listener); 6123 } 6124 6125 /** 6126 * Returns the focus-change callback registered for this view. 6127 * 6128 * @return The callback, or null if one is not registered. 6129 */ 6130 public OnFocusChangeListener getOnFocusChangeListener() { 6131 ListenerInfo li = mListenerInfo; 6132 return li != null ? li.mOnFocusChangeListener : null; 6133 } 6134 6135 /** 6136 * Register a callback to be invoked when this view is clicked. If this view is not 6137 * clickable, it becomes clickable. 6138 * 6139 * @param l The callback that will run 6140 * 6141 * @see #setClickable(boolean) 6142 */ 6143 public void setOnClickListener(@Nullable OnClickListener l) { 6144 if (!isClickable()) { 6145 setClickable(true); 6146 } 6147 getListenerInfo().mOnClickListener = l; 6148 } 6149 6150 /** 6151 * Return whether this view has an attached OnClickListener. Returns 6152 * true if there is a listener, false if there is none. 6153 */ 6154 public boolean hasOnClickListeners() { 6155 ListenerInfo li = mListenerInfo; 6156 return (li != null && li.mOnClickListener != null); 6157 } 6158 6159 /** 6160 * Register a callback to be invoked when this view is clicked and held. If this view is not 6161 * long clickable, it becomes long clickable. 6162 * 6163 * @param l The callback that will run 6164 * 6165 * @see #setLongClickable(boolean) 6166 */ 6167 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6168 if (!isLongClickable()) { 6169 setLongClickable(true); 6170 } 6171 getListenerInfo().mOnLongClickListener = l; 6172 } 6173 6174 /** 6175 * Register a callback to be invoked when this view is context clicked. If the view is not 6176 * context clickable, it becomes context clickable. 6177 * 6178 * @param l The callback that will run 6179 * @see #setContextClickable(boolean) 6180 */ 6181 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6182 if (!isContextClickable()) { 6183 setContextClickable(true); 6184 } 6185 getListenerInfo().mOnContextClickListener = l; 6186 } 6187 6188 /** 6189 * Register a callback to be invoked when the context menu for this view is 6190 * being built. If this view is not long clickable, it becomes long clickable. 6191 * 6192 * @param l The callback that will run 6193 * 6194 */ 6195 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6196 if (!isLongClickable()) { 6197 setLongClickable(true); 6198 } 6199 getListenerInfo().mOnCreateContextMenuListener = l; 6200 } 6201 6202 /** 6203 * Set an observer to collect stats for each frame rendered for this view. 6204 * 6205 * @hide 6206 */ 6207 public void addFrameMetricsListener(Window window, 6208 Window.OnFrameMetricsAvailableListener listener, 6209 Handler handler) { 6210 if (mAttachInfo != null) { 6211 if (mAttachInfo.mThreadedRenderer != null) { 6212 if (mFrameMetricsObservers == null) { 6213 mFrameMetricsObservers = new ArrayList<>(); 6214 } 6215 6216 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6217 handler.getLooper(), listener); 6218 mFrameMetricsObservers.add(fmo); 6219 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 6220 } else { 6221 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6222 } 6223 } else { 6224 if (mFrameMetricsObservers == null) { 6225 mFrameMetricsObservers = new ArrayList<>(); 6226 } 6227 6228 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 6229 handler.getLooper(), listener); 6230 mFrameMetricsObservers.add(fmo); 6231 } 6232 } 6233 6234 /** 6235 * Remove observer configured to collect frame stats for this view. 6236 * 6237 * @hide 6238 */ 6239 public void removeFrameMetricsListener( 6240 Window.OnFrameMetricsAvailableListener listener) { 6241 ThreadedRenderer renderer = getThreadedRenderer(); 6242 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 6243 if (fmo == null) { 6244 throw new IllegalArgumentException( 6245 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 6246 } 6247 6248 if (mFrameMetricsObservers != null) { 6249 mFrameMetricsObservers.remove(fmo); 6250 if (renderer != null) { 6251 renderer.removeFrameMetricsObserver(fmo); 6252 } 6253 } 6254 } 6255 6256 private void registerPendingFrameMetricsObservers() { 6257 if (mFrameMetricsObservers != null) { 6258 ThreadedRenderer renderer = getThreadedRenderer(); 6259 if (renderer != null) { 6260 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 6261 renderer.addFrameMetricsObserver(fmo); 6262 } 6263 } else { 6264 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 6265 } 6266 } 6267 } 6268 6269 private FrameMetricsObserver findFrameMetricsObserver( 6270 Window.OnFrameMetricsAvailableListener listener) { 6271 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 6272 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 6273 if (observer.mListener == listener) { 6274 return observer; 6275 } 6276 } 6277 6278 return null; 6279 } 6280 6281 /** 6282 * Call this view's OnClickListener, if it is defined. Performs all normal 6283 * actions associated with clicking: reporting accessibility event, playing 6284 * a sound, etc. 6285 * 6286 * @return True there was an assigned OnClickListener that was called, false 6287 * otherwise is returned. 6288 */ 6289 public boolean performClick() { 6290 final boolean result; 6291 final ListenerInfo li = mListenerInfo; 6292 if (li != null && li.mOnClickListener != null) { 6293 playSoundEffect(SoundEffectConstants.CLICK); 6294 li.mOnClickListener.onClick(this); 6295 result = true; 6296 } else { 6297 result = false; 6298 } 6299 6300 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 6301 6302 notifyEnterOrExitForAutoFillIfNeeded(true); 6303 6304 return result; 6305 } 6306 6307 /** 6308 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 6309 * this only calls the listener, and does not do any associated clicking 6310 * actions like reporting an accessibility event. 6311 * 6312 * @return True there was an assigned OnClickListener that was called, false 6313 * otherwise is returned. 6314 */ 6315 public boolean callOnClick() { 6316 ListenerInfo li = mListenerInfo; 6317 if (li != null && li.mOnClickListener != null) { 6318 li.mOnClickListener.onClick(this); 6319 return true; 6320 } 6321 return false; 6322 } 6323 6324 /** 6325 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6326 * context menu if the OnLongClickListener did not consume the event. 6327 * 6328 * @return {@code true} if one of the above receivers consumed the event, 6329 * {@code false} otherwise 6330 */ 6331 public boolean performLongClick() { 6332 return performLongClickInternal(mLongClickX, mLongClickY); 6333 } 6334 6335 /** 6336 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6337 * context menu if the OnLongClickListener did not consume the event, 6338 * anchoring it to an (x,y) coordinate. 6339 * 6340 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6341 * to disable anchoring 6342 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6343 * to disable anchoring 6344 * @return {@code true} if one of the above receivers consumed the event, 6345 * {@code false} otherwise 6346 */ 6347 public boolean performLongClick(float x, float y) { 6348 mLongClickX = x; 6349 mLongClickY = y; 6350 final boolean handled = performLongClick(); 6351 mLongClickX = Float.NaN; 6352 mLongClickY = Float.NaN; 6353 return handled; 6354 } 6355 6356 /** 6357 * Calls this view's OnLongClickListener, if it is defined. Invokes the 6358 * context menu if the OnLongClickListener did not consume the event, 6359 * optionally anchoring it to an (x,y) coordinate. 6360 * 6361 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 6362 * to disable anchoring 6363 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 6364 * to disable anchoring 6365 * @return {@code true} if one of the above receivers consumed the event, 6366 * {@code false} otherwise 6367 */ 6368 private boolean performLongClickInternal(float x, float y) { 6369 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 6370 6371 boolean handled = false; 6372 final ListenerInfo li = mListenerInfo; 6373 if (li != null && li.mOnLongClickListener != null) { 6374 handled = li.mOnLongClickListener.onLongClick(View.this); 6375 } 6376 if (!handled) { 6377 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 6378 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 6379 } 6380 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 6381 if (!handled) { 6382 handled = showLongClickTooltip((int) x, (int) y); 6383 } 6384 } 6385 if (handled) { 6386 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 6387 } 6388 return handled; 6389 } 6390 6391 /** 6392 * Call this view's OnContextClickListener, if it is defined. 6393 * 6394 * @param x the x coordinate of the context click 6395 * @param y the y coordinate of the context click 6396 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6397 * otherwise. 6398 */ 6399 public boolean performContextClick(float x, float y) { 6400 return performContextClick(); 6401 } 6402 6403 /** 6404 * Call this view's OnContextClickListener, if it is defined. 6405 * 6406 * @return True if there was an assigned OnContextClickListener that consumed the event, false 6407 * otherwise. 6408 */ 6409 public boolean performContextClick() { 6410 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 6411 6412 boolean handled = false; 6413 ListenerInfo li = mListenerInfo; 6414 if (li != null && li.mOnContextClickListener != null) { 6415 handled = li.mOnContextClickListener.onContextClick(View.this); 6416 } 6417 if (handled) { 6418 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 6419 } 6420 return handled; 6421 } 6422 6423 /** 6424 * Performs button-related actions during a touch down event. 6425 * 6426 * @param event The event. 6427 * @return True if the down was consumed. 6428 * 6429 * @hide 6430 */ 6431 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 6432 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 6433 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 6434 showContextMenu(event.getX(), event.getY()); 6435 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 6436 return true; 6437 } 6438 return false; 6439 } 6440 6441 /** 6442 * Shows the context menu for this view. 6443 * 6444 * @return {@code true} if the context menu was shown, {@code false} 6445 * otherwise 6446 * @see #showContextMenu(float, float) 6447 */ 6448 public boolean showContextMenu() { 6449 return getParent().showContextMenuForChild(this); 6450 } 6451 6452 /** 6453 * Shows the context menu for this view anchored to the specified 6454 * view-relative coordinate. 6455 * 6456 * @param x the X coordinate in pixels relative to the view to which the 6457 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6458 * @param y the Y coordinate in pixels relative to the view to which the 6459 * menu should be anchored, or {@link Float#NaN} to disable anchoring 6460 * @return {@code true} if the context menu was shown, {@code false} 6461 * otherwise 6462 */ 6463 public boolean showContextMenu(float x, float y) { 6464 return getParent().showContextMenuForChild(this, x, y); 6465 } 6466 6467 /** 6468 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 6469 * 6470 * @param callback Callback that will control the lifecycle of the action mode 6471 * @return The new action mode if it is started, null otherwise 6472 * 6473 * @see ActionMode 6474 * @see #startActionMode(android.view.ActionMode.Callback, int) 6475 */ 6476 public ActionMode startActionMode(ActionMode.Callback callback) { 6477 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 6478 } 6479 6480 /** 6481 * Start an action mode with the given type. 6482 * 6483 * @param callback Callback that will control the lifecycle of the action mode 6484 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 6485 * @return The new action mode if it is started, null otherwise 6486 * 6487 * @see ActionMode 6488 */ 6489 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 6490 ViewParent parent = getParent(); 6491 if (parent == null) return null; 6492 try { 6493 return parent.startActionModeForChild(this, callback, type); 6494 } catch (AbstractMethodError ame) { 6495 // Older implementations of custom views might not implement this. 6496 return parent.startActionModeForChild(this, callback); 6497 } 6498 } 6499 6500 /** 6501 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 6502 * Context, creating a unique View identifier to retrieve the result. 6503 * 6504 * @param intent The Intent to be started. 6505 * @param requestCode The request code to use. 6506 * @hide 6507 */ 6508 public void startActivityForResult(Intent intent, int requestCode) { 6509 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 6510 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 6511 } 6512 6513 /** 6514 * If this View corresponds to the calling who, dispatches the activity result. 6515 * @param who The identifier for the targeted View to receive the result. 6516 * @param requestCode The integer request code originally supplied to 6517 * startActivityForResult(), allowing you to identify who this 6518 * result came from. 6519 * @param resultCode The integer result code returned by the child activity 6520 * through its setResult(). 6521 * @param data An Intent, which can return result data to the caller 6522 * (various data can be attached to Intent "extras"). 6523 * @return {@code true} if the activity result was dispatched. 6524 * @hide 6525 */ 6526 public boolean dispatchActivityResult( 6527 String who, int requestCode, int resultCode, Intent data) { 6528 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 6529 onActivityResult(requestCode, resultCode, data); 6530 mStartActivityRequestWho = null; 6531 return true; 6532 } 6533 return false; 6534 } 6535 6536 /** 6537 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 6538 * 6539 * @param requestCode The integer request code originally supplied to 6540 * startActivityForResult(), allowing you to identify who this 6541 * result came from. 6542 * @param resultCode The integer result code returned by the child activity 6543 * through its setResult(). 6544 * @param data An Intent, which can return result data to the caller 6545 * (various data can be attached to Intent "extras"). 6546 * @hide 6547 */ 6548 public void onActivityResult(int requestCode, int resultCode, Intent data) { 6549 // Do nothing. 6550 } 6551 6552 /** 6553 * Register a callback to be invoked when a hardware key is pressed in this view. 6554 * Key presses in software input methods will generally not trigger the methods of 6555 * this listener. 6556 * @param l the key listener to attach to this view 6557 */ 6558 public void setOnKeyListener(OnKeyListener l) { 6559 getListenerInfo().mOnKeyListener = l; 6560 } 6561 6562 /** 6563 * Register a callback to be invoked when a touch event is sent to this view. 6564 * @param l the touch listener to attach to this view 6565 */ 6566 public void setOnTouchListener(OnTouchListener l) { 6567 getListenerInfo().mOnTouchListener = l; 6568 } 6569 6570 /** 6571 * Register a callback to be invoked when a generic motion event is sent to this view. 6572 * @param l the generic motion listener to attach to this view 6573 */ 6574 public void setOnGenericMotionListener(OnGenericMotionListener l) { 6575 getListenerInfo().mOnGenericMotionListener = l; 6576 } 6577 6578 /** 6579 * Register a callback to be invoked when a hover event is sent to this view. 6580 * @param l the hover listener to attach to this view 6581 */ 6582 public void setOnHoverListener(OnHoverListener l) { 6583 getListenerInfo().mOnHoverListener = l; 6584 } 6585 6586 /** 6587 * Register a drag event listener callback object for this View. The parameter is 6588 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 6589 * View, the system calls the 6590 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 6591 * @param l An implementation of {@link android.view.View.OnDragListener}. 6592 */ 6593 public void setOnDragListener(OnDragListener l) { 6594 getListenerInfo().mOnDragListener = l; 6595 } 6596 6597 /** 6598 * Give this view focus. This will cause 6599 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 6600 * 6601 * Note: this does not check whether this {@link View} should get focus, it just 6602 * gives it focus no matter what. It should only be called internally by framework 6603 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 6604 * 6605 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 6606 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 6607 * focus moved when requestFocus() is called. It may not always 6608 * apply, in which case use the default View.FOCUS_DOWN. 6609 * @param previouslyFocusedRect The rectangle of the view that had focus 6610 * prior in this View's coordinate system. 6611 */ 6612 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 6613 if (DBG) { 6614 System.out.println(this + " requestFocus()"); 6615 } 6616 6617 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 6618 mPrivateFlags |= PFLAG_FOCUSED; 6619 6620 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 6621 6622 if (mParent != null) { 6623 mParent.requestChildFocus(this, this); 6624 updateFocusedInCluster(oldFocus, direction); 6625 } 6626 6627 if (mAttachInfo != null) { 6628 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 6629 } 6630 6631 onFocusChanged(true, direction, previouslyFocusedRect); 6632 refreshDrawableState(); 6633 } 6634 } 6635 6636 /** 6637 * Sets this view's preference for reveal behavior when it gains focus. 6638 * 6639 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 6640 * this view would prefer to be brought fully into view when it gains focus. 6641 * For example, a text field that a user is meant to type into. Other views such 6642 * as scrolling containers may prefer to opt-out of this behavior.</p> 6643 * 6644 * <p>The default value for views is true, though subclasses may change this 6645 * based on their preferred behavior.</p> 6646 * 6647 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 6648 * 6649 * @see #getRevealOnFocusHint() 6650 */ 6651 public final void setRevealOnFocusHint(boolean revealOnFocus) { 6652 if (revealOnFocus) { 6653 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 6654 } else { 6655 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 6656 } 6657 } 6658 6659 /** 6660 * Returns this view's preference for reveal behavior when it gains focus. 6661 * 6662 * <p>When this method returns true for a child view requesting focus, ancestor 6663 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 6664 * should make a best effort to make the newly focused child fully visible to the user. 6665 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6666 * other properties affecting visibility to the user as part of the focus change.</p> 6667 * 6668 * @return true if this view would prefer to become fully visible when it gains focus, 6669 * false if it would prefer not to disrupt scroll positioning 6670 * 6671 * @see #setRevealOnFocusHint(boolean) 6672 */ 6673 public final boolean getRevealOnFocusHint() { 6674 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6675 } 6676 6677 /** 6678 * Populates <code>outRect</code> with the hotspot bounds. By default, 6679 * the hotspot bounds are identical to the screen bounds. 6680 * 6681 * @param outRect rect to populate with hotspot bounds 6682 * @hide Only for internal use by views and widgets. 6683 */ 6684 public void getHotspotBounds(Rect outRect) { 6685 final Drawable background = getBackground(); 6686 if (background != null) { 6687 background.getHotspotBounds(outRect); 6688 } else { 6689 getBoundsOnScreen(outRect); 6690 } 6691 } 6692 6693 /** 6694 * Request that a rectangle of this view be visible on the screen, 6695 * scrolling if necessary just enough. 6696 * 6697 * <p>A View should call this if it maintains some notion of which part 6698 * of its content is interesting. For example, a text editing view 6699 * should call this when its cursor moves. 6700 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6701 * It should not be affected by which part of the View is currently visible or its scroll 6702 * position. 6703 * 6704 * @param rectangle The rectangle in the View's content coordinate space 6705 * @return Whether any parent scrolled. 6706 */ 6707 public boolean requestRectangleOnScreen(Rect rectangle) { 6708 return requestRectangleOnScreen(rectangle, false); 6709 } 6710 6711 /** 6712 * Request that a rectangle of this view be visible on the screen, 6713 * scrolling if necessary just enough. 6714 * 6715 * <p>A View should call this if it maintains some notion of which part 6716 * of its content is interesting. For example, a text editing view 6717 * should call this when its cursor moves. 6718 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6719 * It should not be affected by which part of the View is currently visible or its scroll 6720 * position. 6721 * <p>When <code>immediate</code> is set to true, scrolling will not be 6722 * animated. 6723 * 6724 * @param rectangle The rectangle in the View's content coordinate space 6725 * @param immediate True to forbid animated scrolling, false otherwise 6726 * @return Whether any parent scrolled. 6727 */ 6728 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6729 if (mParent == null) { 6730 return false; 6731 } 6732 6733 View child = this; 6734 6735 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6736 position.set(rectangle); 6737 6738 ViewParent parent = mParent; 6739 boolean scrolled = false; 6740 while (parent != null) { 6741 rectangle.set((int) position.left, (int) position.top, 6742 (int) position.right, (int) position.bottom); 6743 6744 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6745 6746 if (!(parent instanceof View)) { 6747 break; 6748 } 6749 6750 // move it from child's content coordinate space to parent's content coordinate space 6751 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6752 6753 child = (View) parent; 6754 parent = child.getParent(); 6755 } 6756 6757 return scrolled; 6758 } 6759 6760 /** 6761 * Called when this view wants to give up focus. If focus is cleared 6762 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6763 * <p> 6764 * <strong>Note:</strong> When a View clears focus the framework is trying 6765 * to give focus to the first focusable View from the top. Hence, if this 6766 * View is the first from the top that can take focus, then all callbacks 6767 * related to clearing focus will be invoked after which the framework will 6768 * give focus to this view. 6769 * </p> 6770 */ 6771 public void clearFocus() { 6772 if (DBG) { 6773 System.out.println(this + " clearFocus()"); 6774 } 6775 6776 clearFocusInternal(null, true, true); 6777 } 6778 6779 /** 6780 * Clears focus from the view, optionally propagating the change up through 6781 * the parent hierarchy and requesting that the root view place new focus. 6782 * 6783 * @param propagate whether to propagate the change up through the parent 6784 * hierarchy 6785 * @param refocus when propagate is true, specifies whether to request the 6786 * root view place new focus 6787 */ 6788 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6789 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6790 mPrivateFlags &= ~PFLAG_FOCUSED; 6791 6792 if (propagate && mParent != null) { 6793 mParent.clearChildFocus(this); 6794 } 6795 6796 onFocusChanged(false, 0, null); 6797 refreshDrawableState(); 6798 6799 if (propagate && (!refocus || !rootViewRequestFocus())) { 6800 notifyGlobalFocusCleared(this); 6801 } 6802 } 6803 } 6804 6805 void notifyGlobalFocusCleared(View oldFocus) { 6806 if (oldFocus != null && mAttachInfo != null) { 6807 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6808 } 6809 } 6810 6811 boolean rootViewRequestFocus() { 6812 final View root = getRootView(); 6813 return root != null && root.requestFocus(); 6814 } 6815 6816 /** 6817 * Called internally by the view system when a new view is getting focus. 6818 * This is what clears the old focus. 6819 * <p> 6820 * <b>NOTE:</b> The parent view's focused child must be updated manually 6821 * after calling this method. Otherwise, the view hierarchy may be left in 6822 * an inconstent state. 6823 */ 6824 void unFocus(View focused) { 6825 if (DBG) { 6826 System.out.println(this + " unFocus()"); 6827 } 6828 6829 clearFocusInternal(focused, false, false); 6830 } 6831 6832 /** 6833 * Returns true if this view has focus itself, or is the ancestor of the 6834 * view that has focus. 6835 * 6836 * @return True if this view has or contains focus, false otherwise. 6837 */ 6838 @ViewDebug.ExportedProperty(category = "focus") 6839 public boolean hasFocus() { 6840 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6841 } 6842 6843 /** 6844 * Returns true if this view is focusable or if it contains a reachable View 6845 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 6846 * is a view whose parents do not block descendants focus. 6847 * Only {@link #VISIBLE} views are considered focusable. 6848 * 6849 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 6850 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 6851 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 6852 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 6853 * {@code false} for views not explicitly marked as focusable. 6854 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 6855 * behavior.</p> 6856 * 6857 * @return {@code true} if the view is focusable or if the view contains a focusable 6858 * view, {@code false} otherwise 6859 * 6860 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6861 * @see ViewGroup#getTouchscreenBlocksFocus() 6862 * @see #hasExplicitFocusable() 6863 */ 6864 public boolean hasFocusable() { 6865 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 6866 } 6867 6868 /** 6869 * Returns true if this view is focusable or if it contains a reachable View 6870 * for which {@link #hasExplicitFocusable()} returns {@code true}. 6871 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 6872 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 6873 * {@link #FOCUSABLE} are considered focusable. 6874 * 6875 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 6876 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 6877 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 6878 * to focusable will not.</p> 6879 * 6880 * @return {@code true} if the view is focusable or if the view contains a focusable 6881 * view, {@code false} otherwise 6882 * 6883 * @see #hasFocusable() 6884 */ 6885 public boolean hasExplicitFocusable() { 6886 return hasFocusable(false, true); 6887 } 6888 6889 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 6890 if (!isFocusableInTouchMode()) { 6891 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6892 final ViewGroup g = (ViewGroup) p; 6893 if (g.shouldBlockFocusForTouchscreen()) { 6894 return false; 6895 } 6896 } 6897 } 6898 6899 // Invisible and gone views are never focusable. 6900 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 6901 return false; 6902 } 6903 6904 // Only use effective focusable value when allowed. 6905 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 6906 return true; 6907 } 6908 6909 return false; 6910 } 6911 6912 /** 6913 * Called by the view system when the focus state of this view changes. 6914 * When the focus change event is caused by directional navigation, direction 6915 * and previouslyFocusedRect provide insight into where the focus is coming from. 6916 * When overriding, be sure to call up through to the super class so that 6917 * the standard focus handling will occur. 6918 * 6919 * @param gainFocus True if the View has focus; false otherwise. 6920 * @param direction The direction focus has moved when requestFocus() 6921 * is called to give this view focus. Values are 6922 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6923 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6924 * It may not always apply, in which case use the default. 6925 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6926 * system, of the previously focused view. If applicable, this will be 6927 * passed in as finer grained information about where the focus is coming 6928 * from (in addition to direction). Will be <code>null</code> otherwise. 6929 */ 6930 @CallSuper 6931 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6932 @Nullable Rect previouslyFocusedRect) { 6933 if (gainFocus) { 6934 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6935 } else { 6936 notifyViewAccessibilityStateChangedIfNeeded( 6937 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6938 } 6939 6940 // Here we check whether we still need the default focus highlight, and switch it on/off. 6941 switchDefaultFocusHighlight(); 6942 6943 InputMethodManager imm = InputMethodManager.peekInstance(); 6944 if (!gainFocus) { 6945 if (isPressed()) { 6946 setPressed(false); 6947 } 6948 if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6949 imm.focusOut(this); 6950 } 6951 onFocusLost(); 6952 } else if (imm != null && mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 6953 imm.focusIn(this); 6954 } 6955 6956 invalidate(true); 6957 ListenerInfo li = mListenerInfo; 6958 if (li != null && li.mOnFocusChangeListener != null) { 6959 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6960 } 6961 6962 if (mAttachInfo != null) { 6963 mAttachInfo.mKeyDispatchState.reset(this); 6964 } 6965 6966 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 6967 } 6968 6969 private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 6970 if (isAutofillable() && isAttachedToWindow()) { 6971 AutofillManager afm = getAutofillManager(); 6972 if (afm != null) { 6973 if (enter && hasWindowFocus() && isFocused()) { 6974 // We have not been laid out yet, hence cannot evaluate 6975 // whether this view is visible to the user, we will do 6976 // the evaluation once layout is complete. 6977 if (!isLaidOut()) { 6978 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 6979 } else if (isVisibleToUser()) { 6980 afm.notifyViewEntered(this); 6981 } 6982 } else if (!hasWindowFocus() || !isFocused()) { 6983 afm.notifyViewExited(this); 6984 } 6985 } 6986 } 6987 } 6988 6989 /** 6990 * Sends an accessibility event of the given type. If accessibility is 6991 * not enabled this method has no effect. The default implementation calls 6992 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6993 * to populate information about the event source (this View), then calls 6994 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6995 * populate the text content of the event source including its descendants, 6996 * and last calls 6997 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6998 * on its parent to request sending of the event to interested parties. 6999 * <p> 7000 * If an {@link AccessibilityDelegate} has been specified via calling 7001 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7002 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 7003 * responsible for handling this call. 7004 * </p> 7005 * 7006 * @param eventType The type of the event to send, as defined by several types from 7007 * {@link android.view.accessibility.AccessibilityEvent}, such as 7008 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 7009 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 7010 * 7011 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7012 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7013 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 7014 * @see AccessibilityDelegate 7015 */ 7016 public void sendAccessibilityEvent(int eventType) { 7017 if (mAccessibilityDelegate != null) { 7018 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 7019 } else { 7020 sendAccessibilityEventInternal(eventType); 7021 } 7022 } 7023 7024 /** 7025 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 7026 * {@link AccessibilityEvent} to make an announcement which is related to some 7027 * sort of a context change for which none of the events representing UI transitions 7028 * is a good fit. For example, announcing a new page in a book. If accessibility 7029 * is not enabled this method does nothing. 7030 * 7031 * @param text The announcement text. 7032 */ 7033 public void announceForAccessibility(CharSequence text) { 7034 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 7035 AccessibilityEvent event = AccessibilityEvent.obtain( 7036 AccessibilityEvent.TYPE_ANNOUNCEMENT); 7037 onInitializeAccessibilityEvent(event); 7038 event.getText().add(text); 7039 event.setContentDescription(null); 7040 mParent.requestSendAccessibilityEvent(this, event); 7041 } 7042 } 7043 7044 /** 7045 * @see #sendAccessibilityEvent(int) 7046 * 7047 * Note: Called from the default {@link AccessibilityDelegate}. 7048 * 7049 * @hide 7050 */ 7051 public void sendAccessibilityEventInternal(int eventType) { 7052 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7053 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 7054 } 7055 } 7056 7057 /** 7058 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 7059 * takes as an argument an empty {@link AccessibilityEvent} and does not 7060 * perform a check whether accessibility is enabled. 7061 * <p> 7062 * If an {@link AccessibilityDelegate} has been specified via calling 7063 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7064 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 7065 * is responsible for handling this call. 7066 * </p> 7067 * 7068 * @param event The event to send. 7069 * 7070 * @see #sendAccessibilityEvent(int) 7071 */ 7072 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 7073 if (mAccessibilityDelegate != null) { 7074 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 7075 } else { 7076 sendAccessibilityEventUncheckedInternal(event); 7077 } 7078 } 7079 7080 /** 7081 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 7082 * 7083 * Note: Called from the default {@link AccessibilityDelegate}. 7084 * 7085 * @hide 7086 */ 7087 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 7088 if (!isShown()) { 7089 return; 7090 } 7091 onInitializeAccessibilityEvent(event); 7092 // Only a subset of accessibility events populates text content. 7093 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 7094 dispatchPopulateAccessibilityEvent(event); 7095 } 7096 // In the beginning we called #isShown(), so we know that getParent() is not null. 7097 ViewParent parent = getParent(); 7098 if (parent != null) { 7099 getParent().requestSendAccessibilityEvent(this, event); 7100 } 7101 } 7102 7103 /** 7104 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 7105 * to its children for adding their text content to the event. Note that the 7106 * event text is populated in a separate dispatch path since we add to the 7107 * event not only the text of the source but also the text of all its descendants. 7108 * A typical implementation will call 7109 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 7110 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7111 * on each child. Override this method if custom population of the event text 7112 * content is required. 7113 * <p> 7114 * If an {@link AccessibilityDelegate} has been specified via calling 7115 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7116 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 7117 * is responsible for handling this call. 7118 * </p> 7119 * <p> 7120 * <em>Note:</em> Accessibility events of certain types are not dispatched for 7121 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 7122 * </p> 7123 * 7124 * @param event The event. 7125 * 7126 * @return True if the event population was completed. 7127 */ 7128 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 7129 if (mAccessibilityDelegate != null) { 7130 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 7131 } else { 7132 return dispatchPopulateAccessibilityEventInternal(event); 7133 } 7134 } 7135 7136 /** 7137 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7138 * 7139 * Note: Called from the default {@link AccessibilityDelegate}. 7140 * 7141 * @hide 7142 */ 7143 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7144 onPopulateAccessibilityEvent(event); 7145 return false; 7146 } 7147 7148 /** 7149 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 7150 * giving a chance to this View to populate the accessibility event with its 7151 * text content. While this method is free to modify event 7152 * attributes other than text content, doing so should normally be performed in 7153 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 7154 * <p> 7155 * Example: Adding formatted date string to an accessibility event in addition 7156 * to the text added by the super implementation: 7157 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7158 * super.onPopulateAccessibilityEvent(event); 7159 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 7160 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 7161 * mCurrentDate.getTimeInMillis(), flags); 7162 * event.getText().add(selectedDateUtterance); 7163 * }</pre> 7164 * <p> 7165 * If an {@link AccessibilityDelegate} has been specified via calling 7166 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7167 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 7168 * is responsible for handling this call. 7169 * </p> 7170 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7171 * information to the event, in case the default implementation has basic information to add. 7172 * </p> 7173 * 7174 * @param event The accessibility event which to populate. 7175 * 7176 * @see #sendAccessibilityEvent(int) 7177 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7178 */ 7179 @CallSuper 7180 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 7181 if (mAccessibilityDelegate != null) { 7182 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 7183 } else { 7184 onPopulateAccessibilityEventInternal(event); 7185 } 7186 } 7187 7188 /** 7189 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 7190 * 7191 * Note: Called from the default {@link AccessibilityDelegate}. 7192 * 7193 * @hide 7194 */ 7195 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 7196 } 7197 7198 /** 7199 * Initializes an {@link AccessibilityEvent} with information about 7200 * this View which is the event source. In other words, the source of 7201 * an accessibility event is the view whose state change triggered firing 7202 * the event. 7203 * <p> 7204 * Example: Setting the password property of an event in addition 7205 * to properties set by the super implementation: 7206 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7207 * super.onInitializeAccessibilityEvent(event); 7208 * event.setPassword(true); 7209 * }</pre> 7210 * <p> 7211 * If an {@link AccessibilityDelegate} has been specified via calling 7212 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7213 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 7214 * is responsible for handling this call. 7215 * </p> 7216 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 7217 * information to the event, in case the default implementation has basic information to add. 7218 * </p> 7219 * @param event The event to initialize. 7220 * 7221 * @see #sendAccessibilityEvent(int) 7222 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7223 */ 7224 @CallSuper 7225 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7226 if (mAccessibilityDelegate != null) { 7227 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 7228 } else { 7229 onInitializeAccessibilityEventInternal(event); 7230 } 7231 } 7232 7233 /** 7234 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7235 * 7236 * Note: Called from the default {@link AccessibilityDelegate}. 7237 * 7238 * @hide 7239 */ 7240 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 7241 event.setSource(this); 7242 event.setClassName(getAccessibilityClassName()); 7243 event.setPackageName(getContext().getPackageName()); 7244 event.setEnabled(isEnabled()); 7245 event.setContentDescription(mContentDescription); 7246 7247 switch (event.getEventType()) { 7248 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 7249 ArrayList<View> focusablesTempList = (mAttachInfo != null) 7250 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 7251 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 7252 event.setItemCount(focusablesTempList.size()); 7253 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 7254 if (mAttachInfo != null) { 7255 focusablesTempList.clear(); 7256 } 7257 } break; 7258 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 7259 CharSequence text = getIterableTextForAccessibility(); 7260 if (text != null && text.length() > 0) { 7261 event.setFromIndex(getAccessibilitySelectionStart()); 7262 event.setToIndex(getAccessibilitySelectionEnd()); 7263 event.setItemCount(text.length()); 7264 } 7265 } break; 7266 } 7267 } 7268 7269 /** 7270 * Returns an {@link AccessibilityNodeInfo} representing this view from the 7271 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 7272 * This method is responsible for obtaining an accessibility node info from a 7273 * pool of reusable instances and calling 7274 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 7275 * initialize the former. 7276 * <p> 7277 * Note: The client is responsible for recycling the obtained instance by calling 7278 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 7279 * </p> 7280 * 7281 * @return A populated {@link AccessibilityNodeInfo}. 7282 * 7283 * @see AccessibilityNodeInfo 7284 */ 7285 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 7286 if (mAccessibilityDelegate != null) { 7287 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 7288 } else { 7289 return createAccessibilityNodeInfoInternal(); 7290 } 7291 } 7292 7293 /** 7294 * @see #createAccessibilityNodeInfo() 7295 * 7296 * @hide 7297 */ 7298 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 7299 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7300 if (provider != null) { 7301 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 7302 } else { 7303 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 7304 onInitializeAccessibilityNodeInfo(info); 7305 return info; 7306 } 7307 } 7308 7309 /** 7310 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 7311 * The base implementation sets: 7312 * <ul> 7313 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 7314 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 7315 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 7316 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 7317 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 7318 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 7319 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 7320 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 7321 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 7322 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 7323 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 7324 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 7325 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 7326 * </ul> 7327 * <p> 7328 * Subclasses should override this method, call the super implementation, 7329 * and set additional attributes. 7330 * </p> 7331 * <p> 7332 * If an {@link AccessibilityDelegate} has been specified via calling 7333 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7334 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 7335 * is responsible for handling this call. 7336 * </p> 7337 * 7338 * @param info The instance to initialize. 7339 */ 7340 @CallSuper 7341 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7342 if (mAccessibilityDelegate != null) { 7343 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 7344 } else { 7345 onInitializeAccessibilityNodeInfoInternal(info); 7346 } 7347 } 7348 7349 /** 7350 * Gets the location of this view in screen coordinates. 7351 * 7352 * @param outRect The output location 7353 * @hide 7354 */ 7355 public void getBoundsOnScreen(Rect outRect) { 7356 getBoundsOnScreen(outRect, false); 7357 } 7358 7359 /** 7360 * Gets the location of this view in screen coordinates. 7361 * 7362 * @param outRect The output location 7363 * @param clipToParent Whether to clip child bounds to the parent ones. 7364 * @hide 7365 */ 7366 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 7367 if (mAttachInfo == null) { 7368 return; 7369 } 7370 7371 RectF position = mAttachInfo.mTmpTransformRect; 7372 position.set(0, 0, mRight - mLeft, mBottom - mTop); 7373 mapRectFromViewToScreenCoords(position, clipToParent); 7374 outRect.set(Math.round(position.left), Math.round(position.top), 7375 Math.round(position.right), Math.round(position.bottom)); 7376 } 7377 7378 /** 7379 * Map a rectangle from view-relative coordinates to screen-relative coordinates 7380 * 7381 * @param rect The rectangle to be mapped 7382 * @param clipToParent Whether to clip child bounds to the parent ones. 7383 * @hide 7384 */ 7385 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 7386 if (!hasIdentityMatrix()) { 7387 getMatrix().mapRect(rect); 7388 } 7389 7390 rect.offset(mLeft, mTop); 7391 7392 ViewParent parent = mParent; 7393 while (parent instanceof View) { 7394 View parentView = (View) parent; 7395 7396 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 7397 7398 if (clipToParent) { 7399 rect.left = Math.max(rect.left, 0); 7400 rect.top = Math.max(rect.top, 0); 7401 rect.right = Math.min(rect.right, parentView.getWidth()); 7402 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 7403 } 7404 7405 if (!parentView.hasIdentityMatrix()) { 7406 parentView.getMatrix().mapRect(rect); 7407 } 7408 7409 rect.offset(parentView.mLeft, parentView.mTop); 7410 7411 parent = parentView.mParent; 7412 } 7413 7414 if (parent instanceof ViewRootImpl) { 7415 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 7416 rect.offset(0, -viewRootImpl.mCurScrollY); 7417 } 7418 7419 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 7420 } 7421 7422 /** 7423 * Return the class name of this object to be used for accessibility purposes. 7424 * Subclasses should only override this if they are implementing something that 7425 * should be seen as a completely new class of view when used by accessibility, 7426 * unrelated to the class it is deriving from. This is used to fill in 7427 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 7428 */ 7429 public CharSequence getAccessibilityClassName() { 7430 return View.class.getName(); 7431 } 7432 7433 /** 7434 * Called when assist structure is being retrieved from a view as part of 7435 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 7436 * @param structure Fill in with structured view data. The default implementation 7437 * fills in all data that can be inferred from the view itself. 7438 */ 7439 public void onProvideStructure(ViewStructure structure) { 7440 onProvideStructureForAssistOrAutofill(structure, false, 0); 7441 } 7442 7443 /** 7444 * Populates a {@link ViewStructure} to fullfil an autofill request. 7445 * 7446 * <p>The structure should contain at least the following properties: 7447 * <ul> 7448 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 7449 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 7450 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 7451 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 7452 * </ul> 7453 * 7454 * <p>It's also recommended to set the following properties - the more properties the structure 7455 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 7456 * using the structure: 7457 * 7458 * <ul> 7459 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 7460 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 7461 * view can only be filled with predefined values (typically used when the autofill type 7462 * is {@link #AUTOFILL_TYPE_LIST}). 7463 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 7464 * <li>Class name ({@link ViewStructure#setClassName(String)}). 7465 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 7466 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 7467 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 7468 * opacity ({@link ViewStructure#setOpaque(boolean)}). 7469 * <li>For views representing text fields, text properties such as the text itself 7470 * ({@link ViewStructure#setText(CharSequence)}), text hints 7471 * ({@link ViewStructure#setHint(CharSequence)}, input type 7472 * ({@link ViewStructure#setInputType(int)}), 7473 * <li>For views representing HTML nodes, its web domain 7474 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 7475 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 7476 * </ul> 7477 * 7478 * <p>The default implementation of this method already sets most of these properties based on 7479 * related {@link View} methods (for example, the autofill id is set using 7480 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 7481 * and views in the standard Android widgets library also override it to set their 7482 * relevant properties (for example, {@link android.widget.TextView} already sets the text 7483 * properties), so it's recommended to only override this method 7484 * (and call {@code super.onProvideAutofillStructure()}) when: 7485 * 7486 * <ul> 7487 * <li>The view contents does not include PII (Personally Identifiable Information), so it 7488 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 7489 * <li>The view can only be autofilled with predefined options, so it can call 7490 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 7491 * </ul> 7492 * 7493 * <p><b>Note:</b> The {@code left} and {@code top} values set in 7494 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 7495 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 7496 * 7497 * <p>Views support the Autofill Framework mainly by: 7498 * <ul> 7499 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7500 * <li>Notifying the Android System when the view value changed by calling 7501 * {@link AutofillManager#notifyValueChanged(View)}. 7502 * <li>Implementing the methods that autofill the view. 7503 * </ul> 7504 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 7505 * for the latter. 7506 * 7507 * @param structure fill in with structured view data for autofill purposes. 7508 * @param flags optional flags. 7509 * 7510 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7511 */ 7512 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 7513 onProvideStructureForAssistOrAutofill(structure, true, flags); 7514 } 7515 7516 private void onProvideStructureForAssistOrAutofill(ViewStructure structure, 7517 boolean forAutofill, @AutofillFlags int flags) { 7518 final int id = mID; 7519 if (id != NO_ID && !isViewIdGenerated(id)) { 7520 String pkg, type, entry; 7521 try { 7522 final Resources res = getResources(); 7523 entry = res.getResourceEntryName(id); 7524 type = res.getResourceTypeName(id); 7525 pkg = res.getResourcePackageName(id); 7526 } catch (Resources.NotFoundException e) { 7527 entry = type = pkg = null; 7528 } 7529 structure.setId(id, pkg, type, entry); 7530 } else { 7531 structure.setId(id, null, null, null); 7532 } 7533 7534 if (forAutofill) { 7535 final @AutofillType int autofillType = getAutofillType(); 7536 // Don't need to fill autofill info if view does not support it. 7537 // For example, only TextViews that are editable support autofill 7538 if (autofillType != AUTOFILL_TYPE_NONE) { 7539 structure.setAutofillType(autofillType); 7540 structure.setAutofillHints(getAutofillHints()); 7541 structure.setAutofillValue(getAutofillValue()); 7542 } 7543 } 7544 7545 int ignoredParentLeft = 0; 7546 int ignoredParentTop = 0; 7547 if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 7548 View parentGroup = null; 7549 7550 ViewParent viewParent = getParent(); 7551 if (viewParent instanceof View) { 7552 parentGroup = (View) viewParent; 7553 } 7554 7555 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 7556 ignoredParentLeft += parentGroup.mLeft; 7557 ignoredParentTop += parentGroup.mTop; 7558 7559 viewParent = parentGroup.getParent(); 7560 if (viewParent instanceof View) { 7561 parentGroup = (View) viewParent; 7562 } else { 7563 break; 7564 } 7565 } 7566 } 7567 7568 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 7569 mRight - mLeft, mBottom - mTop); 7570 if (!forAutofill) { 7571 if (!hasIdentityMatrix()) { 7572 structure.setTransformation(getMatrix()); 7573 } 7574 structure.setElevation(getZ()); 7575 } 7576 structure.setVisibility(getVisibility()); 7577 structure.setEnabled(isEnabled()); 7578 if (isClickable()) { 7579 structure.setClickable(true); 7580 } 7581 if (isFocusable()) { 7582 structure.setFocusable(true); 7583 } 7584 if (isFocused()) { 7585 structure.setFocused(true); 7586 } 7587 if (isAccessibilityFocused()) { 7588 structure.setAccessibilityFocused(true); 7589 } 7590 if (isSelected()) { 7591 structure.setSelected(true); 7592 } 7593 if (isActivated()) { 7594 structure.setActivated(true); 7595 } 7596 if (isLongClickable()) { 7597 structure.setLongClickable(true); 7598 } 7599 if (this instanceof Checkable) { 7600 structure.setCheckable(true); 7601 if (((Checkable)this).isChecked()) { 7602 structure.setChecked(true); 7603 } 7604 } 7605 if (isOpaque()) { 7606 structure.setOpaque(true); 7607 } 7608 if (isContextClickable()) { 7609 structure.setContextClickable(true); 7610 } 7611 structure.setClassName(getAccessibilityClassName().toString()); 7612 structure.setContentDescription(getContentDescription()); 7613 } 7614 7615 /** 7616 * Called when assist structure is being retrieved from a view as part of 7617 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 7618 * generate additional virtual structure under this view. The defaullt implementation 7619 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 7620 * view's virtual accessibility nodes, if any. You can override this for a more 7621 * optimal implementation providing this data. 7622 */ 7623 public void onProvideVirtualStructure(ViewStructure structure) { 7624 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 7625 if (provider != null) { 7626 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 7627 structure.setChildCount(1); 7628 ViewStructure root = structure.newChild(0); 7629 populateVirtualStructure(root, provider, info); 7630 info.recycle(); 7631 } 7632 } 7633 7634 /** 7635 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 7636 * request. 7637 * 7638 * <p>This method should be used when the view manages a virtual structure under this view. For 7639 * example, a view that draws input fields using {@link #draw(Canvas)}. 7640 * 7641 * <p>When implementing this method, subclasses must follow the rules below: 7642 * 7643 * <ul> 7644 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 7645 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 7646 * identifying the children in the virtual structure. 7647 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 7648 * exclude intermediate levels that are irrelevant for autofill; that would improve the 7649 * autofill performance. 7650 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 7651 * children. 7652 * <li>Set the autofill properties of the child structure as defined by 7653 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 7654 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 7655 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 7656 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 7657 * when the focused virtual child changed. 7658 * <li>Call 7659 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 7660 * when the value of a virtual child changed. 7661 * <li>Call 7662 * {@link 7663 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 7664 * when the visibility of a virtual child changed. 7665 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 7666 * changed and the current context should be committed (for example, when the user tapped 7667 * a {@code SUBMIT} button in an HTML page). 7668 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 7669 * changed and the current context should be canceled (for example, when the user tapped 7670 * a {@code CANCEL} button in an HTML page). 7671 * <li>Provide ways for users to manually request autofill by calling 7672 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 7673 * <li>The {@code left} and {@code top} values set in 7674 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 7675 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 7676 * structure. 7677 * </ul> 7678 * 7679 * <p>Views with virtual children support the Autofill Framework mainly by: 7680 * <ul> 7681 * <li>Providing the metadata defining what the virtual children mean and how they can be 7682 * autofilled. 7683 * <li>Implementing the methods that autofill the virtual children. 7684 * </ul> 7685 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 7686 * for the latter. 7687 * 7688 * @param structure fill in with virtual children data for autofill purposes. 7689 * @param flags optional flags. 7690 * 7691 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 7692 */ 7693 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 7694 } 7695 7696 /** 7697 * Automatically fills the content of this view with the {@code value}. 7698 * 7699 * <p>Views support the Autofill Framework mainly by: 7700 * <ul> 7701 * <li>Providing the metadata defining what the view means and how it can be autofilled. 7702 * <li>Implementing the methods that autofill the view. 7703 * </ul> 7704 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 7705 * this method is responsible for latter. 7706 * 7707 * <p>This method does nothing by default, but when overridden it typically: 7708 * <ol> 7709 * <li>Checks if the provided value matches the expected type (which is defined by 7710 * {@link #getAutofillType()}). 7711 * <li>Checks if the view is editable - if it isn't, it should return right away. 7712 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 7713 * <li>Pass the actual value to the equivalent setter in the view. 7714 * </ol> 7715 * 7716 * <p>For example, a text-field view could implement the method this way: 7717 * 7718 * <pre class="prettyprint"> 7719 * @Override 7720 * public void autofill(AutofillValue value) { 7721 * if (!value.isText() || !this.isEditable()) { 7722 * return; 7723 * } 7724 * CharSequence text = value.getTextValue(); 7725 * if (text != null) { 7726 * this.setText(text); 7727 * } 7728 * } 7729 * </pre> 7730 * 7731 * <p>If the value is updated asynchronously, the next call to 7732 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 7733 * changed to the autofilled value. If not, the view will not be considered autofilled. 7734 * 7735 * <p><b>Note:</b> After this method is called, the value returned by 7736 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 7737 * view will not be highlighted as autofilled. 7738 * 7739 * @param value value to be autofilled. 7740 */ 7741 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 7742 } 7743 7744 /** 7745 * Automatically fills the content of the virtual children within this view. 7746 * 7747 * <p>Views with virtual children support the Autofill Framework mainly by: 7748 * <ul> 7749 * <li>Providing the metadata defining what the virtual children mean and how they can be 7750 * autofilled. 7751 * <li>Implementing the methods that autofill the virtual children. 7752 * </ul> 7753 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 7754 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 7755 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 7756 * 7757 * <p>If a child value is updated asynchronously, the next call to 7758 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 7759 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 7760 * considered autofilled. 7761 * 7762 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 7763 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 7764 * changes. 7765 * 7766 * @param values map of values to be autofilled, keyed by virtual child id. 7767 * 7768 * @attr ref android.R.styleable#Theme_autofilledHighlight 7769 */ 7770 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 7771 } 7772 7773 /** 7774 * Gets the unique identifier of this view in the screen, for autofill purposes. 7775 * 7776 * @return The View's autofill id. 7777 */ 7778 public final AutofillId getAutofillId() { 7779 if (mAutofillId == null) { 7780 // The autofill id needs to be unique, but its value doesn't matter, 7781 // so it's better to reuse the accessibility id to save space. 7782 mAutofillId = new AutofillId(getAutofillViewId()); 7783 } 7784 return mAutofillId; 7785 } 7786 7787 /** 7788 * Describes the autofill type of this view, so an 7789 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 7790 * when autofilling the view. 7791 * 7792 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 7793 * support the Autofill Framework. 7794 * 7795 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 7796 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 7797 * 7798 * @see #onProvideAutofillStructure(ViewStructure, int) 7799 * @see #autofill(AutofillValue) 7800 */ 7801 public @AutofillType int getAutofillType() { 7802 return AUTOFILL_TYPE_NONE; 7803 } 7804 7805 /** 7806 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 7807 * to autofill the view with the user's data. 7808 * 7809 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 7810 * 7811 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 7812 * {@code null} if no hints were set. 7813 * 7814 * @attr ref android.R.styleable#View_autofillHints 7815 */ 7816 @ViewDebug.ExportedProperty() 7817 @Nullable public String[] getAutofillHints() { 7818 return mAutofillHints; 7819 } 7820 7821 /** 7822 * @hide 7823 */ 7824 public boolean isAutofilled() { 7825 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 7826 } 7827 7828 /** 7829 * Gets the {@link View}'s current autofill value. 7830 * 7831 * <p>By default returns {@code null}, but subclasses should override it and return an 7832 * appropriate value to properly support the Autofill Framework. 7833 * 7834 * @see #onProvideAutofillStructure(ViewStructure, int) 7835 * @see #autofill(AutofillValue) 7836 */ 7837 @Nullable 7838 public AutofillValue getAutofillValue() { 7839 return null; 7840 } 7841 7842 /** 7843 * Gets the mode for determining whether this view is important for autofill. 7844 * 7845 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 7846 * info about this mode. 7847 * 7848 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 7849 * {@link #setImportantForAutofill(int)}. 7850 * 7851 * @attr ref android.R.styleable#View_importantForAutofill 7852 */ 7853 @ViewDebug.ExportedProperty(mapping = { 7854 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 7855 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 7856 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 7857 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 7858 to = "yesExcludeDescendants"), 7859 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 7860 to = "noExcludeDescendants")}) 7861 public @AutofillImportance int getImportantForAutofill() { 7862 return (mPrivateFlags3 7863 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 7864 } 7865 7866 /** 7867 * Sets the mode for determining whether this view is considered important for autofill. 7868 * 7869 * <p>The platform determines the importance for autofill automatically but you 7870 * can use this method to customize the behavior. For example: 7871 * 7872 * <ol> 7873 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 7874 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 7875 * <li>When both the view and its children are irrelevant for autofill (for example, the root 7876 * view of an activity containing a spreadhseet editor), it should be 7877 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7878 * <li>When the view content is relevant for autofill but its children aren't (for example, 7879 * a credit card expiration date represented by a custom view that overrides the proper 7880 * autofill methods and has 2 children representing the month and year), it should 7881 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 7882 * </ol> 7883 * 7884 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7885 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 7886 * children) will be always be considered not important; for example, when the user explicitly 7887 * makes an autofill request, all views are considered important. See 7888 * {@link #isImportantForAutofill()} for more details about how the View's importance for 7889 * autofill is used. 7890 * 7891 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 7892 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 7893 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 7894 * 7895 * @attr ref android.R.styleable#View_importantForAutofill 7896 */ 7897 public void setImportantForAutofill(@AutofillImportance int mode) { 7898 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7899 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 7900 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 7901 } 7902 7903 /** 7904 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 7905 * associated with this view is considered important for autofill purposes. 7906 * 7907 * <p>Generally speaking, a view is important for autofill if: 7908 * <ol> 7909 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 7910 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 7911 * determine how other views can be autofilled. 7912 * <ol> 7913 * 7914 * <p>For example, view containers should typically return {@code false} for performance reasons 7915 * (since the important info is provided by their children), but if its properties have relevant 7916 * information (for example, a resource id called {@code credentials}, it should return 7917 * {@code true}. On the other hand, views representing labels or editable fields should 7918 * typically return {@code true}, but in some cases they could return {@code false} 7919 * (for example, if they're part of a "Captcha" mechanism). 7920 * 7921 * <p>The value returned by this method depends on the value returned by 7922 * {@link #getImportantForAutofill()}: 7923 * 7924 * <ol> 7925 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 7926 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 7927 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 7928 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 7929 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 7930 * that can return {@code true} in some cases (like a container with a resource id), 7931 * but {@code false} in most. 7932 * <li>otherwise, it returns {@code false}. 7933 * </ol> 7934 * 7935 * <p>When a view is considered important for autofill: 7936 * <ul> 7937 * <li>The view might automatically trigger an autofill request when focused on. 7938 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 7939 * request. 7940 * </ul> 7941 * 7942 * <p>On the other hand, when a view is considered not important for autofill: 7943 * <ul> 7944 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 7945 * request through {@link AutofillManager#requestAutofill(View)}. 7946 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 7947 * autofill request, unless the request has the 7948 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 7949 * </ul> 7950 * 7951 * @return whether the view is considered important for autofill. 7952 * 7953 * @see #setImportantForAutofill(int) 7954 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 7955 * @see #IMPORTANT_FOR_AUTOFILL_YES 7956 * @see #IMPORTANT_FOR_AUTOFILL_NO 7957 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7958 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7959 * @see AutofillManager#requestAutofill(View) 7960 */ 7961 public final boolean isImportantForAutofill() { 7962 // Check parent mode to ensure we're not hidden. 7963 ViewParent parent = mParent; 7964 while (parent instanceof View) { 7965 final int parentImportance = ((View) parent).getImportantForAutofill(); 7966 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7967 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 7968 return false; 7969 } 7970 parent = parent.getParent(); 7971 } 7972 7973 final int importance = getImportantForAutofill(); 7974 7975 // First, check the explicit states. 7976 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 7977 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 7978 return true; 7979 } 7980 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 7981 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 7982 return false; 7983 } 7984 7985 // Then use some heuristics to handle AUTO. 7986 7987 // Always include views that have an explicit resource id. 7988 final int id = mID; 7989 if (id != NO_ID && !isViewIdGenerated(id)) { 7990 final Resources res = getResources(); 7991 String entry = null; 7992 String pkg = null; 7993 try { 7994 entry = res.getResourceEntryName(id); 7995 pkg = res.getResourcePackageName(id); 7996 } catch (Resources.NotFoundException e) { 7997 // ignore 7998 } 7999 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 8000 return true; 8001 } 8002 } 8003 8004 // Otherwise, assume it's not important... 8005 return false; 8006 } 8007 8008 @Nullable 8009 private AutofillManager getAutofillManager() { 8010 return mContext.getSystemService(AutofillManager.class); 8011 } 8012 8013 private boolean isAutofillable() { 8014 return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill() 8015 && getAutofillViewId() > LAST_APP_AUTOFILL_ID; 8016 } 8017 8018 private void populateVirtualStructure(ViewStructure structure, 8019 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { 8020 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 8021 null, null, null); 8022 Rect rect = structure.getTempRect(); 8023 info.getBoundsInParent(rect); 8024 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 8025 structure.setVisibility(VISIBLE); 8026 structure.setEnabled(info.isEnabled()); 8027 if (info.isClickable()) { 8028 structure.setClickable(true); 8029 } 8030 if (info.isFocusable()) { 8031 structure.setFocusable(true); 8032 } 8033 if (info.isFocused()) { 8034 structure.setFocused(true); 8035 } 8036 if (info.isAccessibilityFocused()) { 8037 structure.setAccessibilityFocused(true); 8038 } 8039 if (info.isSelected()) { 8040 structure.setSelected(true); 8041 } 8042 if (info.isLongClickable()) { 8043 structure.setLongClickable(true); 8044 } 8045 if (info.isCheckable()) { 8046 structure.setCheckable(true); 8047 if (info.isChecked()) { 8048 structure.setChecked(true); 8049 } 8050 } 8051 if (info.isContextClickable()) { 8052 structure.setContextClickable(true); 8053 } 8054 CharSequence cname = info.getClassName(); 8055 structure.setClassName(cname != null ? cname.toString() : null); 8056 structure.setContentDescription(info.getContentDescription()); 8057 if ((info.getText() != null || info.getError() != null)) { 8058 structure.setText(info.getText(), info.getTextSelectionStart(), 8059 info.getTextSelectionEnd()); 8060 } 8061 final int NCHILDREN = info.getChildCount(); 8062 if (NCHILDREN > 0) { 8063 structure.setChildCount(NCHILDREN); 8064 for (int i=0; i<NCHILDREN; i++) { 8065 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 8066 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 8067 ViewStructure child = structure.newChild(i); 8068 populateVirtualStructure(child, provider, cinfo); 8069 cinfo.recycle(); 8070 } 8071 } 8072 } 8073 8074 /** 8075 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 8076 * implementation calls {@link #onProvideStructure} and 8077 * {@link #onProvideVirtualStructure}. 8078 */ 8079 public void dispatchProvideStructure(ViewStructure structure) { 8080 dispatchProvideStructureForAssistOrAutofill(structure, false, 0); 8081 } 8082 8083 /** 8084 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 8085 * when an Assist structure is being created as part of an autofill request. 8086 * 8087 * <p>The default implementation does the following: 8088 * <ul> 8089 * <li>Sets the {@link AutofillId} in the structure. 8090 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 8091 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 8092 * </ul> 8093 * 8094 * <p>Typically, this method should only be overridden by subclasses that provide a view 8095 * hierarchy (such as {@link ViewGroup}) - other classes should override 8096 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 8097 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 8098 * 8099 * <p>When overridden, it must: 8100 * 8101 * <ul> 8102 * <li>Either call 8103 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 8104 * set the {@link AutofillId} in the structure (for example, by calling 8105 * {@code structure.setAutofillId(getAutofillId())}). 8106 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 8107 * set, all views in the structure should be considered important for autofill, 8108 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 8109 * respect this flag to provide a better user experience - this flag is typically used 8110 * when an user explicitly requested autofill. If the flag is not set, 8111 * then only views marked as important for autofill should be included in the 8112 * structure - skipping non-important views optimizes the overall autofill performance. 8113 * </ul> 8114 * 8115 * @param structure fill in with structured view data for autofill purposes. 8116 * @param flags optional flags. 8117 * 8118 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8119 */ 8120 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 8121 @AutofillFlags int flags) { 8122 dispatchProvideStructureForAssistOrAutofill(structure, true, flags); 8123 } 8124 8125 private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure, 8126 boolean forAutofill, @AutofillFlags int flags) { 8127 if (forAutofill) { 8128 structure.setAutofillId(getAutofillId()); 8129 onProvideAutofillStructure(structure, flags); 8130 onProvideAutofillVirtualStructure(structure, flags); 8131 } else if (!isAssistBlocked()) { 8132 onProvideStructure(structure); 8133 onProvideVirtualStructure(structure); 8134 } else { 8135 structure.setClassName(getAccessibilityClassName().toString()); 8136 structure.setAssistBlocked(true); 8137 } 8138 } 8139 8140 /** 8141 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 8142 * 8143 * Note: Called from the default {@link AccessibilityDelegate}. 8144 * 8145 * @hide 8146 */ 8147 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 8148 if (mAttachInfo == null) { 8149 return; 8150 } 8151 8152 Rect bounds = mAttachInfo.mTmpInvalRect; 8153 8154 getDrawingRect(bounds); 8155 info.setBoundsInParent(bounds); 8156 8157 getBoundsOnScreen(bounds, true); 8158 info.setBoundsInScreen(bounds); 8159 8160 ViewParent parent = getParentForAccessibility(); 8161 if (parent instanceof View) { 8162 info.setParent((View) parent); 8163 } 8164 8165 if (mID != View.NO_ID) { 8166 View rootView = getRootView(); 8167 if (rootView == null) { 8168 rootView = this; 8169 } 8170 8171 View label = rootView.findLabelForView(this, mID); 8172 if (label != null) { 8173 info.setLabeledBy(label); 8174 } 8175 8176 if ((mAttachInfo.mAccessibilityFetchFlags 8177 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 8178 && Resources.resourceHasPackage(mID)) { 8179 try { 8180 String viewId = getResources().getResourceName(mID); 8181 info.setViewIdResourceName(viewId); 8182 } catch (Resources.NotFoundException nfe) { 8183 /* ignore */ 8184 } 8185 } 8186 } 8187 8188 if (mLabelForId != View.NO_ID) { 8189 View rootView = getRootView(); 8190 if (rootView == null) { 8191 rootView = this; 8192 } 8193 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 8194 if (labeled != null) { 8195 info.setLabelFor(labeled); 8196 } 8197 } 8198 8199 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 8200 View rootView = getRootView(); 8201 if (rootView == null) { 8202 rootView = this; 8203 } 8204 View next = rootView.findViewInsideOutShouldExist(this, 8205 mAccessibilityTraversalBeforeId); 8206 if (next != null && next.includeForAccessibility()) { 8207 info.setTraversalBefore(next); 8208 } 8209 } 8210 8211 if (mAccessibilityTraversalAfterId != View.NO_ID) { 8212 View rootView = getRootView(); 8213 if (rootView == null) { 8214 rootView = this; 8215 } 8216 View next = rootView.findViewInsideOutShouldExist(this, 8217 mAccessibilityTraversalAfterId); 8218 if (next != null && next.includeForAccessibility()) { 8219 info.setTraversalAfter(next); 8220 } 8221 } 8222 8223 info.setVisibleToUser(isVisibleToUser()); 8224 8225 info.setImportantForAccessibility(isImportantForAccessibility()); 8226 info.setPackageName(mContext.getPackageName()); 8227 info.setClassName(getAccessibilityClassName()); 8228 info.setContentDescription(getContentDescription()); 8229 8230 info.setEnabled(isEnabled()); 8231 info.setClickable(isClickable()); 8232 info.setFocusable(isFocusable()); 8233 info.setFocused(isFocused()); 8234 info.setAccessibilityFocused(isAccessibilityFocused()); 8235 info.setSelected(isSelected()); 8236 info.setLongClickable(isLongClickable()); 8237 info.setContextClickable(isContextClickable()); 8238 info.setLiveRegion(getAccessibilityLiveRegion()); 8239 8240 // TODO: These make sense only if we are in an AdapterView but all 8241 // views can be selected. Maybe from accessibility perspective 8242 // we should report as selectable view in an AdapterView. 8243 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 8244 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 8245 8246 if (isFocusable()) { 8247 if (isFocused()) { 8248 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 8249 } else { 8250 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 8251 } 8252 } 8253 8254 if (!isAccessibilityFocused()) { 8255 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 8256 } else { 8257 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 8258 } 8259 8260 if (isClickable() && isEnabled()) { 8261 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 8262 } 8263 8264 if (isLongClickable() && isEnabled()) { 8265 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 8266 } 8267 8268 if (isContextClickable() && isEnabled()) { 8269 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 8270 } 8271 8272 CharSequence text = getIterableTextForAccessibility(); 8273 if (text != null && text.length() > 0) { 8274 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 8275 8276 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 8277 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 8278 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 8279 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 8280 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 8281 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 8282 } 8283 8284 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 8285 populateAccessibilityNodeInfoDrawingOrderInParent(info); 8286 } 8287 8288 /** 8289 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 8290 * additional data. 8291 * <p> 8292 * This method only needs overloading if the node is marked as having extra data available. 8293 * </p> 8294 * 8295 * @param info The info to which to add the extra data. Never {@code null}. 8296 * @param extraDataKey A key specifying the type of extra data to add to the info. The 8297 * extra data should be added to the {@link Bundle} returned by 8298 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 8299 * {@code null}. 8300 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 8301 * {@code null} if the service provided no arguments. 8302 * 8303 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 8304 */ 8305 public void addExtraDataToAccessibilityNodeInfo( 8306 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 8307 @Nullable Bundle arguments) { 8308 } 8309 8310 /** 8311 * Determine the order in which this view will be drawn relative to its siblings for a11y 8312 * 8313 * @param info The info whose drawing order should be populated 8314 */ 8315 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 8316 /* 8317 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 8318 * drawing order may not be well-defined, and some Views with custom drawing order may 8319 * not be initialized sufficiently to respond properly getChildDrawingOrder. 8320 */ 8321 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 8322 info.setDrawingOrder(0); 8323 return; 8324 } 8325 int drawingOrderInParent = 1; 8326 // Iterate up the hierarchy if parents are not important for a11y 8327 View viewAtDrawingLevel = this; 8328 final ViewParent parent = getParentForAccessibility(); 8329 while (viewAtDrawingLevel != parent) { 8330 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 8331 if (!(currentParent instanceof ViewGroup)) { 8332 // Should only happen for the Decor 8333 drawingOrderInParent = 0; 8334 break; 8335 } else { 8336 final ViewGroup parentGroup = (ViewGroup) currentParent; 8337 final int childCount = parentGroup.getChildCount(); 8338 if (childCount > 1) { 8339 List<View> preorderedList = parentGroup.buildOrderedChildList(); 8340 if (preorderedList != null) { 8341 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 8342 for (int i = 0; i < childDrawIndex; i++) { 8343 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 8344 } 8345 } else { 8346 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 8347 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 8348 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 8349 .getChildDrawingOrder(childCount, childIndex) : childIndex; 8350 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 8351 if (childDrawIndex != 0) { 8352 for (int i = 0; i < numChildrenToIterate; i++) { 8353 final int otherDrawIndex = (customOrder ? 8354 parentGroup.getChildDrawingOrder(childCount, i) : i); 8355 if (otherDrawIndex < childDrawIndex) { 8356 drawingOrderInParent += 8357 numViewsForAccessibility(parentGroup.getChildAt(i)); 8358 } 8359 } 8360 } 8361 } 8362 } 8363 } 8364 viewAtDrawingLevel = (View) currentParent; 8365 } 8366 info.setDrawingOrder(drawingOrderInParent); 8367 } 8368 numViewsForAccessibility(View view)8369 private static int numViewsForAccessibility(View view) { 8370 if (view != null) { 8371 if (view.includeForAccessibility()) { 8372 return 1; 8373 } else if (view instanceof ViewGroup) { 8374 return ((ViewGroup) view).getNumChildrenForAccessibility(); 8375 } 8376 } 8377 return 0; 8378 } 8379 findLabelForView(View view, int labeledId)8380 private View findLabelForView(View view, int labeledId) { 8381 if (mMatchLabelForPredicate == null) { 8382 mMatchLabelForPredicate = new MatchLabelForPredicate(); 8383 } 8384 mMatchLabelForPredicate.mLabeledId = labeledId; 8385 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 8386 } 8387 8388 /** 8389 * Computes whether this view is visible to the user. Such a view is 8390 * attached, visible, all its predecessors are visible, it is not clipped 8391 * entirely by its predecessors, and has an alpha greater than zero. 8392 * 8393 * @return Whether the view is visible on the screen. 8394 * 8395 * @hide 8396 */ isVisibleToUser()8397 protected boolean isVisibleToUser() { 8398 return isVisibleToUser(null); 8399 } 8400 8401 /** 8402 * Computes whether the given portion of this view is visible to the user. 8403 * Such a view is attached, visible, all its predecessors are visible, 8404 * has an alpha greater than zero, and the specified portion is not 8405 * clipped entirely by its predecessors. 8406 * 8407 * @param boundInView the portion of the view to test; coordinates should be relative; may be 8408 * <code>null</code>, and the entire view will be tested in this case. 8409 * When <code>true</code> is returned by the function, the actual visible 8410 * region will be stored in this parameter; that is, if boundInView is fully 8411 * contained within the view, no modification will be made, otherwise regions 8412 * outside of the visible area of the view will be clipped. 8413 * 8414 * @return Whether the specified portion of the view is visible on the screen. 8415 * 8416 * @hide 8417 */ isVisibleToUser(Rect boundInView)8418 protected boolean isVisibleToUser(Rect boundInView) { 8419 if (mAttachInfo != null) { 8420 // Attached to invisible window means this view is not visible. 8421 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 8422 return false; 8423 } 8424 // An invisible predecessor or one with alpha zero means 8425 // that this view is not visible to the user. 8426 Object current = this; 8427 while (current instanceof View) { 8428 View view = (View) current; 8429 // We have attach info so this view is attached and there is no 8430 // need to check whether we reach to ViewRootImpl on the way up. 8431 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 8432 view.getVisibility() != VISIBLE) { 8433 return false; 8434 } 8435 current = view.mParent; 8436 } 8437 // Check if the view is entirely covered by its predecessors. 8438 Rect visibleRect = mAttachInfo.mTmpInvalRect; 8439 Point offset = mAttachInfo.mPoint; 8440 if (!getGlobalVisibleRect(visibleRect, offset)) { 8441 return false; 8442 } 8443 // Check if the visible portion intersects the rectangle of interest. 8444 if (boundInView != null) { 8445 visibleRect.offset(-offset.x, -offset.y); 8446 return boundInView.intersect(visibleRect); 8447 } 8448 return true; 8449 } 8450 return false; 8451 } 8452 8453 /** 8454 * Returns the delegate for implementing accessibility support via 8455 * composition. For more details see {@link AccessibilityDelegate}. 8456 * 8457 * @return The delegate, or null if none set. 8458 * 8459 * @hide 8460 */ getAccessibilityDelegate()8461 public AccessibilityDelegate getAccessibilityDelegate() { 8462 return mAccessibilityDelegate; 8463 } 8464 8465 /** 8466 * Sets a delegate for implementing accessibility support via composition 8467 * (as opposed to inheritance). For more details, see 8468 * {@link AccessibilityDelegate}. 8469 * <p> 8470 * <strong>Note:</strong> On platform versions prior to 8471 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 8472 * views in the {@code android.widget.*} package are called <i>before</i> 8473 * host methods. This prevents certain properties such as class name from 8474 * being modified by overriding 8475 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 8476 * as any changes will be overwritten by the host class. 8477 * <p> 8478 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 8479 * methods are called <i>after</i> host methods, which all properties to be 8480 * modified without being overwritten by the host class. 8481 * 8482 * @param delegate the object to which accessibility method calls should be 8483 * delegated 8484 * @see AccessibilityDelegate 8485 */ setAccessibilityDelegate(@ullable AccessibilityDelegate delegate)8486 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 8487 mAccessibilityDelegate = delegate; 8488 } 8489 8490 /** 8491 * Gets the provider for managing a virtual view hierarchy rooted at this View 8492 * and reported to {@link android.accessibilityservice.AccessibilityService}s 8493 * that explore the window content. 8494 * <p> 8495 * If this method returns an instance, this instance is responsible for managing 8496 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 8497 * View including the one representing the View itself. Similarly the returned 8498 * instance is responsible for performing accessibility actions on any virtual 8499 * view or the root view itself. 8500 * </p> 8501 * <p> 8502 * If an {@link AccessibilityDelegate} has been specified via calling 8503 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8504 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 8505 * is responsible for handling this call. 8506 * </p> 8507 * 8508 * @return The provider. 8509 * 8510 * @see AccessibilityNodeProvider 8511 */ getAccessibilityNodeProvider()8512 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 8513 if (mAccessibilityDelegate != null) { 8514 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 8515 } else { 8516 return null; 8517 } 8518 } 8519 8520 /** 8521 * Gets the unique identifier of this view on the screen for accessibility purposes. 8522 * 8523 * @return The view accessibility id. 8524 * 8525 * @hide 8526 */ getAccessibilityViewId()8527 public int getAccessibilityViewId() { 8528 if (mAccessibilityViewId == NO_ID) { 8529 mAccessibilityViewId = sNextAccessibilityViewId++; 8530 } 8531 return mAccessibilityViewId; 8532 } 8533 8534 /** 8535 * Gets the unique identifier of this view on the screen for autofill purposes. 8536 * 8537 * @return The view autofill id. 8538 * 8539 * @hide 8540 */ getAutofillViewId()8541 public int getAutofillViewId() { 8542 if (mAutofillViewId == NO_ID) { 8543 mAutofillViewId = mContext.getNextAutofillId(); 8544 } 8545 return mAutofillViewId; 8546 } 8547 8548 /** 8549 * Gets the unique identifier of the window in which this View reseides. 8550 * 8551 * @return The window accessibility id. 8552 * 8553 * @hide 8554 */ getAccessibilityWindowId()8555 public int getAccessibilityWindowId() { 8556 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 8557 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 8558 } 8559 8560 /** 8561 * Returns the {@link View}'s content description. 8562 * <p> 8563 * <strong>Note:</strong> Do not override this method, as it will have no 8564 * effect on the content description presented to accessibility services. 8565 * You must call {@link #setContentDescription(CharSequence)} to modify the 8566 * content description. 8567 * 8568 * @return the content description 8569 * @see #setContentDescription(CharSequence) 8570 * @attr ref android.R.styleable#View_contentDescription 8571 */ 8572 @ViewDebug.ExportedProperty(category = "accessibility") getContentDescription()8573 public CharSequence getContentDescription() { 8574 return mContentDescription; 8575 } 8576 8577 /** 8578 * Sets the {@link View}'s content description. 8579 * <p> 8580 * A content description briefly describes the view and is primarily used 8581 * for accessibility support to determine how a view should be presented to 8582 * the user. In the case of a view with no textual representation, such as 8583 * {@link android.widget.ImageButton}, a useful content description 8584 * explains what the view does. For example, an image button with a phone 8585 * icon that is used to place a call may use "Call" as its content 8586 * description. An image of a floppy disk that is used to save a file may 8587 * use "Save". 8588 * 8589 * @param contentDescription The content description. 8590 * @see #getContentDescription() 8591 * @attr ref android.R.styleable#View_contentDescription 8592 */ 8593 @RemotableViewMethod setContentDescription(CharSequence contentDescription)8594 public void setContentDescription(CharSequence contentDescription) { 8595 if (mContentDescription == null) { 8596 if (contentDescription == null) { 8597 return; 8598 } 8599 } else if (mContentDescription.equals(contentDescription)) { 8600 return; 8601 } 8602 mContentDescription = contentDescription; 8603 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 8604 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8605 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8606 notifySubtreeAccessibilityStateChangedIfNeeded(); 8607 } else { 8608 notifyViewAccessibilityStateChangedIfNeeded( 8609 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 8610 } 8611 } 8612 8613 /** 8614 * Sets the id of a view before which this one is visited in accessibility traversal. 8615 * A screen-reader must visit the content of this view before the content of the one 8616 * it precedes. For example, if view B is set to be before view A, then a screen-reader 8617 * will traverse the entire content of B before traversing the entire content of A, 8618 * regardles of what traversal strategy it is using. 8619 * <p> 8620 * Views that do not have specified before/after relationships are traversed in order 8621 * determined by the screen-reader. 8622 * </p> 8623 * <p> 8624 * Setting that this view is before a view that is not important for accessibility 8625 * or if this view is not important for accessibility will have no effect as the 8626 * screen-reader is not aware of unimportant views. 8627 * </p> 8628 * 8629 * @param beforeId The id of a view this one precedes in accessibility traversal. 8630 * 8631 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 8632 * 8633 * @see #setImportantForAccessibility(int) 8634 */ 8635 @RemotableViewMethod setAccessibilityTraversalBefore(int beforeId)8636 public void setAccessibilityTraversalBefore(int beforeId) { 8637 if (mAccessibilityTraversalBeforeId == beforeId) { 8638 return; 8639 } 8640 mAccessibilityTraversalBeforeId = beforeId; 8641 notifyViewAccessibilityStateChangedIfNeeded( 8642 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8643 } 8644 8645 /** 8646 * Gets the id of a view before which this one is visited in accessibility traversal. 8647 * 8648 * @return The id of a view this one precedes in accessibility traversal if 8649 * specified, otherwise {@link #NO_ID}. 8650 * 8651 * @see #setAccessibilityTraversalBefore(int) 8652 */ getAccessibilityTraversalBefore()8653 public int getAccessibilityTraversalBefore() { 8654 return mAccessibilityTraversalBeforeId; 8655 } 8656 8657 /** 8658 * Sets the id of a view after which this one is visited in accessibility traversal. 8659 * A screen-reader must visit the content of the other view before the content of this 8660 * one. For example, if view B is set to be after view A, then a screen-reader 8661 * will traverse the entire content of A before traversing the entire content of B, 8662 * regardles of what traversal strategy it is using. 8663 * <p> 8664 * Views that do not have specified before/after relationships are traversed in order 8665 * determined by the screen-reader. 8666 * </p> 8667 * <p> 8668 * Setting that this view is after a view that is not important for accessibility 8669 * or if this view is not important for accessibility will have no effect as the 8670 * screen-reader is not aware of unimportant views. 8671 * </p> 8672 * 8673 * @param afterId The id of a view this one succedees in accessibility traversal. 8674 * 8675 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 8676 * 8677 * @see #setImportantForAccessibility(int) 8678 */ 8679 @RemotableViewMethod setAccessibilityTraversalAfter(int afterId)8680 public void setAccessibilityTraversalAfter(int afterId) { 8681 if (mAccessibilityTraversalAfterId == afterId) { 8682 return; 8683 } 8684 mAccessibilityTraversalAfterId = afterId; 8685 notifyViewAccessibilityStateChangedIfNeeded( 8686 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8687 } 8688 8689 /** 8690 * Gets the id of a view after which this one is visited in accessibility traversal. 8691 * 8692 * @return The id of a view this one succeedes in accessibility traversal if 8693 * specified, otherwise {@link #NO_ID}. 8694 * 8695 * @see #setAccessibilityTraversalAfter(int) 8696 */ getAccessibilityTraversalAfter()8697 public int getAccessibilityTraversalAfter() { 8698 return mAccessibilityTraversalAfterId; 8699 } 8700 8701 /** 8702 * Gets the id of a view for which this view serves as a label for 8703 * accessibility purposes. 8704 * 8705 * @return The labeled view id. 8706 */ 8707 @ViewDebug.ExportedProperty(category = "accessibility") getLabelFor()8708 public int getLabelFor() { 8709 return mLabelForId; 8710 } 8711 8712 /** 8713 * Sets the id of a view for which this view serves as a label for 8714 * accessibility purposes. 8715 * 8716 * @param id The labeled view id. 8717 */ 8718 @RemotableViewMethod setLabelFor(@dRes int id)8719 public void setLabelFor(@IdRes int id) { 8720 if (mLabelForId == id) { 8721 return; 8722 } 8723 mLabelForId = id; 8724 if (mLabelForId != View.NO_ID 8725 && mID == View.NO_ID) { 8726 mID = generateViewId(); 8727 } 8728 notifyViewAccessibilityStateChangedIfNeeded( 8729 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8730 } 8731 8732 /** 8733 * Invoked whenever this view loses focus, either by losing window focus or by losing 8734 * focus within its window. This method can be used to clear any state tied to the 8735 * focus. For instance, if a button is held pressed with the trackball and the window 8736 * loses focus, this method can be used to cancel the press. 8737 * 8738 * Subclasses of View overriding this method should always call super.onFocusLost(). 8739 * 8740 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 8741 * @see #onWindowFocusChanged(boolean) 8742 * 8743 * @hide pending API council approval 8744 */ 8745 @CallSuper onFocusLost()8746 protected void onFocusLost() { 8747 resetPressedState(); 8748 } 8749 resetPressedState()8750 private void resetPressedState() { 8751 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 8752 return; 8753 } 8754 8755 if (isPressed()) { 8756 setPressed(false); 8757 8758 if (!mHasPerformedLongPress) { 8759 removeLongPressCallback(); 8760 } 8761 } 8762 } 8763 8764 /** 8765 * Returns true if this view has focus 8766 * 8767 * @return True if this view has focus, false otherwise. 8768 */ 8769 @ViewDebug.ExportedProperty(category = "focus") isFocused()8770 public boolean isFocused() { 8771 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8772 } 8773 8774 /** 8775 * Find the view in the hierarchy rooted at this view that currently has 8776 * focus. 8777 * 8778 * @return The view that currently has focus, or null if no focused view can 8779 * be found. 8780 */ findFocus()8781 public View findFocus() { 8782 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 8783 } 8784 8785 /** 8786 * Indicates whether this view is one of the set of scrollable containers in 8787 * its window. 8788 * 8789 * @return whether this view is one of the set of scrollable containers in 8790 * its window 8791 * 8792 * @attr ref android.R.styleable#View_isScrollContainer 8793 */ isScrollContainer()8794 public boolean isScrollContainer() { 8795 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 8796 } 8797 8798 /** 8799 * Change whether this view is one of the set of scrollable containers in 8800 * its window. This will be used to determine whether the window can 8801 * resize or must pan when a soft input area is open -- scrollable 8802 * containers allow the window to use resize mode since the container 8803 * will appropriately shrink. 8804 * 8805 * @attr ref android.R.styleable#View_isScrollContainer 8806 */ setScrollContainer(boolean isScrollContainer)8807 public void setScrollContainer(boolean isScrollContainer) { 8808 if (isScrollContainer) { 8809 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 8810 mAttachInfo.mScrollContainers.add(this); 8811 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 8812 } 8813 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 8814 } else { 8815 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 8816 mAttachInfo.mScrollContainers.remove(this); 8817 } 8818 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 8819 } 8820 } 8821 8822 /** 8823 * Returns the quality of the drawing cache. 8824 * 8825 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8826 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8827 * 8828 * @see #setDrawingCacheQuality(int) 8829 * @see #setDrawingCacheEnabled(boolean) 8830 * @see #isDrawingCacheEnabled() 8831 * 8832 * @attr ref android.R.styleable#View_drawingCacheQuality 8833 */ 8834 @DrawingCacheQuality getDrawingCacheQuality()8835 public int getDrawingCacheQuality() { 8836 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 8837 } 8838 8839 /** 8840 * Set the drawing cache quality of this view. This value is used only when the 8841 * drawing cache is enabled 8842 * 8843 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 8844 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 8845 * 8846 * @see #getDrawingCacheQuality() 8847 * @see #setDrawingCacheEnabled(boolean) 8848 * @see #isDrawingCacheEnabled() 8849 * 8850 * @attr ref android.R.styleable#View_drawingCacheQuality 8851 */ setDrawingCacheQuality(@rawingCacheQuality int quality)8852 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 8853 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 8854 } 8855 8856 /** 8857 * Returns whether the screen should remain on, corresponding to the current 8858 * value of {@link #KEEP_SCREEN_ON}. 8859 * 8860 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 8861 * 8862 * @see #setKeepScreenOn(boolean) 8863 * 8864 * @attr ref android.R.styleable#View_keepScreenOn 8865 */ getKeepScreenOn()8866 public boolean getKeepScreenOn() { 8867 return (mViewFlags & KEEP_SCREEN_ON) != 0; 8868 } 8869 8870 /** 8871 * Controls whether the screen should remain on, modifying the 8872 * value of {@link #KEEP_SCREEN_ON}. 8873 * 8874 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 8875 * 8876 * @see #getKeepScreenOn() 8877 * 8878 * @attr ref android.R.styleable#View_keepScreenOn 8879 */ setKeepScreenOn(boolean keepScreenOn)8880 public void setKeepScreenOn(boolean keepScreenOn) { 8881 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 8882 } 8883 8884 /** 8885 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8886 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8887 * 8888 * @attr ref android.R.styleable#View_nextFocusLeft 8889 */ getNextFocusLeftId()8890 public int getNextFocusLeftId() { 8891 return mNextFocusLeftId; 8892 } 8893 8894 /** 8895 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 8896 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 8897 * decide automatically. 8898 * 8899 * @attr ref android.R.styleable#View_nextFocusLeft 8900 */ setNextFocusLeftId(int nextFocusLeftId)8901 public void setNextFocusLeftId(int nextFocusLeftId) { 8902 mNextFocusLeftId = nextFocusLeftId; 8903 } 8904 8905 /** 8906 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8907 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8908 * 8909 * @attr ref android.R.styleable#View_nextFocusRight 8910 */ getNextFocusRightId()8911 public int getNextFocusRightId() { 8912 return mNextFocusRightId; 8913 } 8914 8915 /** 8916 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 8917 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 8918 * decide automatically. 8919 * 8920 * @attr ref android.R.styleable#View_nextFocusRight 8921 */ setNextFocusRightId(int nextFocusRightId)8922 public void setNextFocusRightId(int nextFocusRightId) { 8923 mNextFocusRightId = nextFocusRightId; 8924 } 8925 8926 /** 8927 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8928 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8929 * 8930 * @attr ref android.R.styleable#View_nextFocusUp 8931 */ getNextFocusUpId()8932 public int getNextFocusUpId() { 8933 return mNextFocusUpId; 8934 } 8935 8936 /** 8937 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 8938 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 8939 * decide automatically. 8940 * 8941 * @attr ref android.R.styleable#View_nextFocusUp 8942 */ setNextFocusUpId(int nextFocusUpId)8943 public void setNextFocusUpId(int nextFocusUpId) { 8944 mNextFocusUpId = nextFocusUpId; 8945 } 8946 8947 /** 8948 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8949 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8950 * 8951 * @attr ref android.R.styleable#View_nextFocusDown 8952 */ getNextFocusDownId()8953 public int getNextFocusDownId() { 8954 return mNextFocusDownId; 8955 } 8956 8957 /** 8958 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 8959 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 8960 * decide automatically. 8961 * 8962 * @attr ref android.R.styleable#View_nextFocusDown 8963 */ setNextFocusDownId(int nextFocusDownId)8964 public void setNextFocusDownId(int nextFocusDownId) { 8965 mNextFocusDownId = nextFocusDownId; 8966 } 8967 8968 /** 8969 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8970 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 8971 * 8972 * @attr ref android.R.styleable#View_nextFocusForward 8973 */ getNextFocusForwardId()8974 public int getNextFocusForwardId() { 8975 return mNextFocusForwardId; 8976 } 8977 8978 /** 8979 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 8980 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 8981 * decide automatically. 8982 * 8983 * @attr ref android.R.styleable#View_nextFocusForward 8984 */ setNextFocusForwardId(int nextFocusForwardId)8985 public void setNextFocusForwardId(int nextFocusForwardId) { 8986 mNextFocusForwardId = nextFocusForwardId; 8987 } 8988 8989 /** 8990 * Gets the id of the root of the next keyboard navigation cluster. 8991 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 8992 * decide automatically. 8993 * 8994 * @attr ref android.R.styleable#View_nextClusterForward 8995 */ getNextClusterForwardId()8996 public int getNextClusterForwardId() { 8997 return mNextClusterForwardId; 8998 } 8999 9000 /** 9001 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 9002 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 9003 * decide automatically. 9004 * 9005 * @attr ref android.R.styleable#View_nextClusterForward 9006 */ setNextClusterForwardId(int nextClusterForwardId)9007 public void setNextClusterForwardId(int nextClusterForwardId) { 9008 mNextClusterForwardId = nextClusterForwardId; 9009 } 9010 9011 /** 9012 * Returns the visibility of this view and all of its ancestors 9013 * 9014 * @return True if this view and all of its ancestors are {@link #VISIBLE} 9015 */ isShown()9016 public boolean isShown() { 9017 View current = this; 9018 //noinspection ConstantConditions 9019 do { 9020 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9021 return false; 9022 } 9023 ViewParent parent = current.mParent; 9024 if (parent == null) { 9025 return false; // We are not attached to the view root 9026 } 9027 if (!(parent instanceof View)) { 9028 return true; 9029 } 9030 current = (View) parent; 9031 } while (current != null); 9032 9033 return false; 9034 } 9035 9036 /** 9037 * Called by the view hierarchy when the content insets for a window have 9038 * changed, to allow it to adjust its content to fit within those windows. 9039 * The content insets tell you the space that the status bar, input method, 9040 * and other system windows infringe on the application's window. 9041 * 9042 * <p>You do not normally need to deal with this function, since the default 9043 * window decoration given to applications takes care of applying it to the 9044 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 9045 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 9046 * and your content can be placed under those system elements. You can then 9047 * use this method within your view hierarchy if you have parts of your UI 9048 * which you would like to ensure are not being covered. 9049 * 9050 * <p>The default implementation of this method simply applies the content 9051 * insets to the view's padding, consuming that content (modifying the 9052 * insets to be 0), and returning true. This behavior is off by default, but can 9053 * be enabled through {@link #setFitsSystemWindows(boolean)}. 9054 * 9055 * <p>This function's traversal down the hierarchy is depth-first. The same content 9056 * insets object is propagated down the hierarchy, so any changes made to it will 9057 * be seen by all following views (including potentially ones above in 9058 * the hierarchy since this is a depth-first traversal). The first view 9059 * that returns true will abort the entire traversal. 9060 * 9061 * <p>The default implementation works well for a situation where it is 9062 * used with a container that covers the entire window, allowing it to 9063 * apply the appropriate insets to its content on all edges. If you need 9064 * a more complicated layout (such as two different views fitting system 9065 * windows, one on the top of the window, and one on the bottom), 9066 * you can override the method and handle the insets however you would like. 9067 * Note that the insets provided by the framework are always relative to the 9068 * far edges of the window, not accounting for the location of the called view 9069 * within that window. (In fact when this method is called you do not yet know 9070 * where the layout will place the view, as it is done before layout happens.) 9071 * 9072 * <p>Note: unlike many View methods, there is no dispatch phase to this 9073 * call. If you are overriding it in a ViewGroup and want to allow the 9074 * call to continue to your children, you must be sure to call the super 9075 * implementation. 9076 * 9077 * <p>Here is a sample layout that makes use of fitting system windows 9078 * to have controls for a video view placed inside of the window decorations 9079 * that it hides and shows. This can be used with code like the second 9080 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 9081 * 9082 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 9083 * 9084 * @param insets Current content insets of the window. Prior to 9085 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 9086 * the insets or else you and Android will be unhappy. 9087 * 9088 * @return {@code true} if this view applied the insets and it should not 9089 * continue propagating further down the hierarchy, {@code false} otherwise. 9090 * @see #getFitsSystemWindows() 9091 * @see #setFitsSystemWindows(boolean) 9092 * @see #setSystemUiVisibility(int) 9093 * 9094 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 9095 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 9096 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 9097 * to implement handling their own insets. 9098 */ 9099 @Deprecated fitSystemWindows(Rect insets)9100 protected boolean fitSystemWindows(Rect insets) { 9101 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 9102 if (insets == null) { 9103 // Null insets by definition have already been consumed. 9104 // This call cannot apply insets since there are none to apply, 9105 // so return false. 9106 return false; 9107 } 9108 // If we're not in the process of dispatching the newer apply insets call, 9109 // that means we're not in the compatibility path. Dispatch into the newer 9110 // apply insets path and take things from there. 9111 try { 9112 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 9113 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 9114 } finally { 9115 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 9116 } 9117 } else { 9118 // We're being called from the newer apply insets path. 9119 // Perform the standard fallback behavior. 9120 return fitSystemWindowsInt(insets); 9121 } 9122 } 9123 fitSystemWindowsInt(Rect insets)9124 private boolean fitSystemWindowsInt(Rect insets) { 9125 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 9126 mUserPaddingStart = UNDEFINED_PADDING; 9127 mUserPaddingEnd = UNDEFINED_PADDING; 9128 Rect localInsets = sThreadLocal.get(); 9129 if (localInsets == null) { 9130 localInsets = new Rect(); 9131 sThreadLocal.set(localInsets); 9132 } 9133 boolean res = computeFitSystemWindows(insets, localInsets); 9134 mUserPaddingLeftInitial = localInsets.left; 9135 mUserPaddingRightInitial = localInsets.right; 9136 internalSetPadding(localInsets.left, localInsets.top, 9137 localInsets.right, localInsets.bottom); 9138 return res; 9139 } 9140 return false; 9141 } 9142 9143 /** 9144 * Called when the view should apply {@link WindowInsets} according to its internal policy. 9145 * 9146 * <p>This method should be overridden by views that wish to apply a policy different from or 9147 * in addition to the default behavior. Clients that wish to force a view subtree 9148 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 9149 * 9150 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 9151 * it will be called during dispatch instead of this method. The listener may optionally 9152 * call this method from its own implementation if it wishes to apply the view's default 9153 * insets policy in addition to its own.</p> 9154 * 9155 * <p>Implementations of this method should either return the insets parameter unchanged 9156 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 9157 * that this view applied itself. This allows new inset types added in future platform 9158 * versions to pass through existing implementations unchanged without being erroneously 9159 * consumed.</p> 9160 * 9161 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 9162 * property is set then the view will consume the system window insets and apply them 9163 * as padding for the view.</p> 9164 * 9165 * @param insets Insets to apply 9166 * @return The supplied insets with any applied insets consumed 9167 */ onApplyWindowInsets(WindowInsets insets)9168 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 9169 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 9170 // We weren't called from within a direct call to fitSystemWindows, 9171 // call into it as a fallback in case we're in a class that overrides it 9172 // and has logic to perform. 9173 if (fitSystemWindows(insets.getSystemWindowInsets())) { 9174 return insets.consumeSystemWindowInsets(); 9175 } 9176 } else { 9177 // We were called from within a direct call to fitSystemWindows. 9178 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 9179 return insets.consumeSystemWindowInsets(); 9180 } 9181 } 9182 return insets; 9183 } 9184 9185 /** 9186 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 9187 * window insets to this view. The listener's 9188 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 9189 * method will be called instead of the view's 9190 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 9191 * 9192 * @param listener Listener to set 9193 * 9194 * @see #onApplyWindowInsets(WindowInsets) 9195 */ setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)9196 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 9197 getListenerInfo().mOnApplyWindowInsetsListener = listener; 9198 } 9199 9200 /** 9201 * Request to apply the given window insets to this view or another view in its subtree. 9202 * 9203 * <p>This method should be called by clients wishing to apply insets corresponding to areas 9204 * obscured by window decorations or overlays. This can include the status and navigation bars, 9205 * action bars, input methods and more. New inset categories may be added in the future. 9206 * The method returns the insets provided minus any that were applied by this view or its 9207 * children.</p> 9208 * 9209 * <p>Clients wishing to provide custom behavior should override the 9210 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 9211 * {@link OnApplyWindowInsetsListener} via the 9212 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 9213 * method.</p> 9214 * 9215 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 9216 * </p> 9217 * 9218 * @param insets Insets to apply 9219 * @return The provided insets minus the insets that were consumed 9220 */ dispatchApplyWindowInsets(WindowInsets insets)9221 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 9222 try { 9223 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 9224 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 9225 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 9226 } else { 9227 return onApplyWindowInsets(insets); 9228 } 9229 } finally { 9230 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 9231 } 9232 } 9233 9234 /** 9235 * Compute the view's coordinate within the surface. 9236 * 9237 * <p>Computes the coordinates of this view in its surface. The argument 9238 * must be an array of two integers. After the method returns, the array 9239 * contains the x and y location in that order.</p> 9240 * @hide 9241 * @param location an array of two integers in which to hold the coordinates 9242 */ getLocationInSurface(@ize2) int[] location)9243 public void getLocationInSurface(@Size(2) int[] location) { 9244 getLocationInWindow(location); 9245 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 9246 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 9247 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 9248 } 9249 } 9250 9251 /** 9252 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 9253 * only available if the view is attached. 9254 * 9255 * @return WindowInsets from the top of the view hierarchy or null if View is detached 9256 */ getRootWindowInsets()9257 public WindowInsets getRootWindowInsets() { 9258 if (mAttachInfo != null) { 9259 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 9260 } 9261 return null; 9262 } 9263 9264 /** 9265 * @hide Compute the insets that should be consumed by this view and the ones 9266 * that should propagate to those under it. 9267 */ computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets)9268 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 9269 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9270 || mAttachInfo == null 9271 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 9272 && !mAttachInfo.mOverscanRequested)) { 9273 outLocalInsets.set(inoutInsets); 9274 inoutInsets.set(0, 0, 0, 0); 9275 return true; 9276 } else { 9277 // The application wants to take care of fitting system window for 9278 // the content... however we still need to take care of any overscan here. 9279 final Rect overscan = mAttachInfo.mOverscanInsets; 9280 outLocalInsets.set(overscan); 9281 inoutInsets.left -= overscan.left; 9282 inoutInsets.top -= overscan.top; 9283 inoutInsets.right -= overscan.right; 9284 inoutInsets.bottom -= overscan.bottom; 9285 return false; 9286 } 9287 } 9288 9289 /** 9290 * Compute insets that should be consumed by this view and the ones that should propagate 9291 * to those under it. 9292 * 9293 * @param in Insets currently being processed by this View, likely received as a parameter 9294 * to {@link #onApplyWindowInsets(WindowInsets)}. 9295 * @param outLocalInsets A Rect that will receive the insets that should be consumed 9296 * by this view 9297 * @return Insets that should be passed along to views under this one 9298 */ computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets)9299 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 9300 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 9301 || mAttachInfo == null 9302 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 9303 outLocalInsets.set(in.getSystemWindowInsets()); 9304 return in.consumeSystemWindowInsets(); 9305 } else { 9306 outLocalInsets.set(0, 0, 0, 0); 9307 return in; 9308 } 9309 } 9310 9311 /** 9312 * Sets whether or not this view should account for system screen decorations 9313 * such as the status bar and inset its content; that is, controlling whether 9314 * the default implementation of {@link #fitSystemWindows(Rect)} will be 9315 * executed. See that method for more details. 9316 * 9317 * <p>Note that if you are providing your own implementation of 9318 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 9319 * flag to true -- your implementation will be overriding the default 9320 * implementation that checks this flag. 9321 * 9322 * @param fitSystemWindows If true, then the default implementation of 9323 * {@link #fitSystemWindows(Rect)} will be executed. 9324 * 9325 * @attr ref android.R.styleable#View_fitsSystemWindows 9326 * @see #getFitsSystemWindows() 9327 * @see #fitSystemWindows(Rect) 9328 * @see #setSystemUiVisibility(int) 9329 */ setFitsSystemWindows(boolean fitSystemWindows)9330 public void setFitsSystemWindows(boolean fitSystemWindows) { 9331 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 9332 } 9333 9334 /** 9335 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 9336 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 9337 * will be executed. 9338 * 9339 * @return {@code true} if the default implementation of 9340 * {@link #fitSystemWindows(Rect)} will be executed. 9341 * 9342 * @attr ref android.R.styleable#View_fitsSystemWindows 9343 * @see #setFitsSystemWindows(boolean) 9344 * @see #fitSystemWindows(Rect) 9345 * @see #setSystemUiVisibility(int) 9346 */ 9347 @ViewDebug.ExportedProperty getFitsSystemWindows()9348 public boolean getFitsSystemWindows() { 9349 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 9350 } 9351 9352 /** @hide */ fitsSystemWindows()9353 public boolean fitsSystemWindows() { 9354 return getFitsSystemWindows(); 9355 } 9356 9357 /** 9358 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 9359 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 9360 */ 9361 @Deprecated requestFitSystemWindows()9362 public void requestFitSystemWindows() { 9363 if (mParent != null) { 9364 mParent.requestFitSystemWindows(); 9365 } 9366 } 9367 9368 /** 9369 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 9370 */ requestApplyInsets()9371 public void requestApplyInsets() { 9372 requestFitSystemWindows(); 9373 } 9374 9375 /** 9376 * For use by PhoneWindow to make its own system window fitting optional. 9377 * @hide 9378 */ makeOptionalFitsSystemWindows()9379 public void makeOptionalFitsSystemWindows() { 9380 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 9381 } 9382 9383 /** 9384 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 9385 * treat them as such. 9386 * @hide 9387 */ getOutsets(Rect outOutsetRect)9388 public void getOutsets(Rect outOutsetRect) { 9389 if (mAttachInfo != null) { 9390 outOutsetRect.set(mAttachInfo.mOutsets); 9391 } else { 9392 outOutsetRect.setEmpty(); 9393 } 9394 } 9395 9396 /** 9397 * Returns the visibility status for this view. 9398 * 9399 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9400 * @attr ref android.R.styleable#View_visibility 9401 */ 9402 @ViewDebug.ExportedProperty(mapping = { 9403 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 9404 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 9405 @ViewDebug.IntToString(from = GONE, to = "GONE") 9406 }) 9407 @Visibility getVisibility()9408 public int getVisibility() { 9409 return mViewFlags & VISIBILITY_MASK; 9410 } 9411 9412 /** 9413 * Set the visibility state of this view. 9414 * 9415 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9416 * @attr ref android.R.styleable#View_visibility 9417 */ 9418 @RemotableViewMethod setVisibility(@isibility int visibility)9419 public void setVisibility(@Visibility int visibility) { 9420 setFlags(visibility, VISIBILITY_MASK); 9421 } 9422 9423 /** 9424 * Returns the enabled status for this view. The interpretation of the 9425 * enabled state varies by subclass. 9426 * 9427 * @return True if this view is enabled, false otherwise. 9428 */ 9429 @ViewDebug.ExportedProperty isEnabled()9430 public boolean isEnabled() { 9431 return (mViewFlags & ENABLED_MASK) == ENABLED; 9432 } 9433 9434 /** 9435 * Set the enabled state of this view. The interpretation of the enabled 9436 * state varies by subclass. 9437 * 9438 * @param enabled True if this view is enabled, false otherwise. 9439 */ 9440 @RemotableViewMethod setEnabled(boolean enabled)9441 public void setEnabled(boolean enabled) { 9442 if (enabled == isEnabled()) return; 9443 9444 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 9445 9446 /* 9447 * The View most likely has to change its appearance, so refresh 9448 * the drawable state. 9449 */ 9450 refreshDrawableState(); 9451 9452 // Invalidate too, since the default behavior for views is to be 9453 // be drawn at 50% alpha rather than to change the drawable. 9454 invalidate(true); 9455 9456 if (!enabled) { 9457 cancelPendingInputEvents(); 9458 } 9459 } 9460 9461 /** 9462 * Set whether this view can receive the focus. 9463 * <p> 9464 * Setting this to false will also ensure that this view is not focusable 9465 * in touch mode. 9466 * 9467 * @param focusable If true, this view can receive the focus. 9468 * 9469 * @see #setFocusableInTouchMode(boolean) 9470 * @see #setFocusable(int) 9471 * @attr ref android.R.styleable#View_focusable 9472 */ setFocusable(boolean focusable)9473 public void setFocusable(boolean focusable) { 9474 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 9475 } 9476 9477 /** 9478 * Sets whether this view can receive focus. 9479 * <p> 9480 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 9481 * automatically based on the view's interactivity. This is the default. 9482 * <p> 9483 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 9484 * in touch mode. 9485 * 9486 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 9487 * or {@link #FOCUSABLE_AUTO}. 9488 * @see #setFocusableInTouchMode(boolean) 9489 * @attr ref android.R.styleable#View_focusable 9490 */ setFocusable(@ocusable int focusable)9491 public void setFocusable(@Focusable int focusable) { 9492 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 9493 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 9494 } 9495 setFlags(focusable, FOCUSABLE_MASK); 9496 } 9497 9498 /** 9499 * Set whether this view can receive focus while in touch mode. 9500 * 9501 * Setting this to true will also ensure that this view is focusable. 9502 * 9503 * @param focusableInTouchMode If true, this view can receive the focus while 9504 * in touch mode. 9505 * 9506 * @see #setFocusable(boolean) 9507 * @attr ref android.R.styleable#View_focusableInTouchMode 9508 */ setFocusableInTouchMode(boolean focusableInTouchMode)9509 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 9510 // Focusable in touch mode should always be set before the focusable flag 9511 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 9512 // which, in touch mode, will not successfully request focus on this view 9513 // because the focusable in touch mode flag is not set 9514 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 9515 9516 // Clear FOCUSABLE_AUTO if set. 9517 if (focusableInTouchMode) { 9518 // Clears FOCUSABLE_AUTO if set. 9519 setFlags(FOCUSABLE, FOCUSABLE_MASK); 9520 } 9521 } 9522 9523 /** 9524 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 9525 * to autofill the view with the user's data. 9526 * 9527 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 9528 * For example, if the application accepts either an username or email address to identify 9529 * an user. 9530 * 9531 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 9532 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 9533 * constants such as: 9534 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 9535 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 9536 * {@link #AUTOFILL_HINT_NAME}, 9537 * {@link #AUTOFILL_HINT_PHONE}, 9538 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 9539 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 9540 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 9541 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 9542 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 9543 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 9544 * 9545 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 9546 * @attr ref android.R.styleable#View_autofillHints 9547 */ setAutofillHints(@ullable String... autofillHints)9548 public void setAutofillHints(@Nullable String... autofillHints) { 9549 if (autofillHints == null || autofillHints.length == 0) { 9550 mAutofillHints = null; 9551 } else { 9552 mAutofillHints = autofillHints; 9553 } 9554 } 9555 9556 /** 9557 * @hide 9558 */ 9559 @TestApi setAutofilled(boolean isAutofilled)9560 public void setAutofilled(boolean isAutofilled) { 9561 boolean wasChanged = isAutofilled != isAutofilled(); 9562 9563 if (wasChanged) { 9564 if (isAutofilled) { 9565 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 9566 } else { 9567 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 9568 } 9569 9570 invalidate(); 9571 } 9572 } 9573 9574 /** 9575 * Set whether this view should have sound effects enabled for events such as 9576 * clicking and touching. 9577 * 9578 * <p>You may wish to disable sound effects for a view if you already play sounds, 9579 * for instance, a dial key that plays dtmf tones. 9580 * 9581 * @param soundEffectsEnabled whether sound effects are enabled for this view. 9582 * @see #isSoundEffectsEnabled() 9583 * @see #playSoundEffect(int) 9584 * @attr ref android.R.styleable#View_soundEffectsEnabled 9585 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)9586 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 9587 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 9588 } 9589 9590 /** 9591 * @return whether this view should have sound effects enabled for events such as 9592 * clicking and touching. 9593 * 9594 * @see #setSoundEffectsEnabled(boolean) 9595 * @see #playSoundEffect(int) 9596 * @attr ref android.R.styleable#View_soundEffectsEnabled 9597 */ 9598 @ViewDebug.ExportedProperty isSoundEffectsEnabled()9599 public boolean isSoundEffectsEnabled() { 9600 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 9601 } 9602 9603 /** 9604 * Set whether this view should have haptic feedback for events such as 9605 * long presses. 9606 * 9607 * <p>You may wish to disable haptic feedback if your view already controls 9608 * its own haptic feedback. 9609 * 9610 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 9611 * @see #isHapticFeedbackEnabled() 9612 * @see #performHapticFeedback(int) 9613 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9614 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)9615 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 9616 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 9617 } 9618 9619 /** 9620 * @return whether this view should have haptic feedback enabled for events 9621 * long presses. 9622 * 9623 * @see #setHapticFeedbackEnabled(boolean) 9624 * @see #performHapticFeedback(int) 9625 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 9626 */ 9627 @ViewDebug.ExportedProperty isHapticFeedbackEnabled()9628 public boolean isHapticFeedbackEnabled() { 9629 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 9630 } 9631 9632 /** 9633 * Returns the layout direction for this view. 9634 * 9635 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 9636 * {@link #LAYOUT_DIRECTION_RTL}, 9637 * {@link #LAYOUT_DIRECTION_INHERIT} or 9638 * {@link #LAYOUT_DIRECTION_LOCALE}. 9639 * 9640 * @attr ref android.R.styleable#View_layoutDirection 9641 * 9642 * @hide 9643 */ 9644 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9645 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 9646 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 9647 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 9648 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 9649 }) 9650 @LayoutDir getRawLayoutDirection()9651 public int getRawLayoutDirection() { 9652 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 9653 } 9654 9655 /** 9656 * Set the layout direction for this view. This will propagate a reset of layout direction 9657 * resolution to the view's children and resolve layout direction for this view. 9658 * 9659 * @param layoutDirection the layout direction to set. Should be one of: 9660 * 9661 * {@link #LAYOUT_DIRECTION_LTR}, 9662 * {@link #LAYOUT_DIRECTION_RTL}, 9663 * {@link #LAYOUT_DIRECTION_INHERIT}, 9664 * {@link #LAYOUT_DIRECTION_LOCALE}. 9665 * 9666 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 9667 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 9668 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 9669 * 9670 * @attr ref android.R.styleable#View_layoutDirection 9671 */ 9672 @RemotableViewMethod setLayoutDirection(@ayoutDir int layoutDirection)9673 public void setLayoutDirection(@LayoutDir int layoutDirection) { 9674 if (getRawLayoutDirection() != layoutDirection) { 9675 // Reset the current layout direction and the resolved one 9676 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 9677 resetRtlProperties(); 9678 // Set the new layout direction (filtered) 9679 mPrivateFlags2 |= 9680 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 9681 // We need to resolve all RTL properties as they all depend on layout direction 9682 resolveRtlPropertiesIfNeeded(); 9683 requestLayout(); 9684 invalidate(true); 9685 } 9686 } 9687 9688 /** 9689 * Returns the resolved layout direction for this view. 9690 * 9691 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 9692 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 9693 * 9694 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 9695 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 9696 * 9697 * @attr ref android.R.styleable#View_layoutDirection 9698 */ 9699 @ViewDebug.ExportedProperty(category = "layout", mapping = { 9700 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 9701 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 9702 }) 9703 @ResolvedLayoutDir getLayoutDirection()9704 public int getLayoutDirection() { 9705 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 9706 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 9707 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 9708 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 9709 } 9710 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 9711 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 9712 } 9713 9714 /** 9715 * Indicates whether or not this view's layout is right-to-left. This is resolved from 9716 * layout attribute and/or the inherited value from the parent 9717 * 9718 * @return true if the layout is right-to-left. 9719 * 9720 * @hide 9721 */ 9722 @ViewDebug.ExportedProperty(category = "layout") isLayoutRtl()9723 public boolean isLayoutRtl() { 9724 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 9725 } 9726 9727 /** 9728 * Indicates whether the view is currently tracking transient state that the 9729 * app should not need to concern itself with saving and restoring, but that 9730 * the framework should take special note to preserve when possible. 9731 * 9732 * <p>A view with transient state cannot be trivially rebound from an external 9733 * data source, such as an adapter binding item views in a list. This may be 9734 * because the view is performing an animation, tracking user selection 9735 * of content, or similar.</p> 9736 * 9737 * @return true if the view has transient state 9738 */ 9739 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()9740 public boolean hasTransientState() { 9741 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 9742 } 9743 9744 /** 9745 * Set whether this view is currently tracking transient state that the 9746 * framework should attempt to preserve when possible. This flag is reference counted, 9747 * so every call to setHasTransientState(true) should be paired with a later call 9748 * to setHasTransientState(false). 9749 * 9750 * <p>A view with transient state cannot be trivially rebound from an external 9751 * data source, such as an adapter binding item views in a list. This may be 9752 * because the view is performing an animation, tracking user selection 9753 * of content, or similar.</p> 9754 * 9755 * @param hasTransientState true if this view has transient state 9756 */ setHasTransientState(boolean hasTransientState)9757 public void setHasTransientState(boolean hasTransientState) { 9758 final boolean oldHasTransientState = hasTransientState(); 9759 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 9760 mTransientStateCount - 1; 9761 if (mTransientStateCount < 0) { 9762 mTransientStateCount = 0; 9763 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 9764 "unmatched pair of setHasTransientState calls"); 9765 } else if ((hasTransientState && mTransientStateCount == 1) || 9766 (!hasTransientState && mTransientStateCount == 0)) { 9767 // update flag if we've just incremented up from 0 or decremented down to 0 9768 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 9769 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 9770 final boolean newHasTransientState = hasTransientState(); 9771 if (mParent != null && newHasTransientState != oldHasTransientState) { 9772 try { 9773 mParent.childHasTransientStateChanged(this, newHasTransientState); 9774 } catch (AbstractMethodError e) { 9775 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9776 " does not fully implement ViewParent", e); 9777 } 9778 } 9779 } 9780 } 9781 9782 /** 9783 * Returns true if this view is currently attached to a window. 9784 */ isAttachedToWindow()9785 public boolean isAttachedToWindow() { 9786 return mAttachInfo != null; 9787 } 9788 9789 /** 9790 * Returns true if this view has been through at least one layout since it 9791 * was last attached to or detached from a window. 9792 */ isLaidOut()9793 public boolean isLaidOut() { 9794 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 9795 } 9796 9797 /** 9798 * If this view doesn't do any drawing on its own, set this flag to 9799 * allow further optimizations. By default, this flag is not set on 9800 * View, but could be set on some View subclasses such as ViewGroup. 9801 * 9802 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 9803 * you should clear this flag. 9804 * 9805 * @param willNotDraw whether or not this View draw on its own 9806 */ setWillNotDraw(boolean willNotDraw)9807 public void setWillNotDraw(boolean willNotDraw) { 9808 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 9809 } 9810 9811 /** 9812 * Returns whether or not this View draws on its own. 9813 * 9814 * @return true if this view has nothing to draw, false otherwise 9815 */ 9816 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()9817 public boolean willNotDraw() { 9818 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 9819 } 9820 9821 /** 9822 * When a View's drawing cache is enabled, drawing is redirected to an 9823 * offscreen bitmap. Some views, like an ImageView, must be able to 9824 * bypass this mechanism if they already draw a single bitmap, to avoid 9825 * unnecessary usage of the memory. 9826 * 9827 * @param willNotCacheDrawing true if this view does not cache its 9828 * drawing, false otherwise 9829 */ setWillNotCacheDrawing(boolean willNotCacheDrawing)9830 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 9831 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 9832 } 9833 9834 /** 9835 * Returns whether or not this View can cache its drawing or not. 9836 * 9837 * @return true if this view does not cache its drawing, false otherwise 9838 */ 9839 @ViewDebug.ExportedProperty(category = "drawing") willNotCacheDrawing()9840 public boolean willNotCacheDrawing() { 9841 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 9842 } 9843 9844 /** 9845 * Indicates whether this view reacts to click events or not. 9846 * 9847 * @return true if the view is clickable, false otherwise 9848 * 9849 * @see #setClickable(boolean) 9850 * @attr ref android.R.styleable#View_clickable 9851 */ 9852 @ViewDebug.ExportedProperty isClickable()9853 public boolean isClickable() { 9854 return (mViewFlags & CLICKABLE) == CLICKABLE; 9855 } 9856 9857 /** 9858 * Enables or disables click events for this view. When a view 9859 * is clickable it will change its state to "pressed" on every click. 9860 * Subclasses should set the view clickable to visually react to 9861 * user's clicks. 9862 * 9863 * @param clickable true to make the view clickable, false otherwise 9864 * 9865 * @see #isClickable() 9866 * @attr ref android.R.styleable#View_clickable 9867 */ setClickable(boolean clickable)9868 public void setClickable(boolean clickable) { 9869 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 9870 } 9871 9872 /** 9873 * Indicates whether this view reacts to long click events or not. 9874 * 9875 * @return true if the view is long clickable, false otherwise 9876 * 9877 * @see #setLongClickable(boolean) 9878 * @attr ref android.R.styleable#View_longClickable 9879 */ isLongClickable()9880 public boolean isLongClickable() { 9881 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 9882 } 9883 9884 /** 9885 * Enables or disables long click events for this view. When a view is long 9886 * clickable it reacts to the user holding down the button for a longer 9887 * duration than a tap. This event can either launch the listener or a 9888 * context menu. 9889 * 9890 * @param longClickable true to make the view long clickable, false otherwise 9891 * @see #isLongClickable() 9892 * @attr ref android.R.styleable#View_longClickable 9893 */ setLongClickable(boolean longClickable)9894 public void setLongClickable(boolean longClickable) { 9895 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 9896 } 9897 9898 /** 9899 * Indicates whether this view reacts to context clicks or not. 9900 * 9901 * @return true if the view is context clickable, false otherwise 9902 * @see #setContextClickable(boolean) 9903 * @attr ref android.R.styleable#View_contextClickable 9904 */ isContextClickable()9905 public boolean isContextClickable() { 9906 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 9907 } 9908 9909 /** 9910 * Enables or disables context clicking for this view. This event can launch the listener. 9911 * 9912 * @param contextClickable true to make the view react to a context click, false otherwise 9913 * @see #isContextClickable() 9914 * @attr ref android.R.styleable#View_contextClickable 9915 */ setContextClickable(boolean contextClickable)9916 public void setContextClickable(boolean contextClickable) { 9917 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 9918 } 9919 9920 /** 9921 * Sets the pressed state for this view and provides a touch coordinate for 9922 * animation hinting. 9923 * 9924 * @param pressed Pass true to set the View's internal state to "pressed", 9925 * or false to reverts the View's internal state from a 9926 * previously set "pressed" state. 9927 * @param x The x coordinate of the touch that caused the press 9928 * @param y The y coordinate of the touch that caused the press 9929 */ setPressed(boolean pressed, float x, float y)9930 private void setPressed(boolean pressed, float x, float y) { 9931 if (pressed) { 9932 drawableHotspotChanged(x, y); 9933 } 9934 9935 setPressed(pressed); 9936 } 9937 9938 /** 9939 * Sets the pressed state for this view. 9940 * 9941 * @see #isClickable() 9942 * @see #setClickable(boolean) 9943 * 9944 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 9945 * the View's internal state from a previously set "pressed" state. 9946 */ setPressed(boolean pressed)9947 public void setPressed(boolean pressed) { 9948 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 9949 9950 if (pressed) { 9951 mPrivateFlags |= PFLAG_PRESSED; 9952 } else { 9953 mPrivateFlags &= ~PFLAG_PRESSED; 9954 } 9955 9956 if (needsRefresh) { 9957 refreshDrawableState(); 9958 } 9959 dispatchSetPressed(pressed); 9960 } 9961 9962 /** 9963 * Dispatch setPressed to all of this View's children. 9964 * 9965 * @see #setPressed(boolean) 9966 * 9967 * @param pressed The new pressed state 9968 */ dispatchSetPressed(boolean pressed)9969 protected void dispatchSetPressed(boolean pressed) { 9970 } 9971 9972 /** 9973 * Indicates whether the view is currently in pressed state. Unless 9974 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 9975 * the pressed state. 9976 * 9977 * @see #setPressed(boolean) 9978 * @see #isClickable() 9979 * @see #setClickable(boolean) 9980 * 9981 * @return true if the view is currently pressed, false otherwise 9982 */ 9983 @ViewDebug.ExportedProperty isPressed()9984 public boolean isPressed() { 9985 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 9986 } 9987 9988 /** 9989 * @hide 9990 * Indicates whether this view will participate in data collection through 9991 * {@link ViewStructure}. If true, it will not provide any data 9992 * for itself or its children. If false, the normal data collection will be allowed. 9993 * 9994 * @return Returns false if assist data collection is not blocked, else true. 9995 * 9996 * @see #setAssistBlocked(boolean) 9997 * @attr ref android.R.styleable#View_assistBlocked 9998 */ isAssistBlocked()9999 public boolean isAssistBlocked() { 10000 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 10001 } 10002 10003 /** 10004 * @hide 10005 * Controls whether assist data collection from this view and its children is enabled 10006 * (that is, whether {@link #onProvideStructure} and 10007 * {@link #onProvideVirtualStructure} will be called). The default value is false, 10008 * allowing normal assist collection. Setting this to false will disable assist collection. 10009 * 10010 * @param enabled Set to true to <em>disable</em> assist data collection, or false 10011 * (the default) to allow it. 10012 * 10013 * @see #isAssistBlocked() 10014 * @see #onProvideStructure 10015 * @see #onProvideVirtualStructure 10016 * @attr ref android.R.styleable#View_assistBlocked 10017 */ setAssistBlocked(boolean enabled)10018 public void setAssistBlocked(boolean enabled) { 10019 if (enabled) { 10020 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 10021 } else { 10022 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 10023 } 10024 } 10025 10026 /** 10027 * Indicates whether this view will save its state (that is, 10028 * whether its {@link #onSaveInstanceState} method will be called). 10029 * 10030 * @return Returns true if the view state saving is enabled, else false. 10031 * 10032 * @see #setSaveEnabled(boolean) 10033 * @attr ref android.R.styleable#View_saveEnabled 10034 */ isSaveEnabled()10035 public boolean isSaveEnabled() { 10036 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 10037 } 10038 10039 /** 10040 * Controls whether the saving of this view's state is 10041 * enabled (that is, whether its {@link #onSaveInstanceState} method 10042 * will be called). Note that even if freezing is enabled, the 10043 * view still must have an id assigned to it (via {@link #setId(int)}) 10044 * for its state to be saved. This flag can only disable the 10045 * saving of this view; any child views may still have their state saved. 10046 * 10047 * @param enabled Set to false to <em>disable</em> state saving, or true 10048 * (the default) to allow it. 10049 * 10050 * @see #isSaveEnabled() 10051 * @see #setId(int) 10052 * @see #onSaveInstanceState() 10053 * @attr ref android.R.styleable#View_saveEnabled 10054 */ setSaveEnabled(boolean enabled)10055 public void setSaveEnabled(boolean enabled) { 10056 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 10057 } 10058 10059 /** 10060 * Gets whether the framework should discard touches when the view's 10061 * window is obscured by another visible window. 10062 * Refer to the {@link View} security documentation for more details. 10063 * 10064 * @return True if touch filtering is enabled. 10065 * 10066 * @see #setFilterTouchesWhenObscured(boolean) 10067 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10068 */ 10069 @ViewDebug.ExportedProperty getFilterTouchesWhenObscured()10070 public boolean getFilterTouchesWhenObscured() { 10071 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 10072 } 10073 10074 /** 10075 * Sets whether the framework should discard touches when the view's 10076 * window is obscured by another visible window. 10077 * Refer to the {@link View} security documentation for more details. 10078 * 10079 * @param enabled True if touch filtering should be enabled. 10080 * 10081 * @see #getFilterTouchesWhenObscured 10082 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 10083 */ setFilterTouchesWhenObscured(boolean enabled)10084 public void setFilterTouchesWhenObscured(boolean enabled) { 10085 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 10086 FILTER_TOUCHES_WHEN_OBSCURED); 10087 } 10088 10089 /** 10090 * Indicates whether the entire hierarchy under this view will save its 10091 * state when a state saving traversal occurs from its parent. The default 10092 * is true; if false, these views will not be saved unless 10093 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10094 * 10095 * @return Returns true if the view state saving from parent is enabled, else false. 10096 * 10097 * @see #setSaveFromParentEnabled(boolean) 10098 */ isSaveFromParentEnabled()10099 public boolean isSaveFromParentEnabled() { 10100 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 10101 } 10102 10103 /** 10104 * Controls whether the entire hierarchy under this view will save its 10105 * state when a state saving traversal occurs from its parent. The default 10106 * is true; if false, these views will not be saved unless 10107 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 10108 * 10109 * @param enabled Set to false to <em>disable</em> state saving, or true 10110 * (the default) to allow it. 10111 * 10112 * @see #isSaveFromParentEnabled() 10113 * @see #setId(int) 10114 * @see #onSaveInstanceState() 10115 */ setSaveFromParentEnabled(boolean enabled)10116 public void setSaveFromParentEnabled(boolean enabled) { 10117 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 10118 } 10119 10120 10121 /** 10122 * Returns whether this View is currently able to take focus. 10123 * 10124 * @return True if this view can take focus, or false otherwise. 10125 */ 10126 @ViewDebug.ExportedProperty(category = "focus") isFocusable()10127 public final boolean isFocusable() { 10128 return FOCUSABLE == (mViewFlags & FOCUSABLE); 10129 } 10130 10131 /** 10132 * Returns the focusable setting for this view. 10133 * 10134 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 10135 * @attr ref android.R.styleable#View_focusable 10136 */ 10137 @ViewDebug.ExportedProperty(mapping = { 10138 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 10139 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 10140 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 10141 }, category = "focus") 10142 @Focusable getFocusable()10143 public int getFocusable() { 10144 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 10145 } 10146 10147 /** 10148 * When a view is focusable, it may not want to take focus when in touch mode. 10149 * For example, a button would like focus when the user is navigating via a D-pad 10150 * so that the user can click on it, but once the user starts touching the screen, 10151 * the button shouldn't take focus 10152 * @return Whether the view is focusable in touch mode. 10153 * @attr ref android.R.styleable#View_focusableInTouchMode 10154 */ 10155 @ViewDebug.ExportedProperty(category = "focus") isFocusableInTouchMode()10156 public final boolean isFocusableInTouchMode() { 10157 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 10158 } 10159 10160 /** 10161 * Find the nearest view in the specified direction that can take focus. 10162 * This does not actually give focus to that view. 10163 * 10164 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10165 * 10166 * @return The nearest focusable in the specified direction, or null if none 10167 * can be found. 10168 */ focusSearch(@ocusRealDirection int direction)10169 public View focusSearch(@FocusRealDirection int direction) { 10170 if (mParent != null) { 10171 return mParent.focusSearch(this, direction); 10172 } else { 10173 return null; 10174 } 10175 } 10176 10177 /** 10178 * Returns whether this View is a root of a keyboard navigation cluster. 10179 * 10180 * @return True if this view is a root of a cluster, or false otherwise. 10181 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10182 */ 10183 @ViewDebug.ExportedProperty(category = "focus") isKeyboardNavigationCluster()10184 public final boolean isKeyboardNavigationCluster() { 10185 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 10186 } 10187 10188 /** 10189 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 10190 * will be ignored. 10191 * 10192 * @return the keyboard navigation cluster that this view is in (can be this view) 10193 * or {@code null} if not in one 10194 */ findKeyboardNavigationCluster()10195 View findKeyboardNavigationCluster() { 10196 if (mParent instanceof View) { 10197 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 10198 if (cluster != null) { 10199 return cluster; 10200 } else if (isKeyboardNavigationCluster()) { 10201 return this; 10202 } 10203 } 10204 return null; 10205 } 10206 10207 /** 10208 * Set whether this view is a root of a keyboard navigation cluster. 10209 * 10210 * @param isCluster If true, this view is a root of a cluster. 10211 * 10212 * @attr ref android.R.styleable#View_keyboardNavigationCluster 10213 */ setKeyboardNavigationCluster(boolean isCluster)10214 public void setKeyboardNavigationCluster(boolean isCluster) { 10215 if (isCluster) { 10216 mPrivateFlags3 |= PFLAG3_CLUSTER; 10217 } else { 10218 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 10219 } 10220 } 10221 10222 /** 10223 * Sets this View as the one which receives focus the next time cluster navigation jumps 10224 * to the cluster containing this View. This does NOT change focus even if the cluster 10225 * containing this view is current. 10226 * 10227 * @hide 10228 */ 10229 @TestApi setFocusedInCluster()10230 public final void setFocusedInCluster() { 10231 setFocusedInCluster(findKeyboardNavigationCluster()); 10232 } 10233 setFocusedInCluster(View cluster)10234 private void setFocusedInCluster(View cluster) { 10235 if (this instanceof ViewGroup) { 10236 ((ViewGroup) this).mFocusedInCluster = null; 10237 } 10238 if (cluster == this) { 10239 return; 10240 } 10241 ViewParent parent = mParent; 10242 View child = this; 10243 while (parent instanceof ViewGroup) { 10244 ((ViewGroup) parent).mFocusedInCluster = child; 10245 if (parent == cluster) { 10246 break; 10247 } 10248 child = (View) parent; 10249 parent = parent.getParent(); 10250 } 10251 } 10252 updateFocusedInCluster(View oldFocus, @FocusDirection int direction)10253 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 10254 if (oldFocus != null) { 10255 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 10256 View cluster = findKeyboardNavigationCluster(); 10257 if (oldCluster != cluster) { 10258 // Going from one cluster to another, so save last-focused. 10259 // This covers cluster jumps because they are always FOCUS_DOWN 10260 oldFocus.setFocusedInCluster(oldCluster); 10261 if (!(oldFocus.mParent instanceof ViewGroup)) { 10262 return; 10263 } 10264 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 10265 // This is a result of ordered navigation so consider navigation through 10266 // the previous cluster "complete" and clear its last-focused memory. 10267 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10268 } else if (oldFocus instanceof ViewGroup 10269 && ((ViewGroup) oldFocus).getDescendantFocusability() 10270 == ViewGroup.FOCUS_AFTER_DESCENDANTS 10271 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 10272 // This means oldFocus is not focusable since it obviously has a focusable 10273 // child (this). Don't restore focus to it in the future. 10274 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 10275 } 10276 } 10277 } 10278 } 10279 10280 /** 10281 * Returns whether this View should receive focus when the focus is restored for the view 10282 * hierarchy containing this view. 10283 * <p> 10284 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10285 * window or serves as a target of cluster navigation. 10286 * 10287 * @see #restoreDefaultFocus() 10288 * 10289 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 10290 * @attr ref android.R.styleable#View_focusedByDefault 10291 */ 10292 @ViewDebug.ExportedProperty(category = "focus") isFocusedByDefault()10293 public final boolean isFocusedByDefault() { 10294 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 10295 } 10296 10297 /** 10298 * Sets whether this View should receive focus when the focus is restored for the view 10299 * hierarchy containing this view. 10300 * <p> 10301 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 10302 * window or serves as a target of cluster navigation. 10303 * 10304 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 10305 * {@code false} otherwise. 10306 * 10307 * @see #restoreDefaultFocus() 10308 * 10309 * @attr ref android.R.styleable#View_focusedByDefault 10310 */ setFocusedByDefault(boolean isFocusedByDefault)10311 public void setFocusedByDefault(boolean isFocusedByDefault) { 10312 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 10313 return; 10314 } 10315 10316 if (isFocusedByDefault) { 10317 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 10318 } else { 10319 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 10320 } 10321 10322 if (mParent instanceof ViewGroup) { 10323 if (isFocusedByDefault) { 10324 ((ViewGroup) mParent).setDefaultFocus(this); 10325 } else { 10326 ((ViewGroup) mParent).clearDefaultFocus(this); 10327 } 10328 } 10329 } 10330 10331 /** 10332 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 10333 * 10334 * @return {@code true} if this view has default focus, {@code false} otherwise 10335 */ hasDefaultFocus()10336 boolean hasDefaultFocus() { 10337 return isFocusedByDefault(); 10338 } 10339 10340 /** 10341 * Find the nearest keyboard navigation cluster in the specified direction. 10342 * This does not actually give focus to that cluster. 10343 * 10344 * @param currentCluster The starting point of the search. Null means the current cluster is not 10345 * found yet 10346 * @param direction Direction to look 10347 * 10348 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 10349 * can be found 10350 */ keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)10351 public View keyboardNavigationClusterSearch(View currentCluster, 10352 @FocusDirection int direction) { 10353 if (isKeyboardNavigationCluster()) { 10354 currentCluster = this; 10355 } 10356 if (isRootNamespace()) { 10357 // Root namespace means we should consider ourselves the top of the 10358 // tree for group searching; otherwise we could be group searching 10359 // into other tabs. see LocalActivityManager and TabHost for more info. 10360 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 10361 this, currentCluster, direction); 10362 } else if (mParent != null) { 10363 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 10364 } 10365 return null; 10366 } 10367 10368 /** 10369 * This method is the last chance for the focused view and its ancestors to 10370 * respond to an arrow key. This is called when the focused view did not 10371 * consume the key internally, nor could the view system find a new view in 10372 * the requested direction to give focus to. 10373 * 10374 * @param focused The currently focused view. 10375 * @param direction The direction focus wants to move. One of FOCUS_UP, 10376 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 10377 * @return True if the this view consumed this unhandled move. 10378 */ dispatchUnhandledMove(View focused, @FocusRealDirection int direction)10379 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 10380 return false; 10381 } 10382 10383 /** 10384 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 10385 * have {@link android.R.attr#state_focused} defined in its background. 10386 * 10387 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 10388 * highlight, {@code false} otherwise. 10389 * 10390 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10391 */ setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled)10392 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 10393 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 10394 } 10395 10396 /** 10397 10398 /** 10399 * Returns whether this View should use a default focus highlight when it gets focused but 10400 * doesn't have {@link android.R.attr#state_focused} defined in its background. 10401 * 10402 * @return True if this View should use a default focus highlight. 10403 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 10404 */ 10405 @ViewDebug.ExportedProperty(category = "focus") getDefaultFocusHighlightEnabled()10406 public final boolean getDefaultFocusHighlightEnabled() { 10407 return mDefaultFocusHighlightEnabled; 10408 } 10409 10410 /** 10411 * If a user manually specified the next view id for a particular direction, 10412 * use the root to look up the view. 10413 * @param root The root view of the hierarchy containing this view. 10414 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 10415 * or FOCUS_BACKWARD. 10416 * @return The user specified next view, or null if there is none. 10417 */ findUserSetNextFocus(View root, @FocusDirection int direction)10418 View findUserSetNextFocus(View root, @FocusDirection int direction) { 10419 switch (direction) { 10420 case FOCUS_LEFT: 10421 if (mNextFocusLeftId == View.NO_ID) return null; 10422 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 10423 case FOCUS_RIGHT: 10424 if (mNextFocusRightId == View.NO_ID) return null; 10425 return findViewInsideOutShouldExist(root, mNextFocusRightId); 10426 case FOCUS_UP: 10427 if (mNextFocusUpId == View.NO_ID) return null; 10428 return findViewInsideOutShouldExist(root, mNextFocusUpId); 10429 case FOCUS_DOWN: 10430 if (mNextFocusDownId == View.NO_ID) return null; 10431 return findViewInsideOutShouldExist(root, mNextFocusDownId); 10432 case FOCUS_FORWARD: 10433 if (mNextFocusForwardId == View.NO_ID) return null; 10434 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 10435 case FOCUS_BACKWARD: { 10436 if (mID == View.NO_ID) return null; 10437 final int id = mID; 10438 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 10439 @Override 10440 public boolean test(View t) { 10441 return t.mNextFocusForwardId == id; 10442 } 10443 }); 10444 } 10445 } 10446 return null; 10447 } 10448 10449 /** 10450 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 10451 * use the root to look up the view. 10452 * 10453 * @param root the root view of the hierarchy containing this view 10454 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 10455 * @return the user-specified next cluster, or {@code null} if there is none 10456 */ 10457 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 10458 switch (direction) { 10459 case FOCUS_FORWARD: 10460 if (mNextClusterForwardId == View.NO_ID) return null; 10461 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 10462 case FOCUS_BACKWARD: { 10463 if (mID == View.NO_ID) return null; 10464 final int id = mID; 10465 return root.findViewByPredicateInsideOut(this, 10466 (Predicate<View>) t -> t.mNextClusterForwardId == id); 10467 } 10468 } 10469 return null; 10470 } 10471 10472 private View findViewInsideOutShouldExist(View root, int id) { 10473 if (mMatchIdPredicate == null) { 10474 mMatchIdPredicate = new MatchIdPredicate(); 10475 } 10476 mMatchIdPredicate.mId = id; 10477 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 10478 if (result == null) { 10479 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 10480 } 10481 return result; 10482 } 10483 10484 /** 10485 * Find and return all focusable views that are descendants of this view, 10486 * possibly including this view if it is focusable itself. 10487 * 10488 * @param direction The direction of the focus 10489 * @return A list of focusable views 10490 */ 10491 public ArrayList<View> getFocusables(@FocusDirection int direction) { 10492 ArrayList<View> result = new ArrayList<View>(24); 10493 addFocusables(result, direction); 10494 return result; 10495 } 10496 10497 /** 10498 * Add any focusable views that are descendants of this view (possibly 10499 * including this view if it is focusable itself) to views. If we are in touch mode, 10500 * only add views that are also focusable in touch mode. 10501 * 10502 * @param views Focusable views found so far 10503 * @param direction The direction of the focus 10504 */ 10505 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 10506 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 10507 } 10508 10509 /** 10510 * Adds any focusable views that are descendants of this view (possibly 10511 * including this view if it is focusable itself) to views. This method 10512 * adds all focusable views regardless if we are in touch mode or 10513 * only views focusable in touch mode if we are in touch mode or 10514 * only views that can take accessibility focus if accessibility is enabled 10515 * depending on the focusable mode parameter. 10516 * 10517 * @param views Focusable views found so far or null if all we are interested is 10518 * the number of focusables. 10519 * @param direction The direction of the focus. 10520 * @param focusableMode The type of focusables to be added. 10521 * 10522 * @see #FOCUSABLES_ALL 10523 * @see #FOCUSABLES_TOUCH_MODE 10524 */ 10525 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 10526 @FocusableMode int focusableMode) { 10527 if (views == null) { 10528 return; 10529 } 10530 if (!isFocusable()) { 10531 return; 10532 } 10533 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 10534 && !isFocusableInTouchMode()) { 10535 return; 10536 } 10537 views.add(this); 10538 } 10539 10540 /** 10541 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 10542 * including this view if it is a cluster root itself) to views. 10543 * 10544 * @param views Keyboard navigation cluster roots found so far 10545 * @param direction Direction to look 10546 */ 10547 public void addKeyboardNavigationClusters( 10548 @NonNull Collection<View> views, 10549 int direction) { 10550 if (!isKeyboardNavigationCluster()) { 10551 return; 10552 } 10553 if (!hasFocusable()) { 10554 return; 10555 } 10556 views.add(this); 10557 } 10558 10559 /** 10560 * Finds the Views that contain given text. The containment is case insensitive. 10561 * The search is performed by either the text that the View renders or the content 10562 * description that describes the view for accessibility purposes and the view does 10563 * not render or both. Clients can specify how the search is to be performed via 10564 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 10565 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 10566 * 10567 * @param outViews The output list of matching Views. 10568 * @param searched The text to match against. 10569 * 10570 * @see #FIND_VIEWS_WITH_TEXT 10571 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 10572 * @see #setContentDescription(CharSequence) 10573 */ 10574 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 10575 @FindViewFlags int flags) { 10576 if (getAccessibilityNodeProvider() != null) { 10577 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 10578 outViews.add(this); 10579 } 10580 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 10581 && (searched != null && searched.length() > 0) 10582 && (mContentDescription != null && mContentDescription.length() > 0)) { 10583 String searchedLowerCase = searched.toString().toLowerCase(); 10584 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 10585 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 10586 outViews.add(this); 10587 } 10588 } 10589 } 10590 10591 /** 10592 * Find and return all touchable views that are descendants of this view, 10593 * possibly including this view if it is touchable itself. 10594 * 10595 * @return A list of touchable views 10596 */ 10597 public ArrayList<View> getTouchables() { 10598 ArrayList<View> result = new ArrayList<View>(); 10599 addTouchables(result); 10600 return result; 10601 } 10602 10603 /** 10604 * Add any touchable views that are descendants of this view (possibly 10605 * including this view if it is touchable itself) to views. 10606 * 10607 * @param views Touchable views found so far 10608 */ 10609 public void addTouchables(ArrayList<View> views) { 10610 final int viewFlags = mViewFlags; 10611 10612 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10613 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 10614 && (viewFlags & ENABLED_MASK) == ENABLED) { 10615 views.add(this); 10616 } 10617 } 10618 10619 /** 10620 * Returns whether this View is accessibility focused. 10621 * 10622 * @return True if this View is accessibility focused. 10623 */ 10624 public boolean isAccessibilityFocused() { 10625 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 10626 } 10627 10628 /** 10629 * Call this to try to give accessibility focus to this view. 10630 * 10631 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 10632 * returns false or the view is no visible or the view already has accessibility 10633 * focus. 10634 * 10635 * See also {@link #focusSearch(int)}, which is what you call to say that you 10636 * have focus, and you want your parent to look for the next one. 10637 * 10638 * @return Whether this view actually took accessibility focus. 10639 * 10640 * @hide 10641 */ 10642 public boolean requestAccessibilityFocus() { 10643 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 10644 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 10645 return false; 10646 } 10647 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10648 return false; 10649 } 10650 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 10651 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 10652 ViewRootImpl viewRootImpl = getViewRootImpl(); 10653 if (viewRootImpl != null) { 10654 viewRootImpl.setAccessibilityFocus(this, null); 10655 } 10656 invalidate(); 10657 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 10658 return true; 10659 } 10660 return false; 10661 } 10662 10663 /** 10664 * Call this to try to clear accessibility focus of this view. 10665 * 10666 * See also {@link #focusSearch(int)}, which is what you call to say that you 10667 * have focus, and you want your parent to look for the next one. 10668 * 10669 * @hide 10670 */ 10671 public void clearAccessibilityFocus() { 10672 clearAccessibilityFocusNoCallbacks(0); 10673 10674 // Clear the global reference of accessibility focus if this view or 10675 // any of its descendants had accessibility focus. This will NOT send 10676 // an event or update internal state if focus is cleared from a 10677 // descendant view, which may leave views in inconsistent states. 10678 final ViewRootImpl viewRootImpl = getViewRootImpl(); 10679 if (viewRootImpl != null) { 10680 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 10681 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 10682 viewRootImpl.setAccessibilityFocus(null, null); 10683 } 10684 } 10685 } 10686 10687 private void sendAccessibilityHoverEvent(int eventType) { 10688 // Since we are not delivering to a client accessibility events from not 10689 // important views (unless the clinet request that) we need to fire the 10690 // event from the deepest view exposed to the client. As a consequence if 10691 // the user crosses a not exposed view the client will see enter and exit 10692 // of the exposed predecessor followed by and enter and exit of that same 10693 // predecessor when entering and exiting the not exposed descendant. This 10694 // is fine since the client has a clear idea which view is hovered at the 10695 // price of a couple more events being sent. This is a simple and 10696 // working solution. 10697 View source = this; 10698 while (true) { 10699 if (source.includeForAccessibility()) { 10700 source.sendAccessibilityEvent(eventType); 10701 return; 10702 } 10703 ViewParent parent = source.getParent(); 10704 if (parent instanceof View) { 10705 source = (View) parent; 10706 } else { 10707 return; 10708 } 10709 } 10710 } 10711 10712 /** 10713 * Clears accessibility focus without calling any callback methods 10714 * normally invoked in {@link #clearAccessibilityFocus()}. This method 10715 * is used separately from that one for clearing accessibility focus when 10716 * giving this focus to another view. 10717 * 10718 * @param action The action, if any, that led to focus being cleared. Set to 10719 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 10720 * the window. 10721 */ 10722 void clearAccessibilityFocusNoCallbacks(int action) { 10723 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 10724 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 10725 invalidate(); 10726 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10727 AccessibilityEvent event = AccessibilityEvent.obtain( 10728 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 10729 event.setAction(action); 10730 if (mAccessibilityDelegate != null) { 10731 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 10732 } else { 10733 sendAccessibilityEventUnchecked(event); 10734 } 10735 } 10736 } 10737 } 10738 10739 /** 10740 * Call this to try to give focus to a specific view or to one of its 10741 * descendants. 10742 * 10743 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10744 * false), or if it is focusable and it is not focusable in touch mode 10745 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10746 * 10747 * See also {@link #focusSearch(int)}, which is what you call to say that you 10748 * have focus, and you want your parent to look for the next one. 10749 * 10750 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 10751 * {@link #FOCUS_DOWN} and <code>null</code>. 10752 * 10753 * @return Whether this view or one of its descendants actually took focus. 10754 */ 10755 public final boolean requestFocus() { 10756 return requestFocus(View.FOCUS_DOWN); 10757 } 10758 10759 /** 10760 * This will request focus for whichever View was last focused within this 10761 * cluster before a focus-jump out of it. 10762 * 10763 * @hide 10764 */ 10765 @TestApi 10766 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 10767 // Prioritize focusableByDefault over algorithmic focus selection. 10768 if (restoreDefaultFocus()) { 10769 return true; 10770 } 10771 return requestFocus(direction); 10772 } 10773 10774 /** 10775 * This will request focus for whichever View not in a cluster was last focused before a 10776 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 10777 * the "first" focusable view it finds. 10778 * 10779 * @hide 10780 */ 10781 @TestApi 10782 public boolean restoreFocusNotInCluster() { 10783 return requestFocus(View.FOCUS_DOWN); 10784 } 10785 10786 /** 10787 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 10788 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 10789 * 10790 * @return Whether this view or one of its descendants actually took focus 10791 */ 10792 public boolean restoreDefaultFocus() { 10793 return requestFocus(View.FOCUS_DOWN); 10794 } 10795 10796 /** 10797 * Call this to try to give focus to a specific view or to one of its 10798 * descendants and give it a hint about what direction focus is heading. 10799 * 10800 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10801 * false), or if it is focusable and it is not focusable in touch mode 10802 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10803 * 10804 * See also {@link #focusSearch(int)}, which is what you call to say that you 10805 * have focus, and you want your parent to look for the next one. 10806 * 10807 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 10808 * <code>null</code> set for the previously focused rectangle. 10809 * 10810 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10811 * @return Whether this view or one of its descendants actually took focus. 10812 */ 10813 public final boolean requestFocus(int direction) { 10814 return requestFocus(direction, null); 10815 } 10816 10817 /** 10818 * Call this to try to give focus to a specific view or to one of its descendants 10819 * and give it hints about the direction and a specific rectangle that the focus 10820 * is coming from. The rectangle can help give larger views a finer grained hint 10821 * about where focus is coming from, and therefore, where to show selection, or 10822 * forward focus change internally. 10823 * 10824 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 10825 * false), or if it is focusable and it is not focusable in touch mode 10826 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 10827 * 10828 * A View will not take focus if it is not visible. 10829 * 10830 * A View will not take focus if one of its parents has 10831 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 10832 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 10833 * 10834 * See also {@link #focusSearch(int)}, which is what you call to say that you 10835 * have focus, and you want your parent to look for the next one. 10836 * 10837 * You may wish to override this method if your custom {@link View} has an internal 10838 * {@link View} that it wishes to forward the request to. 10839 * 10840 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 10841 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 10842 * to give a finer grained hint about where focus is coming from. May be null 10843 * if there is no hint. 10844 * @return Whether this view or one of its descendants actually took focus. 10845 */ 10846 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 10847 return requestFocusNoSearch(direction, previouslyFocusedRect); 10848 } 10849 10850 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 10851 // need to be focusable 10852 if ((mViewFlags & FOCUSABLE) != FOCUSABLE 10853 || (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10854 return false; 10855 } 10856 10857 // need to be focusable in touch mode if in touch mode 10858 if (isInTouchMode() && 10859 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 10860 return false; 10861 } 10862 10863 // need to not have any parents blocking us 10864 if (hasAncestorThatBlocksDescendantFocus()) { 10865 return false; 10866 } 10867 10868 handleFocusGainInternal(direction, previouslyFocusedRect); 10869 return true; 10870 } 10871 10872 /** 10873 * Call this to try to give focus to a specific view or to one of its descendants. This is a 10874 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 10875 * touch mode to request focus when they are touched. 10876 * 10877 * @return Whether this view or one of its descendants actually took focus. 10878 * 10879 * @see #isInTouchMode() 10880 * 10881 */ 10882 public final boolean requestFocusFromTouch() { 10883 // Leave touch mode if we need to 10884 if (isInTouchMode()) { 10885 ViewRootImpl viewRoot = getViewRootImpl(); 10886 if (viewRoot != null) { 10887 viewRoot.ensureTouchMode(false); 10888 } 10889 } 10890 return requestFocus(View.FOCUS_DOWN); 10891 } 10892 10893 /** 10894 * @return Whether any ancestor of this view blocks descendant focus. 10895 */ 10896 private boolean hasAncestorThatBlocksDescendantFocus() { 10897 final boolean focusableInTouchMode = isFocusableInTouchMode(); 10898 ViewParent ancestor = mParent; 10899 while (ancestor instanceof ViewGroup) { 10900 final ViewGroup vgAncestor = (ViewGroup) ancestor; 10901 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 10902 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 10903 return true; 10904 } else { 10905 ancestor = vgAncestor.getParent(); 10906 } 10907 } 10908 return false; 10909 } 10910 10911 /** 10912 * Gets the mode for determining whether this View is important for accessibility. 10913 * A view is important for accessibility if it fires accessibility events and if it 10914 * is reported to accessibility services that query the screen. 10915 * 10916 * @return The mode for determining whether a view is important for accessibility, one 10917 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 10918 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 10919 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 10920 * 10921 * @attr ref android.R.styleable#View_importantForAccessibility 10922 * 10923 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 10924 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 10925 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 10926 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 10927 */ 10928 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 10929 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 10930 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 10931 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 10932 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 10933 to = "noHideDescendants") 10934 }) 10935 public int getImportantForAccessibility() { 10936 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 10937 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 10938 } 10939 10940 /** 10941 * Sets the live region mode for this view. This indicates to accessibility 10942 * services whether they should automatically notify the user about changes 10943 * to the view's content description or text, or to the content descriptions 10944 * or text of the view's children (where applicable). 10945 * <p> 10946 * For example, in a login screen with a TextView that displays an "incorrect 10947 * password" notification, that view should be marked as a live region with 10948 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10949 * <p> 10950 * To disable change notifications for this view, use 10951 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 10952 * mode for most views. 10953 * <p> 10954 * To indicate that the user should be notified of changes, use 10955 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 10956 * <p> 10957 * If the view's changes should interrupt ongoing speech and notify the user 10958 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 10959 * 10960 * @param mode The live region mode for this view, one of: 10961 * <ul> 10962 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 10963 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 10964 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 10965 * </ul> 10966 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10967 */ 10968 public void setAccessibilityLiveRegion(int mode) { 10969 if (mode != getAccessibilityLiveRegion()) { 10970 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10971 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 10972 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 10973 notifyViewAccessibilityStateChangedIfNeeded( 10974 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10975 } 10976 } 10977 10978 /** 10979 * Gets the live region mode for this View. 10980 * 10981 * @return The live region mode for the view. 10982 * 10983 * @attr ref android.R.styleable#View_accessibilityLiveRegion 10984 * 10985 * @see #setAccessibilityLiveRegion(int) 10986 */ 10987 public int getAccessibilityLiveRegion() { 10988 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 10989 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 10990 } 10991 10992 /** 10993 * Sets how to determine whether this view is important for accessibility 10994 * which is if it fires accessibility events and if it is reported to 10995 * accessibility services that query the screen. 10996 * 10997 * @param mode How to determine whether this view is important for accessibility. 10998 * 10999 * @attr ref android.R.styleable#View_importantForAccessibility 11000 * 11001 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 11002 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 11003 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 11004 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 11005 */ 11006 public void setImportantForAccessibility(int mode) { 11007 final int oldMode = getImportantForAccessibility(); 11008 if (mode != oldMode) { 11009 final boolean hideDescendants = 11010 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 11011 11012 // If this node or its descendants are no longer important, try to 11013 // clear accessibility focus. 11014 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 11015 final View focusHost = findAccessibilityFocusHost(hideDescendants); 11016 if (focusHost != null) { 11017 focusHost.clearAccessibilityFocus(); 11018 } 11019 } 11020 11021 // If we're moving between AUTO and another state, we might not need 11022 // to send a subtree changed notification. We'll store the computed 11023 // importance, since we'll need to check it later to make sure. 11024 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 11025 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 11026 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 11027 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 11028 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 11029 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 11030 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 11031 notifySubtreeAccessibilityStateChangedIfNeeded(); 11032 } else { 11033 notifyViewAccessibilityStateChangedIfNeeded( 11034 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11035 } 11036 } 11037 } 11038 11039 /** 11040 * Returns the view within this view's hierarchy that is hosting 11041 * accessibility focus. 11042 * 11043 * @param searchDescendants whether to search for focus in descendant views 11044 * @return the view hosting accessibility focus, or {@code null} 11045 */ 11046 private View findAccessibilityFocusHost(boolean searchDescendants) { 11047 if (isAccessibilityFocusedViewOrHost()) { 11048 return this; 11049 } 11050 11051 if (searchDescendants) { 11052 final ViewRootImpl viewRoot = getViewRootImpl(); 11053 if (viewRoot != null) { 11054 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 11055 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 11056 return focusHost; 11057 } 11058 } 11059 } 11060 11061 return null; 11062 } 11063 11064 /** 11065 * Computes whether this view should be exposed for accessibility. In 11066 * general, views that are interactive or provide information are exposed 11067 * while views that serve only as containers are hidden. 11068 * <p> 11069 * If an ancestor of this view has importance 11070 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 11071 * returns <code>false</code>. 11072 * <p> 11073 * Otherwise, the value is computed according to the view's 11074 * {@link #getImportantForAccessibility()} value: 11075 * <ol> 11076 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 11077 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 11078 * </code> 11079 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 11080 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 11081 * view satisfies any of the following: 11082 * <ul> 11083 * <li>Is actionable, e.g. {@link #isClickable()}, 11084 * {@link #isLongClickable()}, or {@link #isFocusable()} 11085 * <li>Has an {@link AccessibilityDelegate} 11086 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 11087 * {@link OnKeyListener}, etc. 11088 * <li>Is an accessibility live region, e.g. 11089 * {@link #getAccessibilityLiveRegion()} is not 11090 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 11091 * </ul> 11092 * </ol> 11093 * 11094 * @return Whether the view is exposed for accessibility. 11095 * @see #setImportantForAccessibility(int) 11096 * @see #getImportantForAccessibility() 11097 */ 11098 public boolean isImportantForAccessibility() { 11099 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 11100 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 11101 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 11102 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11103 return false; 11104 } 11105 11106 // Check parent mode to ensure we're not hidden. 11107 ViewParent parent = mParent; 11108 while (parent instanceof View) { 11109 if (((View) parent).getImportantForAccessibility() 11110 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 11111 return false; 11112 } 11113 parent = parent.getParent(); 11114 } 11115 11116 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 11117 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 11118 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 11119 } 11120 11121 /** 11122 * Gets the parent for accessibility purposes. Note that the parent for 11123 * accessibility is not necessary the immediate parent. It is the first 11124 * predecessor that is important for accessibility. 11125 * 11126 * @return The parent for accessibility purposes. 11127 */ 11128 public ViewParent getParentForAccessibility() { 11129 if (mParent instanceof View) { 11130 View parentView = (View) mParent; 11131 if (parentView.includeForAccessibility()) { 11132 return mParent; 11133 } else { 11134 return mParent.getParentForAccessibility(); 11135 } 11136 } 11137 return null; 11138 } 11139 11140 /** 11141 * Adds the children of this View relevant for accessibility to the given list 11142 * as output. Since some Views are not important for accessibility the added 11143 * child views are not necessarily direct children of this view, rather they are 11144 * the first level of descendants important for accessibility. 11145 * 11146 * @param outChildren The output list that will receive children for accessibility. 11147 */ 11148 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 11149 11150 } 11151 11152 /** 11153 * Whether to regard this view for accessibility. A view is regarded for 11154 * accessibility if it is important for accessibility or the querying 11155 * accessibility service has explicitly requested that view not 11156 * important for accessibility are regarded. 11157 * 11158 * @return Whether to regard the view for accessibility. 11159 * 11160 * @hide 11161 */ 11162 public boolean includeForAccessibility() { 11163 if (mAttachInfo != null) { 11164 return (mAttachInfo.mAccessibilityFetchFlags 11165 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 11166 || isImportantForAccessibility(); 11167 } 11168 return false; 11169 } 11170 11171 /** 11172 * Returns whether the View is considered actionable from 11173 * accessibility perspective. Such view are important for 11174 * accessibility. 11175 * 11176 * @return True if the view is actionable for accessibility. 11177 * 11178 * @hide 11179 */ 11180 public boolean isActionableForAccessibility() { 11181 return (isClickable() || isLongClickable() || isFocusable()); 11182 } 11183 11184 /** 11185 * Returns whether the View has registered callbacks which makes it 11186 * important for accessibility. 11187 * 11188 * @return True if the view is actionable for accessibility. 11189 */ 11190 private boolean hasListenersForAccessibility() { 11191 ListenerInfo info = getListenerInfo(); 11192 return mTouchDelegate != null || info.mOnKeyListener != null 11193 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 11194 || info.mOnHoverListener != null || info.mOnDragListener != null; 11195 } 11196 11197 /** 11198 * Notifies that the accessibility state of this view changed. The change 11199 * is local to this view and does not represent structural changes such 11200 * as children and parent. For example, the view became focusable. The 11201 * notification is at at most once every 11202 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11203 * to avoid unnecessary load to the system. Also once a view has a pending 11204 * notification this method is a NOP until the notification has been sent. 11205 * 11206 * @hide 11207 */ 11208 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 11209 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11210 return; 11211 } 11212 // If this is a live region, we should send a subtree change event 11213 // from this view immediately. Otherwise, we can let it propagate up. 11214 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 11215 final AccessibilityEvent event = AccessibilityEvent.obtain(); 11216 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11217 event.setContentChangeTypes(changeType); 11218 sendAccessibilityEventUnchecked(event); 11219 } else if (mParent != null) { 11220 try { 11221 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 11222 } catch (AbstractMethodError e) { 11223 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11224 " does not fully implement ViewParent", e); 11225 } 11226 } 11227 } 11228 11229 /** 11230 * Notifies that the accessibility state of this view changed. The change 11231 * is *not* local to this view and does represent structural changes such 11232 * as children and parent. For example, the view size changed. The 11233 * notification is at at most once every 11234 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 11235 * to avoid unnecessary load to the system. Also once a view has a pending 11236 * notification this method is a NOP until the notification has been sent. 11237 * 11238 * @hide 11239 */ 11240 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 11241 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 11242 return; 11243 } 11244 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 11245 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11246 if (mParent != null) { 11247 try { 11248 mParent.notifySubtreeAccessibilityStateChanged( 11249 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 11250 } catch (AbstractMethodError e) { 11251 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11252 " does not fully implement ViewParent", e); 11253 } 11254 } 11255 } 11256 } 11257 11258 /** 11259 * Change the visibility of the View without triggering any other changes. This is 11260 * important for transitions, where visibility changes should not adjust focus or 11261 * trigger a new layout. This is only used when the visibility has already been changed 11262 * and we need a transient value during an animation. When the animation completes, 11263 * the original visibility value is always restored. 11264 * 11265 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11266 * @hide 11267 */ 11268 public void setTransitionVisibility(@Visibility int visibility) { 11269 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 11270 } 11271 11272 /** 11273 * Reset the flag indicating the accessibility state of the subtree rooted 11274 * at this view changed. 11275 */ 11276 void resetSubtreeAccessibilityStateChanged() { 11277 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 11278 } 11279 11280 /** 11281 * Report an accessibility action to this view's parents for delegated processing. 11282 * 11283 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 11284 * call this method to delegate an accessibility action to a supporting parent. If the parent 11285 * returns true from its 11286 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 11287 * method this method will return true to signify that the action was consumed.</p> 11288 * 11289 * <p>This method is useful for implementing nested scrolling child views. If 11290 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 11291 * a custom view implementation may invoke this method to allow a parent to consume the 11292 * scroll first. If this method returns true the custom view should skip its own scrolling 11293 * behavior.</p> 11294 * 11295 * @param action Accessibility action to delegate 11296 * @param arguments Optional action arguments 11297 * @return true if the action was consumed by a parent 11298 */ 11299 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 11300 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 11301 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 11302 return true; 11303 } 11304 } 11305 return false; 11306 } 11307 11308 /** 11309 * Performs the specified accessibility action on the view. For 11310 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 11311 * <p> 11312 * If an {@link AccessibilityDelegate} has been specified via calling 11313 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11314 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 11315 * is responsible for handling this call. 11316 * </p> 11317 * 11318 * <p>The default implementation will delegate 11319 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 11320 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 11321 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 11322 * 11323 * @param action The action to perform. 11324 * @param arguments Optional action arguments. 11325 * @return Whether the action was performed. 11326 */ 11327 public boolean performAccessibilityAction(int action, Bundle arguments) { 11328 if (mAccessibilityDelegate != null) { 11329 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 11330 } else { 11331 return performAccessibilityActionInternal(action, arguments); 11332 } 11333 } 11334 11335 /** 11336 * @see #performAccessibilityAction(int, Bundle) 11337 * 11338 * Note: Called from the default {@link AccessibilityDelegate}. 11339 * 11340 * @hide 11341 */ 11342 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 11343 if (isNestedScrollingEnabled() 11344 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 11345 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 11346 || action == R.id.accessibilityActionScrollUp 11347 || action == R.id.accessibilityActionScrollLeft 11348 || action == R.id.accessibilityActionScrollDown 11349 || action == R.id.accessibilityActionScrollRight)) { 11350 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 11351 return true; 11352 } 11353 } 11354 11355 switch (action) { 11356 case AccessibilityNodeInfo.ACTION_CLICK: { 11357 if (isClickable()) { 11358 performClick(); 11359 return true; 11360 } 11361 } break; 11362 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 11363 if (isLongClickable()) { 11364 performLongClick(); 11365 return true; 11366 } 11367 } break; 11368 case AccessibilityNodeInfo.ACTION_FOCUS: { 11369 if (!hasFocus()) { 11370 // Get out of touch mode since accessibility 11371 // wants to move focus around. 11372 getViewRootImpl().ensureTouchMode(false); 11373 return requestFocus(); 11374 } 11375 } break; 11376 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 11377 if (hasFocus()) { 11378 clearFocus(); 11379 return !isFocused(); 11380 } 11381 } break; 11382 case AccessibilityNodeInfo.ACTION_SELECT: { 11383 if (!isSelected()) { 11384 setSelected(true); 11385 return isSelected(); 11386 } 11387 } break; 11388 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 11389 if (isSelected()) { 11390 setSelected(false); 11391 return !isSelected(); 11392 } 11393 } break; 11394 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 11395 if (!isAccessibilityFocused()) { 11396 return requestAccessibilityFocus(); 11397 } 11398 } break; 11399 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 11400 if (isAccessibilityFocused()) { 11401 clearAccessibilityFocus(); 11402 return true; 11403 } 11404 } break; 11405 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 11406 if (arguments != null) { 11407 final int granularity = arguments.getInt( 11408 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11409 final boolean extendSelection = arguments.getBoolean( 11410 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11411 return traverseAtGranularity(granularity, true, extendSelection); 11412 } 11413 } break; 11414 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 11415 if (arguments != null) { 11416 final int granularity = arguments.getInt( 11417 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 11418 final boolean extendSelection = arguments.getBoolean( 11419 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 11420 return traverseAtGranularity(granularity, false, extendSelection); 11421 } 11422 } break; 11423 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 11424 CharSequence text = getIterableTextForAccessibility(); 11425 if (text == null) { 11426 return false; 11427 } 11428 final int start = (arguments != null) ? arguments.getInt( 11429 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 11430 final int end = (arguments != null) ? arguments.getInt( 11431 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 11432 // Only cursor position can be specified (selection length == 0) 11433 if ((getAccessibilitySelectionStart() != start 11434 || getAccessibilitySelectionEnd() != end) 11435 && (start == end)) { 11436 setAccessibilitySelection(start, end); 11437 notifyViewAccessibilityStateChangedIfNeeded( 11438 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11439 return true; 11440 } 11441 } break; 11442 case R.id.accessibilityActionShowOnScreen: { 11443 if (mAttachInfo != null) { 11444 final Rect r = mAttachInfo.mTmpInvalRect; 11445 getDrawingRect(r); 11446 return requestRectangleOnScreen(r, true); 11447 } 11448 } break; 11449 case R.id.accessibilityActionContextClick: { 11450 if (isContextClickable()) { 11451 performContextClick(); 11452 return true; 11453 } 11454 } break; 11455 } 11456 return false; 11457 } 11458 11459 private boolean traverseAtGranularity(int granularity, boolean forward, 11460 boolean extendSelection) { 11461 CharSequence text = getIterableTextForAccessibility(); 11462 if (text == null || text.length() == 0) { 11463 return false; 11464 } 11465 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 11466 if (iterator == null) { 11467 return false; 11468 } 11469 int current = getAccessibilitySelectionEnd(); 11470 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11471 current = forward ? 0 : text.length(); 11472 } 11473 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 11474 if (range == null) { 11475 return false; 11476 } 11477 final int segmentStart = range[0]; 11478 final int segmentEnd = range[1]; 11479 int selectionStart; 11480 int selectionEnd; 11481 if (extendSelection && isAccessibilitySelectionExtendable()) { 11482 selectionStart = getAccessibilitySelectionStart(); 11483 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 11484 selectionStart = forward ? segmentStart : segmentEnd; 11485 } 11486 selectionEnd = forward ? segmentEnd : segmentStart; 11487 } else { 11488 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 11489 } 11490 setAccessibilitySelection(selectionStart, selectionEnd); 11491 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 11492 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 11493 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 11494 return true; 11495 } 11496 11497 /** 11498 * Gets the text reported for accessibility purposes. 11499 * 11500 * @return The accessibility text. 11501 * 11502 * @hide 11503 */ 11504 public CharSequence getIterableTextForAccessibility() { 11505 return getContentDescription(); 11506 } 11507 11508 /** 11509 * Gets whether accessibility selection can be extended. 11510 * 11511 * @return If selection is extensible. 11512 * 11513 * @hide 11514 */ 11515 public boolean isAccessibilitySelectionExtendable() { 11516 return false; 11517 } 11518 11519 /** 11520 * @hide 11521 */ 11522 public int getAccessibilitySelectionStart() { 11523 return mAccessibilityCursorPosition; 11524 } 11525 11526 /** 11527 * @hide 11528 */ 11529 public int getAccessibilitySelectionEnd() { 11530 return getAccessibilitySelectionStart(); 11531 } 11532 11533 /** 11534 * @hide 11535 */ 11536 public void setAccessibilitySelection(int start, int end) { 11537 if (start == end && end == mAccessibilityCursorPosition) { 11538 return; 11539 } 11540 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 11541 mAccessibilityCursorPosition = start; 11542 } else { 11543 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 11544 } 11545 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 11546 } 11547 11548 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 11549 int fromIndex, int toIndex) { 11550 if (mParent == null) { 11551 return; 11552 } 11553 AccessibilityEvent event = AccessibilityEvent.obtain( 11554 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 11555 onInitializeAccessibilityEvent(event); 11556 onPopulateAccessibilityEvent(event); 11557 event.setFromIndex(fromIndex); 11558 event.setToIndex(toIndex); 11559 event.setAction(action); 11560 event.setMovementGranularity(granularity); 11561 mParent.requestSendAccessibilityEvent(this, event); 11562 } 11563 11564 /** 11565 * @hide 11566 */ 11567 public TextSegmentIterator getIteratorForGranularity(int granularity) { 11568 switch (granularity) { 11569 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 11570 CharSequence text = getIterableTextForAccessibility(); 11571 if (text != null && text.length() > 0) { 11572 CharacterTextSegmentIterator iterator = 11573 CharacterTextSegmentIterator.getInstance( 11574 mContext.getResources().getConfiguration().locale); 11575 iterator.initialize(text.toString()); 11576 return iterator; 11577 } 11578 } break; 11579 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 11580 CharSequence text = getIterableTextForAccessibility(); 11581 if (text != null && text.length() > 0) { 11582 WordTextSegmentIterator iterator = 11583 WordTextSegmentIterator.getInstance( 11584 mContext.getResources().getConfiguration().locale); 11585 iterator.initialize(text.toString()); 11586 return iterator; 11587 } 11588 } break; 11589 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 11590 CharSequence text = getIterableTextForAccessibility(); 11591 if (text != null && text.length() > 0) { 11592 ParagraphTextSegmentIterator iterator = 11593 ParagraphTextSegmentIterator.getInstance(); 11594 iterator.initialize(text.toString()); 11595 return iterator; 11596 } 11597 } break; 11598 } 11599 return null; 11600 } 11601 11602 /** 11603 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 11604 * and {@link #onFinishTemporaryDetach()}. 11605 * 11606 * <p>This method always returns {@code true} when called directly or indirectly from 11607 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 11608 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 11609 * <ul> 11610 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 11611 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 11612 * </ul> 11613 * </p> 11614 * 11615 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 11616 * and {@link #onFinishTemporaryDetach()}. 11617 */ 11618 public final boolean isTemporarilyDetached() { 11619 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 11620 } 11621 11622 /** 11623 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 11624 * a container View. 11625 */ 11626 @CallSuper 11627 public void dispatchStartTemporaryDetach() { 11628 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 11629 notifyEnterOrExitForAutoFillIfNeeded(false); 11630 onStartTemporaryDetach(); 11631 } 11632 11633 /** 11634 * This is called when a container is going to temporarily detach a child, with 11635 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 11636 * It will either be followed by {@link #onFinishTemporaryDetach()} or 11637 * {@link #onDetachedFromWindow()} when the container is done. 11638 */ 11639 public void onStartTemporaryDetach() { 11640 removeUnsetPressCallback(); 11641 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 11642 } 11643 11644 /** 11645 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 11646 * a container View. 11647 */ 11648 @CallSuper 11649 public void dispatchFinishTemporaryDetach() { 11650 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 11651 onFinishTemporaryDetach(); 11652 if (hasWindowFocus() && hasFocus()) { 11653 InputMethodManager.getInstance().focusIn(this); 11654 } 11655 notifyEnterOrExitForAutoFillIfNeeded(true); 11656 } 11657 11658 /** 11659 * Called after {@link #onStartTemporaryDetach} when the container is done 11660 * changing the view. 11661 */ 11662 public void onFinishTemporaryDetach() { 11663 } 11664 11665 /** 11666 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 11667 * for this view's window. Returns null if the view is not currently attached 11668 * to the window. Normally you will not need to use this directly, but 11669 * just use the standard high-level event callbacks like 11670 * {@link #onKeyDown(int, KeyEvent)}. 11671 */ 11672 public KeyEvent.DispatcherState getKeyDispatcherState() { 11673 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 11674 } 11675 11676 /** 11677 * Dispatch a key event before it is processed by any input method 11678 * associated with the view hierarchy. This can be used to intercept 11679 * key events in special situations before the IME consumes them; a 11680 * typical example would be handling the BACK key to update the application's 11681 * UI instead of allowing the IME to see it and close itself. 11682 * 11683 * @param event The key event to be dispatched. 11684 * @return True if the event was handled, false otherwise. 11685 */ 11686 public boolean dispatchKeyEventPreIme(KeyEvent event) { 11687 return onKeyPreIme(event.getKeyCode(), event); 11688 } 11689 11690 /** 11691 * Dispatch a key event to the next view on the focus path. This path runs 11692 * from the top of the view tree down to the currently focused view. If this 11693 * view has focus, it will dispatch to itself. Otherwise it will dispatch 11694 * the next node down the focus path. This method also fires any key 11695 * listeners. 11696 * 11697 * @param event The key event to be dispatched. 11698 * @return True if the event was handled, false otherwise. 11699 */ 11700 public boolean dispatchKeyEvent(KeyEvent event) { 11701 if (mInputEventConsistencyVerifier != null) { 11702 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 11703 } 11704 11705 // Give any attached key listener a first crack at the event. 11706 //noinspection SimplifiableIfStatement 11707 ListenerInfo li = mListenerInfo; 11708 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 11709 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 11710 return true; 11711 } 11712 11713 if (event.dispatch(this, mAttachInfo != null 11714 ? mAttachInfo.mKeyDispatchState : null, this)) { 11715 return true; 11716 } 11717 11718 if (mInputEventConsistencyVerifier != null) { 11719 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11720 } 11721 return false; 11722 } 11723 11724 /** 11725 * Dispatches a key shortcut event. 11726 * 11727 * @param event The key event to be dispatched. 11728 * @return True if the event was handled by the view, false otherwise. 11729 */ 11730 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 11731 return onKeyShortcut(event.getKeyCode(), event); 11732 } 11733 11734 /** 11735 * Pass the touch screen motion event down to the target view, or this 11736 * view if it is the target. 11737 * 11738 * @param event The motion event to be dispatched. 11739 * @return True if the event was handled by the view, false otherwise. 11740 */ 11741 public boolean dispatchTouchEvent(MotionEvent event) { 11742 // If the event should be handled by accessibility focus first. 11743 if (event.isTargetAccessibilityFocus()) { 11744 // We don't have focus or no virtual descendant has it, do not handle the event. 11745 if (!isAccessibilityFocusedViewOrHost()) { 11746 return false; 11747 } 11748 // We have focus and got the event, then use normal event dispatch. 11749 event.setTargetAccessibilityFocus(false); 11750 } 11751 11752 boolean result = false; 11753 11754 if (mInputEventConsistencyVerifier != null) { 11755 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11756 } 11757 11758 final int actionMasked = event.getActionMasked(); 11759 if (actionMasked == MotionEvent.ACTION_DOWN) { 11760 // Defensive cleanup for new gesture 11761 stopNestedScroll(); 11762 } 11763 11764 if (onFilterTouchEventForSecurity(event)) { 11765 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 11766 result = true; 11767 } 11768 //noinspection SimplifiableIfStatement 11769 ListenerInfo li = mListenerInfo; 11770 if (li != null && li.mOnTouchListener != null 11771 && (mViewFlags & ENABLED_MASK) == ENABLED 11772 && li.mOnTouchListener.onTouch(this, event)) { 11773 result = true; 11774 } 11775 11776 if (!result && onTouchEvent(event)) { 11777 result = true; 11778 } 11779 } 11780 11781 if (!result && mInputEventConsistencyVerifier != null) { 11782 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11783 } 11784 11785 // Clean up after nested scrolls if this is the end of a gesture; 11786 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 11787 // of the gesture. 11788 if (actionMasked == MotionEvent.ACTION_UP || 11789 actionMasked == MotionEvent.ACTION_CANCEL || 11790 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 11791 stopNestedScroll(); 11792 } 11793 11794 return result; 11795 } 11796 11797 boolean isAccessibilityFocusedViewOrHost() { 11798 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 11799 .getAccessibilityFocusedHost() == this); 11800 } 11801 11802 /** 11803 * Filter the touch event to apply security policies. 11804 * 11805 * @param event The motion event to be filtered. 11806 * @return True if the event should be dispatched, false if the event should be dropped. 11807 * 11808 * @see #getFilterTouchesWhenObscured 11809 */ 11810 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 11811 //noinspection RedundantIfStatement 11812 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 11813 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 11814 // Window is obscured, drop this touch. 11815 return false; 11816 } 11817 return true; 11818 } 11819 11820 /** 11821 * Pass a trackball motion event down to the focused view. 11822 * 11823 * @param event The motion event to be dispatched. 11824 * @return True if the event was handled by the view, false otherwise. 11825 */ 11826 public boolean dispatchTrackballEvent(MotionEvent event) { 11827 if (mInputEventConsistencyVerifier != null) { 11828 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 11829 } 11830 11831 return onTrackballEvent(event); 11832 } 11833 11834 /** 11835 * Pass a captured pointer event down to the focused view. 11836 * 11837 * @param event The motion event to be dispatched. 11838 * @return True if the event was handled by the view, false otherwise. 11839 */ 11840 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 11841 if (!hasPointerCapture()) { 11842 return false; 11843 } 11844 //noinspection SimplifiableIfStatement 11845 ListenerInfo li = mListenerInfo; 11846 if (li != null && li.mOnCapturedPointerListener != null 11847 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 11848 return true; 11849 } 11850 return onCapturedPointerEvent(event); 11851 } 11852 11853 /** 11854 * Dispatch a generic motion event. 11855 * <p> 11856 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 11857 * are delivered to the view under the pointer. All other generic motion events are 11858 * delivered to the focused view. Hover events are handled specially and are delivered 11859 * to {@link #onHoverEvent(MotionEvent)}. 11860 * </p> 11861 * 11862 * @param event The motion event to be dispatched. 11863 * @return True if the event was handled by the view, false otherwise. 11864 */ 11865 public boolean dispatchGenericMotionEvent(MotionEvent event) { 11866 if (mInputEventConsistencyVerifier != null) { 11867 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 11868 } 11869 11870 final int source = event.getSource(); 11871 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 11872 final int action = event.getAction(); 11873 if (action == MotionEvent.ACTION_HOVER_ENTER 11874 || action == MotionEvent.ACTION_HOVER_MOVE 11875 || action == MotionEvent.ACTION_HOVER_EXIT) { 11876 if (dispatchHoverEvent(event)) { 11877 return true; 11878 } 11879 } else if (dispatchGenericPointerEvent(event)) { 11880 return true; 11881 } 11882 } else if (dispatchGenericFocusedEvent(event)) { 11883 return true; 11884 } 11885 11886 if (dispatchGenericMotionEventInternal(event)) { 11887 return true; 11888 } 11889 11890 if (mInputEventConsistencyVerifier != null) { 11891 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11892 } 11893 return false; 11894 } 11895 11896 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 11897 //noinspection SimplifiableIfStatement 11898 ListenerInfo li = mListenerInfo; 11899 if (li != null && li.mOnGenericMotionListener != null 11900 && (mViewFlags & ENABLED_MASK) == ENABLED 11901 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 11902 return true; 11903 } 11904 11905 if (onGenericMotionEvent(event)) { 11906 return true; 11907 } 11908 11909 final int actionButton = event.getActionButton(); 11910 switch (event.getActionMasked()) { 11911 case MotionEvent.ACTION_BUTTON_PRESS: 11912 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 11913 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11914 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11915 if (performContextClick(event.getX(), event.getY())) { 11916 mInContextButtonPress = true; 11917 setPressed(true, event.getX(), event.getY()); 11918 removeTapCallback(); 11919 removeLongPressCallback(); 11920 return true; 11921 } 11922 } 11923 break; 11924 11925 case MotionEvent.ACTION_BUTTON_RELEASE: 11926 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 11927 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 11928 mInContextButtonPress = false; 11929 mIgnoreNextUpEvent = true; 11930 } 11931 break; 11932 } 11933 11934 if (mInputEventConsistencyVerifier != null) { 11935 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 11936 } 11937 return false; 11938 } 11939 11940 /** 11941 * Dispatch a hover event. 11942 * <p> 11943 * Do not call this method directly. 11944 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11945 * </p> 11946 * 11947 * @param event The motion event to be dispatched. 11948 * @return True if the event was handled by the view, false otherwise. 11949 */ 11950 protected boolean dispatchHoverEvent(MotionEvent event) { 11951 ListenerInfo li = mListenerInfo; 11952 //noinspection SimplifiableIfStatement 11953 if (li != null && li.mOnHoverListener != null 11954 && (mViewFlags & ENABLED_MASK) == ENABLED 11955 && li.mOnHoverListener.onHover(this, event)) { 11956 return true; 11957 } 11958 11959 return onHoverEvent(event); 11960 } 11961 11962 /** 11963 * Returns true if the view has a child to which it has recently sent 11964 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 11965 * it does not have a hovered child, then it must be the innermost hovered view. 11966 * @hide 11967 */ 11968 protected boolean hasHoveredChild() { 11969 return false; 11970 } 11971 11972 /** 11973 * Dispatch a generic motion event to the view under the first pointer. 11974 * <p> 11975 * Do not call this method directly. 11976 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11977 * </p> 11978 * 11979 * @param event The motion event to be dispatched. 11980 * @return True if the event was handled by the view, false otherwise. 11981 */ 11982 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 11983 return false; 11984 } 11985 11986 /** 11987 * Dispatch a generic motion event to the currently focused view. 11988 * <p> 11989 * Do not call this method directly. 11990 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 11991 * </p> 11992 * 11993 * @param event The motion event to be dispatched. 11994 * @return True if the event was handled by the view, false otherwise. 11995 */ 11996 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 11997 return false; 11998 } 11999 12000 /** 12001 * Dispatch a pointer event. 12002 * <p> 12003 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 12004 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 12005 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 12006 * and should not be expected to handle other pointing device features. 12007 * </p> 12008 * 12009 * @param event The motion event to be dispatched. 12010 * @return True if the event was handled by the view, false otherwise. 12011 * @hide 12012 */ 12013 public final boolean dispatchPointerEvent(MotionEvent event) { 12014 if (event.isTouchEvent()) { 12015 return dispatchTouchEvent(event); 12016 } else { 12017 return dispatchGenericMotionEvent(event); 12018 } 12019 } 12020 12021 /** 12022 * Called when the window containing this view gains or loses window focus. 12023 * ViewGroups should override to route to their children. 12024 * 12025 * @param hasFocus True if the window containing this view now has focus, 12026 * false otherwise. 12027 */ 12028 public void dispatchWindowFocusChanged(boolean hasFocus) { 12029 onWindowFocusChanged(hasFocus); 12030 } 12031 12032 /** 12033 * Called when the window containing this view gains or loses focus. Note 12034 * that this is separate from view focus: to receive key events, both 12035 * your view and its window must have focus. If a window is displayed 12036 * on top of yours that takes input focus, then your own window will lose 12037 * focus but the view focus will remain unchanged. 12038 * 12039 * @param hasWindowFocus True if the window containing this view now has 12040 * focus, false otherwise. 12041 */ 12042 public void onWindowFocusChanged(boolean hasWindowFocus) { 12043 InputMethodManager imm = InputMethodManager.peekInstance(); 12044 if (!hasWindowFocus) { 12045 if (isPressed()) { 12046 setPressed(false); 12047 } 12048 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12049 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12050 imm.focusOut(this); 12051 } 12052 removeLongPressCallback(); 12053 removeTapCallback(); 12054 onFocusLost(); 12055 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 12056 imm.focusIn(this); 12057 } 12058 12059 notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); 12060 12061 refreshDrawableState(); 12062 } 12063 12064 /** 12065 * Returns true if this view is in a window that currently has window focus. 12066 * Note that this is not the same as the view itself having focus. 12067 * 12068 * @return True if this view is in a window that currently has window focus. 12069 */ 12070 public boolean hasWindowFocus() { 12071 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 12072 } 12073 12074 /** 12075 * Dispatch a view visibility change down the view hierarchy. 12076 * ViewGroups should override to route to their children. 12077 * @param changedView The view whose visibility changed. Could be 'this' or 12078 * an ancestor view. 12079 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 12080 * {@link #INVISIBLE} or {@link #GONE}. 12081 */ 12082 protected void dispatchVisibilityChanged(@NonNull View changedView, 12083 @Visibility int visibility) { 12084 onVisibilityChanged(changedView, visibility); 12085 } 12086 12087 /** 12088 * Called when the visibility of the view or an ancestor of the view has 12089 * changed. 12090 * 12091 * @param changedView The view whose visibility changed. May be 12092 * {@code this} or an ancestor view. 12093 * @param visibility The new visibility, one of {@link #VISIBLE}, 12094 * {@link #INVISIBLE} or {@link #GONE}. 12095 */ 12096 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 12097 } 12098 12099 /** 12100 * Dispatch a hint about whether this view is displayed. For instance, when 12101 * a View moves out of the screen, it might receives a display hint indicating 12102 * the view is not displayed. Applications should not <em>rely</em> on this hint 12103 * as there is no guarantee that they will receive one. 12104 * 12105 * @param hint A hint about whether or not this view is displayed: 12106 * {@link #VISIBLE} or {@link #INVISIBLE}. 12107 */ 12108 public void dispatchDisplayHint(@Visibility int hint) { 12109 onDisplayHint(hint); 12110 } 12111 12112 /** 12113 * Gives this view a hint about whether is displayed or not. For instance, when 12114 * a View moves out of the screen, it might receives a display hint indicating 12115 * the view is not displayed. Applications should not <em>rely</em> on this hint 12116 * as there is no guarantee that they will receive one. 12117 * 12118 * @param hint A hint about whether or not this view is displayed: 12119 * {@link #VISIBLE} or {@link #INVISIBLE}. 12120 */ 12121 protected void onDisplayHint(@Visibility int hint) { 12122 } 12123 12124 /** 12125 * Dispatch a window visibility change down the view hierarchy. 12126 * ViewGroups should override to route to their children. 12127 * 12128 * @param visibility The new visibility of the window. 12129 * 12130 * @see #onWindowVisibilityChanged(int) 12131 */ 12132 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 12133 onWindowVisibilityChanged(visibility); 12134 } 12135 12136 /** 12137 * Called when the window containing has change its visibility 12138 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 12139 * that this tells you whether or not your window is being made visible 12140 * to the window manager; this does <em>not</em> tell you whether or not 12141 * your window is obscured by other windows on the screen, even if it 12142 * is itself visible. 12143 * 12144 * @param visibility The new visibility of the window. 12145 */ 12146 protected void onWindowVisibilityChanged(@Visibility int visibility) { 12147 if (visibility == VISIBLE) { 12148 initialAwakenScrollBars(); 12149 } 12150 } 12151 12152 /** 12153 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 12154 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 12155 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 12156 * 12157 * @param isVisible true if this view's visibility to the user is uninterrupted by its 12158 * ancestors or by window visibility 12159 * @return true if this view is visible to the user, not counting clipping or overlapping 12160 */ 12161 boolean dispatchVisibilityAggregated(boolean isVisible) { 12162 final boolean thisVisible = getVisibility() == VISIBLE; 12163 // If we're not visible but something is telling us we are, ignore it. 12164 if (thisVisible || !isVisible) { 12165 onVisibilityAggregated(isVisible); 12166 } 12167 return thisVisible && isVisible; 12168 } 12169 12170 /** 12171 * Called when the user-visibility of this View is potentially affected by a change 12172 * to this view itself, an ancestor view or the window this view is attached to. 12173 * 12174 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 12175 * and this view's window is also visible 12176 */ 12177 @CallSuper 12178 public void onVisibilityAggregated(boolean isVisible) { 12179 if (isVisible && mAttachInfo != null) { 12180 initialAwakenScrollBars(); 12181 } 12182 12183 final Drawable dr = mBackground; 12184 if (dr != null && isVisible != dr.isVisible()) { 12185 dr.setVisible(isVisible, false); 12186 } 12187 final Drawable hl = mDefaultFocusHighlight; 12188 if (hl != null && isVisible != hl.isVisible()) { 12189 hl.setVisible(isVisible, false); 12190 } 12191 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 12192 if (fg != null && isVisible != fg.isVisible()) { 12193 fg.setVisible(isVisible, false); 12194 } 12195 12196 if (isAutofillable()) { 12197 AutofillManager afm = getAutofillManager(); 12198 12199 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 12200 if (mVisibilityChangeForAutofillHandler != null) { 12201 mVisibilityChangeForAutofillHandler.removeMessages(0); 12202 } 12203 12204 // If the view is in the background but still part of the hierarchy this is called 12205 // with isVisible=false. Hence visibility==false requires further checks 12206 if (isVisible) { 12207 afm.notifyViewVisibilityChanged(this, true); 12208 } else { 12209 if (mVisibilityChangeForAutofillHandler == null) { 12210 mVisibilityChangeForAutofillHandler = 12211 new VisibilityChangeForAutofillHandler(afm, this); 12212 } 12213 // Let current operation (e.g. removal of the view from the hierarchy) 12214 // finish before checking state 12215 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 12216 } 12217 } 12218 } 12219 } 12220 12221 /** 12222 * Returns the current visibility of the window this view is attached to 12223 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 12224 * 12225 * @return Returns the current visibility of the view's window. 12226 */ 12227 @Visibility 12228 public int getWindowVisibility() { 12229 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 12230 } 12231 12232 /** 12233 * Retrieve the overall visible display size in which the window this view is 12234 * attached to has been positioned in. This takes into account screen 12235 * decorations above the window, for both cases where the window itself 12236 * is being position inside of them or the window is being placed under 12237 * then and covered insets are used for the window to position its content 12238 * inside. In effect, this tells you the available area where content can 12239 * be placed and remain visible to users. 12240 * 12241 * <p>This function requires an IPC back to the window manager to retrieve 12242 * the requested information, so should not be used in performance critical 12243 * code like drawing. 12244 * 12245 * @param outRect Filled in with the visible display frame. If the view 12246 * is not attached to a window, this is simply the raw display size. 12247 */ 12248 public void getWindowVisibleDisplayFrame(Rect outRect) { 12249 if (mAttachInfo != null) { 12250 try { 12251 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12252 } catch (RemoteException e) { 12253 return; 12254 } 12255 // XXX This is really broken, and probably all needs to be done 12256 // in the window manager, and we need to know more about whether 12257 // we want the area behind or in front of the IME. 12258 final Rect insets = mAttachInfo.mVisibleInsets; 12259 outRect.left += insets.left; 12260 outRect.top += insets.top; 12261 outRect.right -= insets.right; 12262 outRect.bottom -= insets.bottom; 12263 return; 12264 } 12265 // The view is not attached to a display so we don't have a context. 12266 // Make a best guess about the display size. 12267 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12268 d.getRectSize(outRect); 12269 } 12270 12271 /** 12272 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 12273 * is currently in without any insets. 12274 * 12275 * @hide 12276 */ 12277 public void getWindowDisplayFrame(Rect outRect) { 12278 if (mAttachInfo != null) { 12279 try { 12280 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 12281 } catch (RemoteException e) { 12282 return; 12283 } 12284 return; 12285 } 12286 // The view is not attached to a display so we don't have a context. 12287 // Make a best guess about the display size. 12288 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 12289 d.getRectSize(outRect); 12290 } 12291 12292 /** 12293 * Dispatch a notification about a resource configuration change down 12294 * the view hierarchy. 12295 * ViewGroups should override to route to their children. 12296 * 12297 * @param newConfig The new resource configuration. 12298 * 12299 * @see #onConfigurationChanged(android.content.res.Configuration) 12300 */ 12301 public void dispatchConfigurationChanged(Configuration newConfig) { 12302 onConfigurationChanged(newConfig); 12303 } 12304 12305 /** 12306 * Called when the current configuration of the resources being used 12307 * by the application have changed. You can use this to decide when 12308 * to reload resources that can changed based on orientation and other 12309 * configuration characteristics. You only need to use this if you are 12310 * not relying on the normal {@link android.app.Activity} mechanism of 12311 * recreating the activity instance upon a configuration change. 12312 * 12313 * @param newConfig The new resource configuration. 12314 */ 12315 protected void onConfigurationChanged(Configuration newConfig) { 12316 } 12317 12318 /** 12319 * Private function to aggregate all per-view attributes in to the view 12320 * root. 12321 */ 12322 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12323 performCollectViewAttributes(attachInfo, visibility); 12324 } 12325 12326 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 12327 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 12328 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 12329 attachInfo.mKeepScreenOn = true; 12330 } 12331 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 12332 ListenerInfo li = mListenerInfo; 12333 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 12334 attachInfo.mHasSystemUiListeners = true; 12335 } 12336 } 12337 } 12338 12339 void needGlobalAttributesUpdate(boolean force) { 12340 final AttachInfo ai = mAttachInfo; 12341 if (ai != null && !ai.mRecomputeGlobalAttributes) { 12342 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 12343 || ai.mHasSystemUiListeners) { 12344 ai.mRecomputeGlobalAttributes = true; 12345 } 12346 } 12347 } 12348 12349 /** 12350 * Returns whether the device is currently in touch mode. Touch mode is entered 12351 * once the user begins interacting with the device by touch, and affects various 12352 * things like whether focus is always visible to the user. 12353 * 12354 * @return Whether the device is in touch mode. 12355 */ 12356 @ViewDebug.ExportedProperty 12357 public boolean isInTouchMode() { 12358 if (mAttachInfo != null) { 12359 return mAttachInfo.mInTouchMode; 12360 } else { 12361 return ViewRootImpl.isInTouchMode(); 12362 } 12363 } 12364 12365 /** 12366 * Returns the context the view is running in, through which it can 12367 * access the current theme, resources, etc. 12368 * 12369 * @return The view's Context. 12370 */ 12371 @ViewDebug.CapturedViewProperty 12372 public final Context getContext() { 12373 return mContext; 12374 } 12375 12376 /** 12377 * Handle a key event before it is processed by any input method 12378 * associated with the view hierarchy. This can be used to intercept 12379 * key events in special situations before the IME consumes them; a 12380 * typical example would be handling the BACK key to update the application's 12381 * UI instead of allowing the IME to see it and close itself. 12382 * 12383 * @param keyCode The value in event.getKeyCode(). 12384 * @param event Description of the key event. 12385 * @return If you handled the event, return true. If you want to allow the 12386 * event to be handled by the next receiver, return false. 12387 */ 12388 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 12389 return false; 12390 } 12391 12392 /** 12393 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 12394 * KeyEvent.Callback.onKeyDown()}: perform press of the view 12395 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 12396 * is released, if the view is enabled and clickable. 12397 * <p> 12398 * Key presses in software keyboards will generally NOT trigger this 12399 * listener, although some may elect to do so in some situations. Do not 12400 * rely on this to catch software key presses. 12401 * 12402 * @param keyCode a key code that represents the button pressed, from 12403 * {@link android.view.KeyEvent} 12404 * @param event the KeyEvent object that defines the button action 12405 */ 12406 public boolean onKeyDown(int keyCode, KeyEvent event) { 12407 if (KeyEvent.isConfirmKey(keyCode)) { 12408 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12409 return true; 12410 } 12411 12412 if (event.getRepeatCount() == 0) { 12413 // Long clickable items don't necessarily have to be clickable. 12414 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 12415 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12416 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 12417 // For the purposes of menu anchoring and drawable hotspots, 12418 // key events are considered to be at the center of the view. 12419 final float x = getWidth() / 2f; 12420 final float y = getHeight() / 2f; 12421 if (clickable) { 12422 setPressed(true, x, y); 12423 } 12424 checkForLongClick(0, x, y); 12425 return true; 12426 } 12427 } 12428 } 12429 12430 return false; 12431 } 12432 12433 /** 12434 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 12435 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 12436 * the event). 12437 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12438 * although some may elect to do so in some situations. Do not rely on this to 12439 * catch software key presses. 12440 */ 12441 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 12442 return false; 12443 } 12444 12445 /** 12446 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 12447 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 12448 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 12449 * or {@link KeyEvent#KEYCODE_SPACE} is released. 12450 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12451 * although some may elect to do so in some situations. Do not rely on this to 12452 * catch software key presses. 12453 * 12454 * @param keyCode A key code that represents the button pressed, from 12455 * {@link android.view.KeyEvent}. 12456 * @param event The KeyEvent object that defines the button action. 12457 */ 12458 public boolean onKeyUp(int keyCode, KeyEvent event) { 12459 if (KeyEvent.isConfirmKey(keyCode)) { 12460 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12461 return true; 12462 } 12463 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 12464 setPressed(false); 12465 12466 if (!mHasPerformedLongPress) { 12467 // This is a tap, so remove the longpress check 12468 removeLongPressCallback(); 12469 if (!event.isCanceled()) { 12470 return performClick(); 12471 } 12472 } 12473 } 12474 } 12475 return false; 12476 } 12477 12478 /** 12479 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 12480 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 12481 * the event). 12482 * <p>Key presses in software keyboards will generally NOT trigger this listener, 12483 * although some may elect to do so in some situations. Do not rely on this to 12484 * catch software key presses. 12485 * 12486 * @param keyCode A key code that represents the button pressed, from 12487 * {@link android.view.KeyEvent}. 12488 * @param repeatCount The number of times the action was made. 12489 * @param event The KeyEvent object that defines the button action. 12490 */ 12491 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 12492 return false; 12493 } 12494 12495 /** 12496 * Called on the focused view when a key shortcut event is not handled. 12497 * Override this method to implement local key shortcuts for the View. 12498 * Key shortcuts can also be implemented by setting the 12499 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 12500 * 12501 * @param keyCode The value in event.getKeyCode(). 12502 * @param event Description of the key event. 12503 * @return If you handled the event, return true. If you want to allow the 12504 * event to be handled by the next receiver, return false. 12505 */ 12506 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 12507 return false; 12508 } 12509 12510 /** 12511 * Check whether the called view is a text editor, in which case it 12512 * would make sense to automatically display a soft input window for 12513 * it. Subclasses should override this if they implement 12514 * {@link #onCreateInputConnection(EditorInfo)} to return true if 12515 * a call on that method would return a non-null InputConnection, and 12516 * they are really a first-class editor that the user would normally 12517 * start typing on when the go into a window containing your view. 12518 * 12519 * <p>The default implementation always returns false. This does 12520 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 12521 * will not be called or the user can not otherwise perform edits on your 12522 * view; it is just a hint to the system that this is not the primary 12523 * purpose of this view. 12524 * 12525 * @return Returns true if this view is a text editor, else false. 12526 */ 12527 public boolean onCheckIsTextEditor() { 12528 return false; 12529 } 12530 12531 /** 12532 * Create a new InputConnection for an InputMethod to interact 12533 * with the view. The default implementation returns null, since it doesn't 12534 * support input methods. You can override this to implement such support. 12535 * This is only needed for views that take focus and text input. 12536 * 12537 * <p>When implementing this, you probably also want to implement 12538 * {@link #onCheckIsTextEditor()} to indicate you will return a 12539 * non-null InputConnection.</p> 12540 * 12541 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 12542 * object correctly and in its entirety, so that the connected IME can rely 12543 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 12544 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 12545 * must be filled in with the correct cursor position for IMEs to work correctly 12546 * with your application.</p> 12547 * 12548 * @param outAttrs Fill in with attribute information about the connection. 12549 */ 12550 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 12551 return null; 12552 } 12553 12554 /** 12555 * Called by the {@link android.view.inputmethod.InputMethodManager} 12556 * when a view who is not the current 12557 * input connection target is trying to make a call on the manager. The 12558 * default implementation returns false; you can override this to return 12559 * true for certain views if you are performing InputConnection proxying 12560 * to them. 12561 * @param view The View that is making the InputMethodManager call. 12562 * @return Return true to allow the call, false to reject. 12563 */ 12564 public boolean checkInputConnectionProxy(View view) { 12565 return false; 12566 } 12567 12568 /** 12569 * Show the context menu for this view. It is not safe to hold on to the 12570 * menu after returning from this method. 12571 * 12572 * You should normally not overload this method. Overload 12573 * {@link #onCreateContextMenu(ContextMenu)} or define an 12574 * {@link OnCreateContextMenuListener} to add items to the context menu. 12575 * 12576 * @param menu The context menu to populate 12577 */ 12578 public void createContextMenu(ContextMenu menu) { 12579 ContextMenuInfo menuInfo = getContextMenuInfo(); 12580 12581 // Sets the current menu info so all items added to menu will have 12582 // my extra info set. 12583 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 12584 12585 onCreateContextMenu(menu); 12586 ListenerInfo li = mListenerInfo; 12587 if (li != null && li.mOnCreateContextMenuListener != null) { 12588 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 12589 } 12590 12591 // Clear the extra information so subsequent items that aren't mine don't 12592 // have my extra info. 12593 ((MenuBuilder)menu).setCurrentMenuInfo(null); 12594 12595 if (mParent != null) { 12596 mParent.createContextMenu(menu); 12597 } 12598 } 12599 12600 /** 12601 * Views should implement this if they have extra information to associate 12602 * with the context menu. The return result is supplied as a parameter to 12603 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 12604 * callback. 12605 * 12606 * @return Extra information about the item for which the context menu 12607 * should be shown. This information will vary across different 12608 * subclasses of View. 12609 */ 12610 protected ContextMenuInfo getContextMenuInfo() { 12611 return null; 12612 } 12613 12614 /** 12615 * Views should implement this if the view itself is going to add items to 12616 * the context menu. 12617 * 12618 * @param menu the context menu to populate 12619 */ 12620 protected void onCreateContextMenu(ContextMenu menu) { 12621 } 12622 12623 /** 12624 * Implement this method to handle trackball motion events. The 12625 * <em>relative</em> movement of the trackball since the last event 12626 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 12627 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 12628 * that a movement of 1 corresponds to the user pressing one DPAD key (so 12629 * they will often be fractional values, representing the more fine-grained 12630 * movement information available from a trackball). 12631 * 12632 * @param event The motion event. 12633 * @return True if the event was handled, false otherwise. 12634 */ 12635 public boolean onTrackballEvent(MotionEvent event) { 12636 return false; 12637 } 12638 12639 /** 12640 * Implement this method to handle generic motion events. 12641 * <p> 12642 * Generic motion events describe joystick movements, mouse hovers, track pad 12643 * touches, scroll wheel movements and other input events. The 12644 * {@link MotionEvent#getSource() source} of the motion event specifies 12645 * the class of input that was received. Implementations of this method 12646 * must examine the bits in the source before processing the event. 12647 * The following code example shows how this is done. 12648 * </p><p> 12649 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 12650 * are delivered to the view under the pointer. All other generic motion events are 12651 * delivered to the focused view. 12652 * </p> 12653 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 12654 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 12655 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 12656 * // process the joystick movement... 12657 * return true; 12658 * } 12659 * } 12660 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 12661 * switch (event.getAction()) { 12662 * case MotionEvent.ACTION_HOVER_MOVE: 12663 * // process the mouse hover movement... 12664 * return true; 12665 * case MotionEvent.ACTION_SCROLL: 12666 * // process the scroll wheel movement... 12667 * return true; 12668 * } 12669 * } 12670 * return super.onGenericMotionEvent(event); 12671 * }</pre> 12672 * 12673 * @param event The generic motion event being processed. 12674 * @return True if the event was handled, false otherwise. 12675 */ 12676 public boolean onGenericMotionEvent(MotionEvent event) { 12677 return false; 12678 } 12679 12680 /** 12681 * Implement this method to handle hover events. 12682 * <p> 12683 * This method is called whenever a pointer is hovering into, over, or out of the 12684 * bounds of a view and the view is not currently being touched. 12685 * Hover events are represented as pointer events with action 12686 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 12687 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 12688 * </p> 12689 * <ul> 12690 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 12691 * when the pointer enters the bounds of the view.</li> 12692 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 12693 * when the pointer has already entered the bounds of the view and has moved.</li> 12694 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 12695 * when the pointer has exited the bounds of the view or when the pointer is 12696 * about to go down due to a button click, tap, or similar user action that 12697 * causes the view to be touched.</li> 12698 * </ul> 12699 * <p> 12700 * The view should implement this method to return true to indicate that it is 12701 * handling the hover event, such as by changing its drawable state. 12702 * </p><p> 12703 * The default implementation calls {@link #setHovered} to update the hovered state 12704 * of the view when a hover enter or hover exit event is received, if the view 12705 * is enabled and is clickable. The default implementation also sends hover 12706 * accessibility events. 12707 * </p> 12708 * 12709 * @param event The motion event that describes the hover. 12710 * @return True if the view handled the hover event. 12711 * 12712 * @see #isHovered 12713 * @see #setHovered 12714 * @see #onHoverChanged 12715 */ 12716 public boolean onHoverEvent(MotionEvent event) { 12717 // The root view may receive hover (or touch) events that are outside the bounds of 12718 // the window. This code ensures that we only send accessibility events for 12719 // hovers that are actually within the bounds of the root view. 12720 final int action = event.getActionMasked(); 12721 if (!mSendingHoverAccessibilityEvents) { 12722 if ((action == MotionEvent.ACTION_HOVER_ENTER 12723 || action == MotionEvent.ACTION_HOVER_MOVE) 12724 && !hasHoveredChild() 12725 && pointInView(event.getX(), event.getY())) { 12726 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 12727 mSendingHoverAccessibilityEvents = true; 12728 } 12729 } else { 12730 if (action == MotionEvent.ACTION_HOVER_EXIT 12731 || (action == MotionEvent.ACTION_MOVE 12732 && !pointInView(event.getX(), event.getY()))) { 12733 mSendingHoverAccessibilityEvents = false; 12734 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 12735 } 12736 } 12737 12738 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 12739 && event.isFromSource(InputDevice.SOURCE_MOUSE) 12740 && isOnScrollbar(event.getX(), event.getY())) { 12741 awakenScrollBars(); 12742 } 12743 12744 // If we consider ourself hoverable, or if we we're already hovered, 12745 // handle changing state in response to ENTER and EXIT events. 12746 if (isHoverable() || isHovered()) { 12747 switch (action) { 12748 case MotionEvent.ACTION_HOVER_ENTER: 12749 setHovered(true); 12750 break; 12751 case MotionEvent.ACTION_HOVER_EXIT: 12752 setHovered(false); 12753 break; 12754 } 12755 12756 // Dispatch the event to onGenericMotionEvent before returning true. 12757 // This is to provide compatibility with existing applications that 12758 // handled HOVER_MOVE events in onGenericMotionEvent and that would 12759 // break because of the new default handling for hoverable views 12760 // in onHoverEvent. 12761 // Note that onGenericMotionEvent will be called by default when 12762 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 12763 dispatchGenericMotionEventInternal(event); 12764 // The event was already handled by calling setHovered(), so always 12765 // return true. 12766 return true; 12767 } 12768 12769 return false; 12770 } 12771 12772 /** 12773 * Returns true if the view should handle {@link #onHoverEvent} 12774 * by calling {@link #setHovered} to change its hovered state. 12775 * 12776 * @return True if the view is hoverable. 12777 */ 12778 private boolean isHoverable() { 12779 final int viewFlags = mViewFlags; 12780 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12781 return false; 12782 } 12783 12784 return (viewFlags & CLICKABLE) == CLICKABLE 12785 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12786 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12787 } 12788 12789 /** 12790 * Returns true if the view is currently hovered. 12791 * 12792 * @return True if the view is currently hovered. 12793 * 12794 * @see #setHovered 12795 * @see #onHoverChanged 12796 */ 12797 @ViewDebug.ExportedProperty 12798 public boolean isHovered() { 12799 return (mPrivateFlags & PFLAG_HOVERED) != 0; 12800 } 12801 12802 /** 12803 * Sets whether the view is currently hovered. 12804 * <p> 12805 * Calling this method also changes the drawable state of the view. This 12806 * enables the view to react to hover by using different drawable resources 12807 * to change its appearance. 12808 * </p><p> 12809 * The {@link #onHoverChanged} method is called when the hovered state changes. 12810 * </p> 12811 * 12812 * @param hovered True if the view is hovered. 12813 * 12814 * @see #isHovered 12815 * @see #onHoverChanged 12816 */ 12817 public void setHovered(boolean hovered) { 12818 if (hovered) { 12819 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 12820 mPrivateFlags |= PFLAG_HOVERED; 12821 refreshDrawableState(); 12822 onHoverChanged(true); 12823 } 12824 } else { 12825 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 12826 mPrivateFlags &= ~PFLAG_HOVERED; 12827 refreshDrawableState(); 12828 onHoverChanged(false); 12829 } 12830 } 12831 } 12832 12833 /** 12834 * Implement this method to handle hover state changes. 12835 * <p> 12836 * This method is called whenever the hover state changes as a result of a 12837 * call to {@link #setHovered}. 12838 * </p> 12839 * 12840 * @param hovered The current hover state, as returned by {@link #isHovered}. 12841 * 12842 * @see #isHovered 12843 * @see #setHovered 12844 */ 12845 public void onHoverChanged(boolean hovered) { 12846 } 12847 12848 /** 12849 * Handles scroll bar dragging by mouse input. 12850 * 12851 * @hide 12852 * @param event The motion event. 12853 * 12854 * @return true if the event was handled as a scroll bar dragging, false otherwise. 12855 */ 12856 protected boolean handleScrollBarDragging(MotionEvent event) { 12857 if (mScrollCache == null) { 12858 return false; 12859 } 12860 final float x = event.getX(); 12861 final float y = event.getY(); 12862 final int action = event.getAction(); 12863 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 12864 && action != MotionEvent.ACTION_DOWN) 12865 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 12866 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 12867 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12868 return false; 12869 } 12870 12871 switch (action) { 12872 case MotionEvent.ACTION_MOVE: 12873 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 12874 return false; 12875 } 12876 if (mScrollCache.mScrollBarDraggingState 12877 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 12878 final Rect bounds = mScrollCache.mScrollBarBounds; 12879 getVerticalScrollBarBounds(bounds, null); 12880 final int range = computeVerticalScrollRange(); 12881 final int offset = computeVerticalScrollOffset(); 12882 final int extent = computeVerticalScrollExtent(); 12883 12884 final int thumbLength = ScrollBarUtils.getThumbLength( 12885 bounds.height(), bounds.width(), extent, range); 12886 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12887 bounds.height(), thumbLength, extent, range, offset); 12888 12889 final float diff = y - mScrollCache.mScrollBarDraggingPos; 12890 final float maxThumbOffset = bounds.height() - thumbLength; 12891 final float newThumbOffset = 12892 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12893 final int height = getHeight(); 12894 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12895 && height > 0 && extent > 0) { 12896 final int newY = Math.round((range - extent) 12897 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 12898 if (newY != getScrollY()) { 12899 mScrollCache.mScrollBarDraggingPos = y; 12900 setScrollY(newY); 12901 } 12902 } 12903 return true; 12904 } 12905 if (mScrollCache.mScrollBarDraggingState 12906 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 12907 final Rect bounds = mScrollCache.mScrollBarBounds; 12908 getHorizontalScrollBarBounds(bounds, null); 12909 final int range = computeHorizontalScrollRange(); 12910 final int offset = computeHorizontalScrollOffset(); 12911 final int extent = computeHorizontalScrollExtent(); 12912 12913 final int thumbLength = ScrollBarUtils.getThumbLength( 12914 bounds.width(), bounds.height(), extent, range); 12915 final int thumbOffset = ScrollBarUtils.getThumbOffset( 12916 bounds.width(), thumbLength, extent, range, offset); 12917 12918 final float diff = x - mScrollCache.mScrollBarDraggingPos; 12919 final float maxThumbOffset = bounds.width() - thumbLength; 12920 final float newThumbOffset = 12921 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 12922 final int width = getWidth(); 12923 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 12924 && width > 0 && extent > 0) { 12925 final int newX = Math.round((range - extent) 12926 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 12927 if (newX != getScrollX()) { 12928 mScrollCache.mScrollBarDraggingPos = x; 12929 setScrollX(newX); 12930 } 12931 } 12932 return true; 12933 } 12934 case MotionEvent.ACTION_DOWN: 12935 if (mScrollCache.state == ScrollabilityCache.OFF) { 12936 return false; 12937 } 12938 if (isOnVerticalScrollbarThumb(x, y)) { 12939 mScrollCache.mScrollBarDraggingState = 12940 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 12941 mScrollCache.mScrollBarDraggingPos = y; 12942 return true; 12943 } 12944 if (isOnHorizontalScrollbarThumb(x, y)) { 12945 mScrollCache.mScrollBarDraggingState = 12946 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 12947 mScrollCache.mScrollBarDraggingPos = x; 12948 return true; 12949 } 12950 } 12951 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 12952 return false; 12953 } 12954 12955 /** 12956 * Implement this method to handle touch screen motion events. 12957 * <p> 12958 * If this method is used to detect click actions, it is recommended that 12959 * the actions be performed by implementing and calling 12960 * {@link #performClick()}. This will ensure consistent system behavior, 12961 * including: 12962 * <ul> 12963 * <li>obeying click sound preferences 12964 * <li>dispatching OnClickListener calls 12965 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 12966 * accessibility features are enabled 12967 * </ul> 12968 * 12969 * @param event The motion event. 12970 * @return True if the event was handled, false otherwise. 12971 */ 12972 public boolean onTouchEvent(MotionEvent event) { 12973 final float x = event.getX(); 12974 final float y = event.getY(); 12975 final int viewFlags = mViewFlags; 12976 final int action = event.getAction(); 12977 12978 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 12979 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 12980 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12981 12982 if ((viewFlags & ENABLED_MASK) == DISABLED) { 12983 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 12984 setPressed(false); 12985 } 12986 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 12987 // A disabled view that is clickable still consumes the touch 12988 // events, it just doesn't respond to them. 12989 return clickable; 12990 } 12991 if (mTouchDelegate != null) { 12992 if (mTouchDelegate.onTouchEvent(event)) { 12993 return true; 12994 } 12995 } 12996 12997 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 12998 switch (action) { 12999 case MotionEvent.ACTION_UP: 13000 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13001 if ((viewFlags & TOOLTIP) == TOOLTIP) { 13002 handleTooltipUp(); 13003 } 13004 if (!clickable) { 13005 removeTapCallback(); 13006 removeLongPressCallback(); 13007 mInContextButtonPress = false; 13008 mHasPerformedLongPress = false; 13009 mIgnoreNextUpEvent = false; 13010 break; 13011 } 13012 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 13013 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 13014 // take focus if we don't have it already and we should in 13015 // touch mode. 13016 boolean focusTaken = false; 13017 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 13018 focusTaken = requestFocus(); 13019 } 13020 13021 if (prepressed) { 13022 // The button is being released before we actually 13023 // showed it as pressed. Make it show the pressed 13024 // state now (before scheduling the click) to ensure 13025 // the user sees it. 13026 setPressed(true, x, y); 13027 } 13028 13029 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 13030 // This is a tap, so remove the longpress check 13031 removeLongPressCallback(); 13032 13033 // Only perform take click actions if we were in the pressed state 13034 if (!focusTaken) { 13035 // Use a Runnable and post this rather than calling 13036 // performClick directly. This lets other visual state 13037 // of the view update before click actions start. 13038 if (mPerformClick == null) { 13039 mPerformClick = new PerformClick(); 13040 } 13041 if (!post(mPerformClick)) { 13042 performClick(); 13043 } 13044 } 13045 } 13046 13047 if (mUnsetPressedState == null) { 13048 mUnsetPressedState = new UnsetPressedState(); 13049 } 13050 13051 if (prepressed) { 13052 postDelayed(mUnsetPressedState, 13053 ViewConfiguration.getPressedStateDuration()); 13054 } else if (!post(mUnsetPressedState)) { 13055 // If the post failed, unpress right now 13056 mUnsetPressedState.run(); 13057 } 13058 13059 removeTapCallback(); 13060 } 13061 mIgnoreNextUpEvent = false; 13062 break; 13063 13064 case MotionEvent.ACTION_DOWN: 13065 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 13066 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 13067 } 13068 mHasPerformedLongPress = false; 13069 13070 if (!clickable) { 13071 checkForLongClick(0, x, y); 13072 break; 13073 } 13074 13075 if (performButtonActionOnTouchDown(event)) { 13076 break; 13077 } 13078 13079 // Walk up the hierarchy to determine if we're inside a scrolling container. 13080 boolean isInScrollingContainer = isInScrollingContainer(); 13081 13082 // For views inside a scrolling container, delay the pressed feedback for 13083 // a short period in case this is a scroll. 13084 if (isInScrollingContainer) { 13085 mPrivateFlags |= PFLAG_PREPRESSED; 13086 if (mPendingCheckForTap == null) { 13087 mPendingCheckForTap = new CheckForTap(); 13088 } 13089 mPendingCheckForTap.x = event.getX(); 13090 mPendingCheckForTap.y = event.getY(); 13091 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 13092 } else { 13093 // Not inside a scrolling container, so show the feedback right away 13094 setPressed(true, x, y); 13095 checkForLongClick(0, x, y); 13096 } 13097 break; 13098 13099 case MotionEvent.ACTION_CANCEL: 13100 if (clickable) { 13101 setPressed(false); 13102 } 13103 removeTapCallback(); 13104 removeLongPressCallback(); 13105 mInContextButtonPress = false; 13106 mHasPerformedLongPress = false; 13107 mIgnoreNextUpEvent = false; 13108 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13109 break; 13110 13111 case MotionEvent.ACTION_MOVE: 13112 if (clickable) { 13113 drawableHotspotChanged(x, y); 13114 } 13115 13116 // Be lenient about moving outside of buttons 13117 if (!pointInView(x, y, mTouchSlop)) { 13118 // Outside button 13119 // Remove any future long press/tap checks 13120 removeTapCallback(); 13121 removeLongPressCallback(); 13122 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 13123 setPressed(false); 13124 } 13125 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13126 } 13127 break; 13128 } 13129 13130 return true; 13131 } 13132 13133 return false; 13134 } 13135 13136 /** 13137 * @hide 13138 */ 13139 public boolean isInScrollingContainer() { 13140 ViewParent p = getParent(); 13141 while (p != null && p instanceof ViewGroup) { 13142 if (((ViewGroup) p).shouldDelayChildPressedState()) { 13143 return true; 13144 } 13145 p = p.getParent(); 13146 } 13147 return false; 13148 } 13149 13150 /** 13151 * Remove the longpress detection timer. 13152 */ 13153 private void removeLongPressCallback() { 13154 if (mPendingCheckForLongPress != null) { 13155 removeCallbacks(mPendingCheckForLongPress); 13156 } 13157 } 13158 13159 /** 13160 * Remove the pending click action 13161 */ 13162 private void removePerformClickCallback() { 13163 if (mPerformClick != null) { 13164 removeCallbacks(mPerformClick); 13165 } 13166 } 13167 13168 /** 13169 * Remove the prepress detection timer. 13170 */ 13171 private void removeUnsetPressCallback() { 13172 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 13173 setPressed(false); 13174 removeCallbacks(mUnsetPressedState); 13175 } 13176 } 13177 13178 /** 13179 * Remove the tap detection timer. 13180 */ 13181 private void removeTapCallback() { 13182 if (mPendingCheckForTap != null) { 13183 mPrivateFlags &= ~PFLAG_PREPRESSED; 13184 removeCallbacks(mPendingCheckForTap); 13185 } 13186 } 13187 13188 /** 13189 * Cancels a pending long press. Your subclass can use this if you 13190 * want the context menu to come up if the user presses and holds 13191 * at the same place, but you don't want it to come up if they press 13192 * and then move around enough to cause scrolling. 13193 */ 13194 public void cancelLongPress() { 13195 removeLongPressCallback(); 13196 13197 /* 13198 * The prepressed state handled by the tap callback is a display 13199 * construct, but the tap callback will post a long press callback 13200 * less its own timeout. Remove it here. 13201 */ 13202 removeTapCallback(); 13203 } 13204 13205 /** 13206 * Remove the pending callback for sending a 13207 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 13208 */ 13209 private void removeSendViewScrolledAccessibilityEventCallback() { 13210 if (mSendViewScrolledAccessibilityEvent != null) { 13211 removeCallbacks(mSendViewScrolledAccessibilityEvent); 13212 mSendViewScrolledAccessibilityEvent.mIsPending = false; 13213 } 13214 } 13215 13216 /** 13217 * Sets the TouchDelegate for this View. 13218 */ 13219 public void setTouchDelegate(TouchDelegate delegate) { 13220 mTouchDelegate = delegate; 13221 } 13222 13223 /** 13224 * Gets the TouchDelegate for this View. 13225 */ 13226 public TouchDelegate getTouchDelegate() { 13227 return mTouchDelegate; 13228 } 13229 13230 /** 13231 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 13232 * 13233 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 13234 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 13235 * available. This method should only be called for touch events. 13236 * 13237 * <p class="note">This api is not intended for most applications. Buffered dispatch 13238 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 13239 * streams will not improve your input latency. Side effects include: increased latency, 13240 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 13241 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 13242 * you.</p> 13243 */ 13244 public final void requestUnbufferedDispatch(MotionEvent event) { 13245 final int action = event.getAction(); 13246 if (mAttachInfo == null 13247 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 13248 || !event.isTouchEvent()) { 13249 return; 13250 } 13251 mAttachInfo.mUnbufferedDispatchRequested = true; 13252 } 13253 13254 /** 13255 * Set flags controlling behavior of this view. 13256 * 13257 * @param flags Constant indicating the value which should be set 13258 * @param mask Constant indicating the bit range that should be changed 13259 */ 13260 void setFlags(int flags, int mask) { 13261 final boolean accessibilityEnabled = 13262 AccessibilityManager.getInstance(mContext).isEnabled(); 13263 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 13264 13265 int old = mViewFlags; 13266 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 13267 13268 int changed = mViewFlags ^ old; 13269 if (changed == 0) { 13270 return; 13271 } 13272 int privateFlags = mPrivateFlags; 13273 13274 // If focusable is auto, update the FOCUSABLE bit. 13275 int focusableChangedByAuto = 0; 13276 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 13277 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 13278 // Heuristic only takes into account whether view is clickable. 13279 final int newFocus; 13280 if ((mViewFlags & CLICKABLE) != 0) { 13281 newFocus = FOCUSABLE; 13282 } else { 13283 newFocus = NOT_FOCUSABLE; 13284 } 13285 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 13286 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 13287 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 13288 } 13289 13290 /* Check if the FOCUSABLE bit has changed */ 13291 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 13292 if (((old & FOCUSABLE) == FOCUSABLE) 13293 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 13294 /* Give up focus if we are no longer focusable */ 13295 clearFocus(); 13296 if (mParent instanceof ViewGroup) { 13297 ((ViewGroup) mParent).clearFocusedInCluster(); 13298 } 13299 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 13300 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 13301 /* 13302 * Tell the view system that we are now available to take focus 13303 * if no one else already has it. 13304 */ 13305 if (mParent != null) { 13306 ViewRootImpl viewRootImpl = getViewRootImpl(); 13307 if (!sAutoFocusableOffUIThreadWontNotifyParents 13308 || focusableChangedByAuto == 0 13309 || viewRootImpl == null 13310 || viewRootImpl.mThread == Thread.currentThread()) { 13311 mParent.focusableViewAvailable(this); 13312 } 13313 } 13314 } 13315 } 13316 13317 final int newVisibility = flags & VISIBILITY_MASK; 13318 if (newVisibility == VISIBLE) { 13319 if ((changed & VISIBILITY_MASK) != 0) { 13320 /* 13321 * If this view is becoming visible, invalidate it in case it changed while 13322 * it was not visible. Marking it drawn ensures that the invalidation will 13323 * go through. 13324 */ 13325 mPrivateFlags |= PFLAG_DRAWN; 13326 invalidate(true); 13327 13328 needGlobalAttributesUpdate(true); 13329 13330 // a view becoming visible is worth notifying the parent 13331 // about in case nothing has focus. even if this specific view 13332 // isn't focusable, it may contain something that is, so let 13333 // the root view try to give this focus if nothing else does. 13334 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 13335 mParent.focusableViewAvailable(this); 13336 } 13337 } 13338 } 13339 13340 /* Check if the GONE bit has changed */ 13341 if ((changed & GONE) != 0) { 13342 needGlobalAttributesUpdate(false); 13343 requestLayout(); 13344 13345 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 13346 if (hasFocus()) { 13347 clearFocus(); 13348 if (mParent instanceof ViewGroup) { 13349 ((ViewGroup) mParent).clearFocusedInCluster(); 13350 } 13351 } 13352 clearAccessibilityFocus(); 13353 destroyDrawingCache(); 13354 if (mParent instanceof View) { 13355 // GONE views noop invalidation, so invalidate the parent 13356 ((View) mParent).invalidate(true); 13357 } 13358 // Mark the view drawn to ensure that it gets invalidated properly the next 13359 // time it is visible and gets invalidated 13360 mPrivateFlags |= PFLAG_DRAWN; 13361 } 13362 if (mAttachInfo != null) { 13363 mAttachInfo.mViewVisibilityChanged = true; 13364 } 13365 } 13366 13367 /* Check if the VISIBLE bit has changed */ 13368 if ((changed & INVISIBLE) != 0) { 13369 needGlobalAttributesUpdate(false); 13370 /* 13371 * If this view is becoming invisible, set the DRAWN flag so that 13372 * the next invalidate() will not be skipped. 13373 */ 13374 mPrivateFlags |= PFLAG_DRAWN; 13375 13376 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 13377 // root view becoming invisible shouldn't clear focus and accessibility focus 13378 if (getRootView() != this) { 13379 if (hasFocus()) { 13380 clearFocus(); 13381 if (mParent instanceof ViewGroup) { 13382 ((ViewGroup) mParent).clearFocusedInCluster(); 13383 } 13384 } 13385 clearAccessibilityFocus(); 13386 } 13387 } 13388 if (mAttachInfo != null) { 13389 mAttachInfo.mViewVisibilityChanged = true; 13390 } 13391 } 13392 13393 if ((changed & VISIBILITY_MASK) != 0) { 13394 // If the view is invisible, cleanup its display list to free up resources 13395 if (newVisibility != VISIBLE && mAttachInfo != null) { 13396 cleanupDraw(); 13397 } 13398 13399 if (mParent instanceof ViewGroup) { 13400 ((ViewGroup) mParent).onChildVisibilityChanged(this, 13401 (changed & VISIBILITY_MASK), newVisibility); 13402 ((View) mParent).invalidate(true); 13403 } else if (mParent != null) { 13404 mParent.invalidateChild(this, null); 13405 } 13406 13407 if (mAttachInfo != null) { 13408 dispatchVisibilityChanged(this, newVisibility); 13409 13410 // Aggregated visibility changes are dispatched to attached views 13411 // in visible windows where the parent is currently shown/drawn 13412 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 13413 // discounting clipping or overlapping. This makes it a good place 13414 // to change animation states. 13415 if (mParent != null && getWindowVisibility() == VISIBLE && 13416 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 13417 dispatchVisibilityAggregated(newVisibility == VISIBLE); 13418 } 13419 notifySubtreeAccessibilityStateChangedIfNeeded(); 13420 } 13421 } 13422 13423 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 13424 destroyDrawingCache(); 13425 } 13426 13427 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 13428 destroyDrawingCache(); 13429 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13430 invalidateParentCaches(); 13431 } 13432 13433 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 13434 destroyDrawingCache(); 13435 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13436 } 13437 13438 if ((changed & DRAW_MASK) != 0) { 13439 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 13440 if (mBackground != null 13441 || mDefaultFocusHighlight != null 13442 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 13443 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13444 } else { 13445 mPrivateFlags |= PFLAG_SKIP_DRAW; 13446 } 13447 } else { 13448 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 13449 } 13450 requestLayout(); 13451 invalidate(true); 13452 } 13453 13454 if ((changed & KEEP_SCREEN_ON) != 0) { 13455 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 13456 mParent.recomputeViewAttributes(this); 13457 } 13458 } 13459 13460 if (accessibilityEnabled) { 13461 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 13462 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 13463 || (changed & CONTEXT_CLICKABLE) != 0) { 13464 if (oldIncludeForAccessibility != includeForAccessibility()) { 13465 notifySubtreeAccessibilityStateChangedIfNeeded(); 13466 } else { 13467 notifyViewAccessibilityStateChangedIfNeeded( 13468 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13469 } 13470 } else if ((changed & ENABLED_MASK) != 0) { 13471 notifyViewAccessibilityStateChangedIfNeeded( 13472 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13473 } 13474 } 13475 } 13476 13477 /** 13478 * Change the view's z order in the tree, so it's on top of other sibling 13479 * views. This ordering change may affect layout, if the parent container 13480 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 13481 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 13482 * method should be followed by calls to {@link #requestLayout()} and 13483 * {@link View#invalidate()} on the view's parent to force the parent to redraw 13484 * with the new child ordering. 13485 * 13486 * @see ViewGroup#bringChildToFront(View) 13487 */ 13488 public void bringToFront() { 13489 if (mParent != null) { 13490 mParent.bringChildToFront(this); 13491 } 13492 } 13493 13494 /** 13495 * This is called in response to an internal scroll in this view (i.e., the 13496 * view scrolled its own contents). This is typically as a result of 13497 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 13498 * called. 13499 * 13500 * @param l Current horizontal scroll origin. 13501 * @param t Current vertical scroll origin. 13502 * @param oldl Previous horizontal scroll origin. 13503 * @param oldt Previous vertical scroll origin. 13504 */ 13505 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 13506 notifySubtreeAccessibilityStateChangedIfNeeded(); 13507 13508 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13509 postSendViewScrolledAccessibilityEventCallback(); 13510 } 13511 13512 mBackgroundSizeChanged = true; 13513 mDefaultFocusHighlightSizeChanged = true; 13514 if (mForegroundInfo != null) { 13515 mForegroundInfo.mBoundsChanged = true; 13516 } 13517 13518 final AttachInfo ai = mAttachInfo; 13519 if (ai != null) { 13520 ai.mViewScrollChanged = true; 13521 } 13522 13523 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 13524 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 13525 } 13526 } 13527 13528 /** 13529 * Interface definition for a callback to be invoked when the scroll 13530 * X or Y positions of a view change. 13531 * <p> 13532 * <b>Note:</b> Some views handle scrolling independently from View and may 13533 * have their own separate listeners for scroll-type events. For example, 13534 * {@link android.widget.ListView ListView} allows clients to register an 13535 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 13536 * to listen for changes in list scroll position. 13537 * 13538 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 13539 */ 13540 public interface OnScrollChangeListener { 13541 /** 13542 * Called when the scroll position of a view changes. 13543 * 13544 * @param v The view whose scroll position has changed. 13545 * @param scrollX Current horizontal scroll origin. 13546 * @param scrollY Current vertical scroll origin. 13547 * @param oldScrollX Previous horizontal scroll origin. 13548 * @param oldScrollY Previous vertical scroll origin. 13549 */ 13550 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 13551 } 13552 13553 /** 13554 * Interface definition for a callback to be invoked when the layout bounds of a view 13555 * changes due to layout processing. 13556 */ 13557 public interface OnLayoutChangeListener { 13558 /** 13559 * Called when the layout bounds of a view changes due to layout processing. 13560 * 13561 * @param v The view whose bounds have changed. 13562 * @param left The new value of the view's left property. 13563 * @param top The new value of the view's top property. 13564 * @param right The new value of the view's right property. 13565 * @param bottom The new value of the view's bottom property. 13566 * @param oldLeft The previous value of the view's left property. 13567 * @param oldTop The previous value of the view's top property. 13568 * @param oldRight The previous value of the view's right property. 13569 * @param oldBottom The previous value of the view's bottom property. 13570 */ 13571 void onLayoutChange(View v, int left, int top, int right, int bottom, 13572 int oldLeft, int oldTop, int oldRight, int oldBottom); 13573 } 13574 13575 /** 13576 * This is called during layout when the size of this view has changed. If 13577 * you were just added to the view hierarchy, you're called with the old 13578 * values of 0. 13579 * 13580 * @param w Current width of this view. 13581 * @param h Current height of this view. 13582 * @param oldw Old width of this view. 13583 * @param oldh Old height of this view. 13584 */ 13585 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 13586 } 13587 13588 /** 13589 * Called by draw to draw the child views. This may be overridden 13590 * by derived classes to gain control just before its children are drawn 13591 * (but after its own view has been drawn). 13592 * @param canvas the canvas on which to draw the view 13593 */ 13594 protected void dispatchDraw(Canvas canvas) { 13595 13596 } 13597 13598 /** 13599 * Gets the parent of this view. Note that the parent is a 13600 * ViewParent and not necessarily a View. 13601 * 13602 * @return Parent of this view. 13603 */ 13604 public final ViewParent getParent() { 13605 return mParent; 13606 } 13607 13608 /** 13609 * Set the horizontal scrolled position of your view. This will cause a call to 13610 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13611 * invalidated. 13612 * @param value the x position to scroll to 13613 */ 13614 public void setScrollX(int value) { 13615 scrollTo(value, mScrollY); 13616 } 13617 13618 /** 13619 * Set the vertical scrolled position of your view. This will cause a call to 13620 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13621 * invalidated. 13622 * @param value the y position to scroll to 13623 */ 13624 public void setScrollY(int value) { 13625 scrollTo(mScrollX, value); 13626 } 13627 13628 /** 13629 * Return the scrolled left position of this view. This is the left edge of 13630 * the displayed part of your view. You do not need to draw any pixels 13631 * farther left, since those are outside of the frame of your view on 13632 * screen. 13633 * 13634 * @return The left edge of the displayed part of your view, in pixels. 13635 */ 13636 public final int getScrollX() { 13637 return mScrollX; 13638 } 13639 13640 /** 13641 * Return the scrolled top position of this view. This is the top edge of 13642 * the displayed part of your view. You do not need to draw any pixels above 13643 * it, since those are outside of the frame of your view on screen. 13644 * 13645 * @return The top edge of the displayed part of your view, in pixels. 13646 */ 13647 public final int getScrollY() { 13648 return mScrollY; 13649 } 13650 13651 /** 13652 * Return the width of the your view. 13653 * 13654 * @return The width of your view, in pixels. 13655 */ 13656 @ViewDebug.ExportedProperty(category = "layout") 13657 public final int getWidth() { 13658 return mRight - mLeft; 13659 } 13660 13661 /** 13662 * Return the height of your view. 13663 * 13664 * @return The height of your view, in pixels. 13665 */ 13666 @ViewDebug.ExportedProperty(category = "layout") 13667 public final int getHeight() { 13668 return mBottom - mTop; 13669 } 13670 13671 /** 13672 * Return the visible drawing bounds of your view. Fills in the output 13673 * rectangle with the values from getScrollX(), getScrollY(), 13674 * getWidth(), and getHeight(). These bounds do not account for any 13675 * transformation properties currently set on the view, such as 13676 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 13677 * 13678 * @param outRect The (scrolled) drawing bounds of the view. 13679 */ 13680 public void getDrawingRect(Rect outRect) { 13681 outRect.left = mScrollX; 13682 outRect.top = mScrollY; 13683 outRect.right = mScrollX + (mRight - mLeft); 13684 outRect.bottom = mScrollY + (mBottom - mTop); 13685 } 13686 13687 /** 13688 * Like {@link #getMeasuredWidthAndState()}, but only returns the 13689 * raw width component (that is the result is masked by 13690 * {@link #MEASURED_SIZE_MASK}). 13691 * 13692 * @return The raw measured width of this view. 13693 */ 13694 public final int getMeasuredWidth() { 13695 return mMeasuredWidth & MEASURED_SIZE_MASK; 13696 } 13697 13698 /** 13699 * Return the full width measurement information for this view as computed 13700 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13701 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13702 * This should be used during measurement and layout calculations only. Use 13703 * {@link #getWidth()} to see how wide a view is after layout. 13704 * 13705 * @return The measured width of this view as a bit mask. 13706 */ 13707 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13708 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13709 name = "MEASURED_STATE_TOO_SMALL"), 13710 }) 13711 public final int getMeasuredWidthAndState() { 13712 return mMeasuredWidth; 13713 } 13714 13715 /** 13716 * Like {@link #getMeasuredHeightAndState()}, but only returns the 13717 * raw height component (that is the result is masked by 13718 * {@link #MEASURED_SIZE_MASK}). 13719 * 13720 * @return The raw measured height of this view. 13721 */ 13722 public final int getMeasuredHeight() { 13723 return mMeasuredHeight & MEASURED_SIZE_MASK; 13724 } 13725 13726 /** 13727 * Return the full height measurement information for this view as computed 13728 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 13729 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 13730 * This should be used during measurement and layout calculations only. Use 13731 * {@link #getHeight()} to see how wide a view is after layout. 13732 * 13733 * @return The measured height of this view as a bit mask. 13734 */ 13735 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 13736 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 13737 name = "MEASURED_STATE_TOO_SMALL"), 13738 }) 13739 public final int getMeasuredHeightAndState() { 13740 return mMeasuredHeight; 13741 } 13742 13743 /** 13744 * Return only the state bits of {@link #getMeasuredWidthAndState()} 13745 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 13746 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 13747 * and the height component is at the shifted bits 13748 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 13749 */ 13750 public final int getMeasuredState() { 13751 return (mMeasuredWidth&MEASURED_STATE_MASK) 13752 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 13753 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 13754 } 13755 13756 /** 13757 * The transform matrix of this view, which is calculated based on the current 13758 * rotation, scale, and pivot properties. 13759 * 13760 * @see #getRotation() 13761 * @see #getScaleX() 13762 * @see #getScaleY() 13763 * @see #getPivotX() 13764 * @see #getPivotY() 13765 * @return The current transform matrix for the view 13766 */ 13767 public Matrix getMatrix() { 13768 ensureTransformationInfo(); 13769 final Matrix matrix = mTransformationInfo.mMatrix; 13770 mRenderNode.getMatrix(matrix); 13771 return matrix; 13772 } 13773 13774 /** 13775 * Returns true if the transform matrix is the identity matrix. 13776 * Recomputes the matrix if necessary. 13777 * 13778 * @return True if the transform matrix is the identity matrix, false otherwise. 13779 */ 13780 final boolean hasIdentityMatrix() { 13781 return mRenderNode.hasIdentityMatrix(); 13782 } 13783 13784 void ensureTransformationInfo() { 13785 if (mTransformationInfo == null) { 13786 mTransformationInfo = new TransformationInfo(); 13787 } 13788 } 13789 13790 /** 13791 * Utility method to retrieve the inverse of the current mMatrix property. 13792 * We cache the matrix to avoid recalculating it when transform properties 13793 * have not changed. 13794 * 13795 * @return The inverse of the current matrix of this view. 13796 * @hide 13797 */ 13798 public final Matrix getInverseMatrix() { 13799 ensureTransformationInfo(); 13800 if (mTransformationInfo.mInverseMatrix == null) { 13801 mTransformationInfo.mInverseMatrix = new Matrix(); 13802 } 13803 final Matrix matrix = mTransformationInfo.mInverseMatrix; 13804 mRenderNode.getInverseMatrix(matrix); 13805 return matrix; 13806 } 13807 13808 /** 13809 * Gets the distance along the Z axis from the camera to this view. 13810 * 13811 * @see #setCameraDistance(float) 13812 * 13813 * @return The distance along the Z axis. 13814 */ 13815 public float getCameraDistance() { 13816 final float dpi = mResources.getDisplayMetrics().densityDpi; 13817 return -(mRenderNode.getCameraDistance() * dpi); 13818 } 13819 13820 /** 13821 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 13822 * views are drawn) from the camera to this view. The camera's distance 13823 * affects 3D transformations, for instance rotations around the X and Y 13824 * axis. If the rotationX or rotationY properties are changed and this view is 13825 * large (more than half the size of the screen), it is recommended to always 13826 * use a camera distance that's greater than the height (X axis rotation) or 13827 * the width (Y axis rotation) of this view.</p> 13828 * 13829 * <p>The distance of the camera from the view plane can have an affect on the 13830 * perspective distortion of the view when it is rotated around the x or y axis. 13831 * For example, a large distance will result in a large viewing angle, and there 13832 * will not be much perspective distortion of the view as it rotates. A short 13833 * distance may cause much more perspective distortion upon rotation, and can 13834 * also result in some drawing artifacts if the rotated view ends up partially 13835 * behind the camera (which is why the recommendation is to use a distance at 13836 * least as far as the size of the view, if the view is to be rotated.)</p> 13837 * 13838 * <p>The distance is expressed in "depth pixels." The default distance depends 13839 * on the screen density. For instance, on a medium density display, the 13840 * default distance is 1280. On a high density display, the default distance 13841 * is 1920.</p> 13842 * 13843 * <p>If you want to specify a distance that leads to visually consistent 13844 * results across various densities, use the following formula:</p> 13845 * <pre> 13846 * float scale = context.getResources().getDisplayMetrics().density; 13847 * view.setCameraDistance(distance * scale); 13848 * </pre> 13849 * 13850 * <p>The density scale factor of a high density display is 1.5, 13851 * and 1920 = 1280 * 1.5.</p> 13852 * 13853 * @param distance The distance in "depth pixels", if negative the opposite 13854 * value is used 13855 * 13856 * @see #setRotationX(float) 13857 * @see #setRotationY(float) 13858 */ 13859 public void setCameraDistance(float distance) { 13860 final float dpi = mResources.getDisplayMetrics().densityDpi; 13861 13862 invalidateViewProperty(true, false); 13863 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 13864 invalidateViewProperty(false, false); 13865 13866 invalidateParentIfNeededAndWasQuickRejected(); 13867 } 13868 13869 /** 13870 * The degrees that the view is rotated around the pivot point. 13871 * 13872 * @see #setRotation(float) 13873 * @see #getPivotX() 13874 * @see #getPivotY() 13875 * 13876 * @return The degrees of rotation. 13877 */ 13878 @ViewDebug.ExportedProperty(category = "drawing") 13879 public float getRotation() { 13880 return mRenderNode.getRotation(); 13881 } 13882 13883 /** 13884 * Sets the degrees that the view is rotated around the pivot point. Increasing values 13885 * result in clockwise rotation. 13886 * 13887 * @param rotation The degrees of rotation. 13888 * 13889 * @see #getRotation() 13890 * @see #getPivotX() 13891 * @see #getPivotY() 13892 * @see #setRotationX(float) 13893 * @see #setRotationY(float) 13894 * 13895 * @attr ref android.R.styleable#View_rotation 13896 */ 13897 public void setRotation(float rotation) { 13898 if (rotation != getRotation()) { 13899 // Double-invalidation is necessary to capture view's old and new areas 13900 invalidateViewProperty(true, false); 13901 mRenderNode.setRotation(rotation); 13902 invalidateViewProperty(false, true); 13903 13904 invalidateParentIfNeededAndWasQuickRejected(); 13905 notifySubtreeAccessibilityStateChangedIfNeeded(); 13906 } 13907 } 13908 13909 /** 13910 * The degrees that the view is rotated around the vertical axis through the pivot point. 13911 * 13912 * @see #getPivotX() 13913 * @see #getPivotY() 13914 * @see #setRotationY(float) 13915 * 13916 * @return The degrees of Y rotation. 13917 */ 13918 @ViewDebug.ExportedProperty(category = "drawing") 13919 public float getRotationY() { 13920 return mRenderNode.getRotationY(); 13921 } 13922 13923 /** 13924 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 13925 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 13926 * down the y axis. 13927 * 13928 * When rotating large views, it is recommended to adjust the camera distance 13929 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13930 * 13931 * @param rotationY The degrees of Y rotation. 13932 * 13933 * @see #getRotationY() 13934 * @see #getPivotX() 13935 * @see #getPivotY() 13936 * @see #setRotation(float) 13937 * @see #setRotationX(float) 13938 * @see #setCameraDistance(float) 13939 * 13940 * @attr ref android.R.styleable#View_rotationY 13941 */ 13942 public void setRotationY(float rotationY) { 13943 if (rotationY != getRotationY()) { 13944 invalidateViewProperty(true, false); 13945 mRenderNode.setRotationY(rotationY); 13946 invalidateViewProperty(false, true); 13947 13948 invalidateParentIfNeededAndWasQuickRejected(); 13949 notifySubtreeAccessibilityStateChangedIfNeeded(); 13950 } 13951 } 13952 13953 /** 13954 * The degrees that the view is rotated around the horizontal axis through the pivot point. 13955 * 13956 * @see #getPivotX() 13957 * @see #getPivotY() 13958 * @see #setRotationX(float) 13959 * 13960 * @return The degrees of X rotation. 13961 */ 13962 @ViewDebug.ExportedProperty(category = "drawing") 13963 public float getRotationX() { 13964 return mRenderNode.getRotationX(); 13965 } 13966 13967 /** 13968 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 13969 * Increasing values result in clockwise rotation from the viewpoint of looking down the 13970 * x axis. 13971 * 13972 * When rotating large views, it is recommended to adjust the camera distance 13973 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 13974 * 13975 * @param rotationX The degrees of X rotation. 13976 * 13977 * @see #getRotationX() 13978 * @see #getPivotX() 13979 * @see #getPivotY() 13980 * @see #setRotation(float) 13981 * @see #setRotationY(float) 13982 * @see #setCameraDistance(float) 13983 * 13984 * @attr ref android.R.styleable#View_rotationX 13985 */ 13986 public void setRotationX(float rotationX) { 13987 if (rotationX != getRotationX()) { 13988 invalidateViewProperty(true, false); 13989 mRenderNode.setRotationX(rotationX); 13990 invalidateViewProperty(false, true); 13991 13992 invalidateParentIfNeededAndWasQuickRejected(); 13993 notifySubtreeAccessibilityStateChangedIfNeeded(); 13994 } 13995 } 13996 13997 /** 13998 * The amount that the view is scaled in x around the pivot point, as a proportion of 13999 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 14000 * 14001 * <p>By default, this is 1.0f. 14002 * 14003 * @see #getPivotX() 14004 * @see #getPivotY() 14005 * @return The scaling factor. 14006 */ 14007 @ViewDebug.ExportedProperty(category = "drawing") 14008 public float getScaleX() { 14009 return mRenderNode.getScaleX(); 14010 } 14011 14012 /** 14013 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 14014 * the view's unscaled width. A value of 1 means that no scaling is applied. 14015 * 14016 * @param scaleX The scaling factor. 14017 * @see #getPivotX() 14018 * @see #getPivotY() 14019 * 14020 * @attr ref android.R.styleable#View_scaleX 14021 */ 14022 public void setScaleX(float scaleX) { 14023 if (scaleX != getScaleX()) { 14024 invalidateViewProperty(true, false); 14025 mRenderNode.setScaleX(scaleX); 14026 invalidateViewProperty(false, true); 14027 14028 invalidateParentIfNeededAndWasQuickRejected(); 14029 notifySubtreeAccessibilityStateChangedIfNeeded(); 14030 } 14031 } 14032 14033 /** 14034 * The amount that the view is scaled in y around the pivot point, as a proportion of 14035 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 14036 * 14037 * <p>By default, this is 1.0f. 14038 * 14039 * @see #getPivotX() 14040 * @see #getPivotY() 14041 * @return The scaling factor. 14042 */ 14043 @ViewDebug.ExportedProperty(category = "drawing") 14044 public float getScaleY() { 14045 return mRenderNode.getScaleY(); 14046 } 14047 14048 /** 14049 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 14050 * the view's unscaled width. A value of 1 means that no scaling is applied. 14051 * 14052 * @param scaleY The scaling factor. 14053 * @see #getPivotX() 14054 * @see #getPivotY() 14055 * 14056 * @attr ref android.R.styleable#View_scaleY 14057 */ 14058 public void setScaleY(float scaleY) { 14059 if (scaleY != getScaleY()) { 14060 invalidateViewProperty(true, false); 14061 mRenderNode.setScaleY(scaleY); 14062 invalidateViewProperty(false, true); 14063 14064 invalidateParentIfNeededAndWasQuickRejected(); 14065 notifySubtreeAccessibilityStateChangedIfNeeded(); 14066 } 14067 } 14068 14069 /** 14070 * The x location of the point around which the view is {@link #setRotation(float) rotated} 14071 * and {@link #setScaleX(float) scaled}. 14072 * 14073 * @see #getRotation() 14074 * @see #getScaleX() 14075 * @see #getScaleY() 14076 * @see #getPivotY() 14077 * @return The x location of the pivot point. 14078 * 14079 * @attr ref android.R.styleable#View_transformPivotX 14080 */ 14081 @ViewDebug.ExportedProperty(category = "drawing") 14082 public float getPivotX() { 14083 return mRenderNode.getPivotX(); 14084 } 14085 14086 /** 14087 * Sets the x location of the point around which the view is 14088 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 14089 * By default, the pivot point is centered on the object. 14090 * Setting this property disables this behavior and causes the view to use only the 14091 * explicitly set pivotX and pivotY values. 14092 * 14093 * @param pivotX The x location of the pivot point. 14094 * @see #getRotation() 14095 * @see #getScaleX() 14096 * @see #getScaleY() 14097 * @see #getPivotY() 14098 * 14099 * @attr ref android.R.styleable#View_transformPivotX 14100 */ 14101 public void setPivotX(float pivotX) { 14102 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 14103 invalidateViewProperty(true, false); 14104 mRenderNode.setPivotX(pivotX); 14105 invalidateViewProperty(false, true); 14106 14107 invalidateParentIfNeededAndWasQuickRejected(); 14108 } 14109 } 14110 14111 /** 14112 * The y location of the point around which the view is {@link #setRotation(float) rotated} 14113 * and {@link #setScaleY(float) scaled}. 14114 * 14115 * @see #getRotation() 14116 * @see #getScaleX() 14117 * @see #getScaleY() 14118 * @see #getPivotY() 14119 * @return The y location of the pivot point. 14120 * 14121 * @attr ref android.R.styleable#View_transformPivotY 14122 */ 14123 @ViewDebug.ExportedProperty(category = "drawing") 14124 public float getPivotY() { 14125 return mRenderNode.getPivotY(); 14126 } 14127 14128 /** 14129 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 14130 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 14131 * Setting this property disables this behavior and causes the view to use only the 14132 * explicitly set pivotX and pivotY values. 14133 * 14134 * @param pivotY The y location of the pivot point. 14135 * @see #getRotation() 14136 * @see #getScaleX() 14137 * @see #getScaleY() 14138 * @see #getPivotY() 14139 * 14140 * @attr ref android.R.styleable#View_transformPivotY 14141 */ 14142 public void setPivotY(float pivotY) { 14143 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 14144 invalidateViewProperty(true, false); 14145 mRenderNode.setPivotY(pivotY); 14146 invalidateViewProperty(false, true); 14147 14148 invalidateParentIfNeededAndWasQuickRejected(); 14149 } 14150 } 14151 14152 /** 14153 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 14154 * completely transparent and 1 means the view is completely opaque. 14155 * 14156 * <p>By default this is 1.0f. 14157 * @return The opacity of the view. 14158 */ 14159 @ViewDebug.ExportedProperty(category = "drawing") 14160 public float getAlpha() { 14161 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 14162 } 14163 14164 /** 14165 * Sets the behavior for overlapping rendering for this view (see {@link 14166 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 14167 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 14168 * providing the value which is then used internally. That is, when {@link 14169 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 14170 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 14171 * instead. 14172 * 14173 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 14174 * instead of that returned by {@link #hasOverlappingRendering()}. 14175 * 14176 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 14177 */ 14178 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 14179 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 14180 if (hasOverlappingRendering) { 14181 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14182 } else { 14183 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 14184 } 14185 } 14186 14187 /** 14188 * Returns the value for overlapping rendering that is used internally. This is either 14189 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 14190 * the return value of {@link #hasOverlappingRendering()}, otherwise. 14191 * 14192 * @return The value for overlapping rendering being used internally. 14193 */ 14194 public final boolean getHasOverlappingRendering() { 14195 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 14196 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 14197 hasOverlappingRendering(); 14198 } 14199 14200 /** 14201 * Returns whether this View has content which overlaps. 14202 * 14203 * <p>This function, intended to be overridden by specific View types, is an optimization when 14204 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 14205 * an offscreen buffer and then composited into place, which can be expensive. If the view has 14206 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 14207 * directly. An example of overlapping rendering is a TextView with a background image, such as 14208 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 14209 * ImageView with only the foreground image. The default implementation returns true; subclasses 14210 * should override if they have cases which can be optimized.</p> 14211 * 14212 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 14213 * necessitates that a View return true if it uses the methods internally without passing the 14214 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 14215 * 14216 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 14217 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 14218 * 14219 * @return true if the content in this view might overlap, false otherwise. 14220 */ 14221 @ViewDebug.ExportedProperty(category = "drawing") 14222 public boolean hasOverlappingRendering() { 14223 return true; 14224 } 14225 14226 /** 14227 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 14228 * completely transparent and 1 means the view is completely opaque. 14229 * 14230 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 14231 * can have significant performance implications, especially for large views. It is best to use 14232 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 14233 * 14234 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 14235 * strongly recommended for performance reasons to either override 14236 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 14237 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 14238 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 14239 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 14240 * of rendering cost, even for simple or small views. Starting with 14241 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 14242 * applied to the view at the rendering level.</p> 14243 * 14244 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 14245 * responsible for applying the opacity itself.</p> 14246 * 14247 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 14248 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 14249 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 14250 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 14251 * 14252 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 14253 * value will clip a View to its bounds, unless the View returns <code>false</code> from 14254 * {@link #hasOverlappingRendering}.</p> 14255 * 14256 * @param alpha The opacity of the view. 14257 * 14258 * @see #hasOverlappingRendering() 14259 * @see #setLayerType(int, android.graphics.Paint) 14260 * 14261 * @attr ref android.R.styleable#View_alpha 14262 */ 14263 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 14264 ensureTransformationInfo(); 14265 if (mTransformationInfo.mAlpha != alpha) { 14266 // Report visibility changes, which can affect children, to accessibility 14267 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 14268 notifySubtreeAccessibilityStateChangedIfNeeded(); 14269 } 14270 mTransformationInfo.mAlpha = alpha; 14271 if (onSetAlpha((int) (alpha * 255))) { 14272 mPrivateFlags |= PFLAG_ALPHA_SET; 14273 // subclass is handling alpha - don't optimize rendering cache invalidation 14274 invalidateParentCaches(); 14275 invalidate(true); 14276 } else { 14277 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14278 invalidateViewProperty(true, false); 14279 mRenderNode.setAlpha(getFinalAlpha()); 14280 } 14281 } 14282 } 14283 14284 /** 14285 * Faster version of setAlpha() which performs the same steps except there are 14286 * no calls to invalidate(). The caller of this function should perform proper invalidation 14287 * on the parent and this object. The return value indicates whether the subclass handles 14288 * alpha (the return value for onSetAlpha()). 14289 * 14290 * @param alpha The new value for the alpha property 14291 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 14292 * the new value for the alpha property is different from the old value 14293 */ 14294 boolean setAlphaNoInvalidation(float alpha) { 14295 ensureTransformationInfo(); 14296 if (mTransformationInfo.mAlpha != alpha) { 14297 mTransformationInfo.mAlpha = alpha; 14298 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 14299 if (subclassHandlesAlpha) { 14300 mPrivateFlags |= PFLAG_ALPHA_SET; 14301 return true; 14302 } else { 14303 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14304 mRenderNode.setAlpha(getFinalAlpha()); 14305 } 14306 } 14307 return false; 14308 } 14309 14310 /** 14311 * This property is hidden and intended only for use by the Fade transition, which 14312 * animates it to produce a visual translucency that does not side-effect (or get 14313 * affected by) the real alpha property. This value is composited with the other 14314 * alpha value (and the AlphaAnimation value, when that is present) to produce 14315 * a final visual translucency result, which is what is passed into the DisplayList. 14316 * 14317 * @hide 14318 */ 14319 public void setTransitionAlpha(float alpha) { 14320 ensureTransformationInfo(); 14321 if (mTransformationInfo.mTransitionAlpha != alpha) { 14322 mTransformationInfo.mTransitionAlpha = alpha; 14323 mPrivateFlags &= ~PFLAG_ALPHA_SET; 14324 invalidateViewProperty(true, false); 14325 mRenderNode.setAlpha(getFinalAlpha()); 14326 } 14327 } 14328 14329 /** 14330 * Calculates the visual alpha of this view, which is a combination of the actual 14331 * alpha value and the transitionAlpha value (if set). 14332 */ 14333 private float getFinalAlpha() { 14334 if (mTransformationInfo != null) { 14335 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 14336 } 14337 return 1; 14338 } 14339 14340 /** 14341 * This property is hidden and intended only for use by the Fade transition, which 14342 * animates it to produce a visual translucency that does not side-effect (or get 14343 * affected by) the real alpha property. This value is composited with the other 14344 * alpha value (and the AlphaAnimation value, when that is present) to produce 14345 * a final visual translucency result, which is what is passed into the DisplayList. 14346 * 14347 * @hide 14348 */ 14349 @ViewDebug.ExportedProperty(category = "drawing") 14350 public float getTransitionAlpha() { 14351 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 14352 } 14353 14354 /** 14355 * Top position of this view relative to its parent. 14356 * 14357 * @return The top of this view, in pixels. 14358 */ 14359 @ViewDebug.CapturedViewProperty 14360 public final int getTop() { 14361 return mTop; 14362 } 14363 14364 /** 14365 * Sets the top position of this view relative to its parent. This method is meant to be called 14366 * by the layout system and should not generally be called otherwise, because the property 14367 * may be changed at any time by the layout. 14368 * 14369 * @param top The top of this view, in pixels. 14370 */ 14371 public final void setTop(int top) { 14372 if (top != mTop) { 14373 final boolean matrixIsIdentity = hasIdentityMatrix(); 14374 if (matrixIsIdentity) { 14375 if (mAttachInfo != null) { 14376 int minTop; 14377 int yLoc; 14378 if (top < mTop) { 14379 minTop = top; 14380 yLoc = top - mTop; 14381 } else { 14382 minTop = mTop; 14383 yLoc = 0; 14384 } 14385 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 14386 } 14387 } else { 14388 // Double-invalidation is necessary to capture view's old and new areas 14389 invalidate(true); 14390 } 14391 14392 int width = mRight - mLeft; 14393 int oldHeight = mBottom - mTop; 14394 14395 mTop = top; 14396 mRenderNode.setTop(mTop); 14397 14398 sizeChange(width, mBottom - mTop, width, oldHeight); 14399 14400 if (!matrixIsIdentity) { 14401 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14402 invalidate(true); 14403 } 14404 mBackgroundSizeChanged = true; 14405 mDefaultFocusHighlightSizeChanged = true; 14406 if (mForegroundInfo != null) { 14407 mForegroundInfo.mBoundsChanged = true; 14408 } 14409 invalidateParentIfNeeded(); 14410 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14411 // View was rejected last time it was drawn by its parent; this may have changed 14412 invalidateParentIfNeeded(); 14413 } 14414 } 14415 } 14416 14417 /** 14418 * Bottom position of this view relative to its parent. 14419 * 14420 * @return The bottom of this view, in pixels. 14421 */ 14422 @ViewDebug.CapturedViewProperty 14423 public final int getBottom() { 14424 return mBottom; 14425 } 14426 14427 /** 14428 * True if this view has changed since the last time being drawn. 14429 * 14430 * @return The dirty state of this view. 14431 */ 14432 public boolean isDirty() { 14433 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 14434 } 14435 14436 /** 14437 * Sets the bottom position of this view relative to its parent. This method is meant to be 14438 * called by the layout system and should not generally be called otherwise, because the 14439 * property may be changed at any time by the layout. 14440 * 14441 * @param bottom The bottom of this view, in pixels. 14442 */ 14443 public final void setBottom(int bottom) { 14444 if (bottom != mBottom) { 14445 final boolean matrixIsIdentity = hasIdentityMatrix(); 14446 if (matrixIsIdentity) { 14447 if (mAttachInfo != null) { 14448 int maxBottom; 14449 if (bottom < mBottom) { 14450 maxBottom = mBottom; 14451 } else { 14452 maxBottom = bottom; 14453 } 14454 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 14455 } 14456 } else { 14457 // Double-invalidation is necessary to capture view's old and new areas 14458 invalidate(true); 14459 } 14460 14461 int width = mRight - mLeft; 14462 int oldHeight = mBottom - mTop; 14463 14464 mBottom = bottom; 14465 mRenderNode.setBottom(mBottom); 14466 14467 sizeChange(width, mBottom - mTop, width, oldHeight); 14468 14469 if (!matrixIsIdentity) { 14470 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14471 invalidate(true); 14472 } 14473 mBackgroundSizeChanged = true; 14474 mDefaultFocusHighlightSizeChanged = true; 14475 if (mForegroundInfo != null) { 14476 mForegroundInfo.mBoundsChanged = true; 14477 } 14478 invalidateParentIfNeeded(); 14479 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14480 // View was rejected last time it was drawn by its parent; this may have changed 14481 invalidateParentIfNeeded(); 14482 } 14483 } 14484 } 14485 14486 /** 14487 * Left position of this view relative to its parent. 14488 * 14489 * @return The left edge of this view, in pixels. 14490 */ 14491 @ViewDebug.CapturedViewProperty 14492 public final int getLeft() { 14493 return mLeft; 14494 } 14495 14496 /** 14497 * Sets the left position of this view relative to its parent. This method is meant to be called 14498 * by the layout system and should not generally be called otherwise, because the property 14499 * may be changed at any time by the layout. 14500 * 14501 * @param left The left of this view, in pixels. 14502 */ 14503 public final void setLeft(int left) { 14504 if (left != mLeft) { 14505 final boolean matrixIsIdentity = hasIdentityMatrix(); 14506 if (matrixIsIdentity) { 14507 if (mAttachInfo != null) { 14508 int minLeft; 14509 int xLoc; 14510 if (left < mLeft) { 14511 minLeft = left; 14512 xLoc = left - mLeft; 14513 } else { 14514 minLeft = mLeft; 14515 xLoc = 0; 14516 } 14517 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 14518 } 14519 } else { 14520 // Double-invalidation is necessary to capture view's old and new areas 14521 invalidate(true); 14522 } 14523 14524 int oldWidth = mRight - mLeft; 14525 int height = mBottom - mTop; 14526 14527 mLeft = left; 14528 mRenderNode.setLeft(left); 14529 14530 sizeChange(mRight - mLeft, height, oldWidth, height); 14531 14532 if (!matrixIsIdentity) { 14533 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14534 invalidate(true); 14535 } 14536 mBackgroundSizeChanged = true; 14537 mDefaultFocusHighlightSizeChanged = true; 14538 if (mForegroundInfo != null) { 14539 mForegroundInfo.mBoundsChanged = true; 14540 } 14541 invalidateParentIfNeeded(); 14542 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14543 // View was rejected last time it was drawn by its parent; this may have changed 14544 invalidateParentIfNeeded(); 14545 } 14546 } 14547 } 14548 14549 /** 14550 * Right position of this view relative to its parent. 14551 * 14552 * @return The right edge of this view, in pixels. 14553 */ 14554 @ViewDebug.CapturedViewProperty 14555 public final int getRight() { 14556 return mRight; 14557 } 14558 14559 /** 14560 * Sets the right position of this view relative to its parent. This method is meant to be called 14561 * by the layout system and should not generally be called otherwise, because the property 14562 * may be changed at any time by the layout. 14563 * 14564 * @param right The right of this view, in pixels. 14565 */ 14566 public final void setRight(int right) { 14567 if (right != mRight) { 14568 final boolean matrixIsIdentity = hasIdentityMatrix(); 14569 if (matrixIsIdentity) { 14570 if (mAttachInfo != null) { 14571 int maxRight; 14572 if (right < mRight) { 14573 maxRight = mRight; 14574 } else { 14575 maxRight = right; 14576 } 14577 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 14578 } 14579 } else { 14580 // Double-invalidation is necessary to capture view's old and new areas 14581 invalidate(true); 14582 } 14583 14584 int oldWidth = mRight - mLeft; 14585 int height = mBottom - mTop; 14586 14587 mRight = right; 14588 mRenderNode.setRight(mRight); 14589 14590 sizeChange(mRight - mLeft, height, oldWidth, height); 14591 14592 if (!matrixIsIdentity) { 14593 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 14594 invalidate(true); 14595 } 14596 mBackgroundSizeChanged = true; 14597 mDefaultFocusHighlightSizeChanged = true; 14598 if (mForegroundInfo != null) { 14599 mForegroundInfo.mBoundsChanged = true; 14600 } 14601 invalidateParentIfNeeded(); 14602 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 14603 // View was rejected last time it was drawn by its parent; this may have changed 14604 invalidateParentIfNeeded(); 14605 } 14606 } 14607 } 14608 14609 /** 14610 * The visual x position of this view, in pixels. This is equivalent to the 14611 * {@link #setTranslationX(float) translationX} property plus the current 14612 * {@link #getLeft() left} property. 14613 * 14614 * @return The visual x position of this view, in pixels. 14615 */ 14616 @ViewDebug.ExportedProperty(category = "drawing") 14617 public float getX() { 14618 return mLeft + getTranslationX(); 14619 } 14620 14621 /** 14622 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 14623 * {@link #setTranslationX(float) translationX} property to be the difference between 14624 * the x value passed in and the current {@link #getLeft() left} property. 14625 * 14626 * @param x The visual x position of this view, in pixels. 14627 */ 14628 public void setX(float x) { 14629 setTranslationX(x - mLeft); 14630 } 14631 14632 /** 14633 * The visual y position of this view, in pixels. This is equivalent to the 14634 * {@link #setTranslationY(float) translationY} property plus the current 14635 * {@link #getTop() top} property. 14636 * 14637 * @return The visual y position of this view, in pixels. 14638 */ 14639 @ViewDebug.ExportedProperty(category = "drawing") 14640 public float getY() { 14641 return mTop + getTranslationY(); 14642 } 14643 14644 /** 14645 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 14646 * {@link #setTranslationY(float) translationY} property to be the difference between 14647 * the y value passed in and the current {@link #getTop() top} property. 14648 * 14649 * @param y The visual y position of this view, in pixels. 14650 */ 14651 public void setY(float y) { 14652 setTranslationY(y - mTop); 14653 } 14654 14655 /** 14656 * The visual z position of this view, in pixels. This is equivalent to the 14657 * {@link #setTranslationZ(float) translationZ} property plus the current 14658 * {@link #getElevation() elevation} property. 14659 * 14660 * @return The visual z position of this view, in pixels. 14661 */ 14662 @ViewDebug.ExportedProperty(category = "drawing") 14663 public float getZ() { 14664 return getElevation() + getTranslationZ(); 14665 } 14666 14667 /** 14668 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 14669 * {@link #setTranslationZ(float) translationZ} property to be the difference between 14670 * the x value passed in and the current {@link #getElevation() elevation} property. 14671 * 14672 * @param z The visual z position of this view, in pixels. 14673 */ 14674 public void setZ(float z) { 14675 setTranslationZ(z - getElevation()); 14676 } 14677 14678 /** 14679 * The base elevation of this view relative to its parent, in pixels. 14680 * 14681 * @return The base depth position of the view, in pixels. 14682 */ 14683 @ViewDebug.ExportedProperty(category = "drawing") 14684 public float getElevation() { 14685 return mRenderNode.getElevation(); 14686 } 14687 14688 /** 14689 * Sets the base elevation of this view, in pixels. 14690 * 14691 * @attr ref android.R.styleable#View_elevation 14692 */ 14693 public void setElevation(float elevation) { 14694 if (elevation != getElevation()) { 14695 invalidateViewProperty(true, false); 14696 mRenderNode.setElevation(elevation); 14697 invalidateViewProperty(false, true); 14698 14699 invalidateParentIfNeededAndWasQuickRejected(); 14700 } 14701 } 14702 14703 /** 14704 * The horizontal location of this view relative to its {@link #getLeft() left} position. 14705 * This position is post-layout, in addition to wherever the object's 14706 * layout placed it. 14707 * 14708 * @return The horizontal position of this view relative to its left position, in pixels. 14709 */ 14710 @ViewDebug.ExportedProperty(category = "drawing") 14711 public float getTranslationX() { 14712 return mRenderNode.getTranslationX(); 14713 } 14714 14715 /** 14716 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 14717 * This effectively positions the object post-layout, in addition to wherever the object's 14718 * layout placed it. 14719 * 14720 * @param translationX The horizontal position of this view relative to its left position, 14721 * in pixels. 14722 * 14723 * @attr ref android.R.styleable#View_translationX 14724 */ 14725 public void setTranslationX(float translationX) { 14726 if (translationX != getTranslationX()) { 14727 invalidateViewProperty(true, false); 14728 mRenderNode.setTranslationX(translationX); 14729 invalidateViewProperty(false, true); 14730 14731 invalidateParentIfNeededAndWasQuickRejected(); 14732 notifySubtreeAccessibilityStateChangedIfNeeded(); 14733 } 14734 } 14735 14736 /** 14737 * The vertical location of this view relative to its {@link #getTop() top} position. 14738 * This position is post-layout, in addition to wherever the object's 14739 * layout placed it. 14740 * 14741 * @return The vertical position of this view relative to its top position, 14742 * in pixels. 14743 */ 14744 @ViewDebug.ExportedProperty(category = "drawing") 14745 public float getTranslationY() { 14746 return mRenderNode.getTranslationY(); 14747 } 14748 14749 /** 14750 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 14751 * This effectively positions the object post-layout, in addition to wherever the object's 14752 * layout placed it. 14753 * 14754 * @param translationY The vertical position of this view relative to its top position, 14755 * in pixels. 14756 * 14757 * @attr ref android.R.styleable#View_translationY 14758 */ 14759 public void setTranslationY(float translationY) { 14760 if (translationY != getTranslationY()) { 14761 invalidateViewProperty(true, false); 14762 mRenderNode.setTranslationY(translationY); 14763 invalidateViewProperty(false, true); 14764 14765 invalidateParentIfNeededAndWasQuickRejected(); 14766 notifySubtreeAccessibilityStateChangedIfNeeded(); 14767 } 14768 } 14769 14770 /** 14771 * The depth location of this view relative to its {@link #getElevation() elevation}. 14772 * 14773 * @return The depth of this view relative to its elevation. 14774 */ 14775 @ViewDebug.ExportedProperty(category = "drawing") 14776 public float getTranslationZ() { 14777 return mRenderNode.getTranslationZ(); 14778 } 14779 14780 /** 14781 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 14782 * 14783 * @attr ref android.R.styleable#View_translationZ 14784 */ 14785 public void setTranslationZ(float translationZ) { 14786 if (translationZ != getTranslationZ()) { 14787 invalidateViewProperty(true, false); 14788 mRenderNode.setTranslationZ(translationZ); 14789 invalidateViewProperty(false, true); 14790 14791 invalidateParentIfNeededAndWasQuickRejected(); 14792 } 14793 } 14794 14795 /** @hide */ 14796 public void setAnimationMatrix(Matrix matrix) { 14797 invalidateViewProperty(true, false); 14798 mRenderNode.setAnimationMatrix(matrix); 14799 invalidateViewProperty(false, true); 14800 14801 invalidateParentIfNeededAndWasQuickRejected(); 14802 } 14803 14804 /** 14805 * Returns the current StateListAnimator if exists. 14806 * 14807 * @return StateListAnimator or null if it does not exists 14808 * @see #setStateListAnimator(android.animation.StateListAnimator) 14809 */ 14810 public StateListAnimator getStateListAnimator() { 14811 return mStateListAnimator; 14812 } 14813 14814 /** 14815 * Attaches the provided StateListAnimator to this View. 14816 * <p> 14817 * Any previously attached StateListAnimator will be detached. 14818 * 14819 * @param stateListAnimator The StateListAnimator to update the view 14820 * @see android.animation.StateListAnimator 14821 */ 14822 public void setStateListAnimator(StateListAnimator stateListAnimator) { 14823 if (mStateListAnimator == stateListAnimator) { 14824 return; 14825 } 14826 if (mStateListAnimator != null) { 14827 mStateListAnimator.setTarget(null); 14828 } 14829 mStateListAnimator = stateListAnimator; 14830 if (stateListAnimator != null) { 14831 stateListAnimator.setTarget(this); 14832 if (isAttachedToWindow()) { 14833 stateListAnimator.setState(getDrawableState()); 14834 } 14835 } 14836 } 14837 14838 /** 14839 * Returns whether the Outline should be used to clip the contents of the View. 14840 * <p> 14841 * Note that this flag will only be respected if the View's Outline returns true from 14842 * {@link Outline#canClip()}. 14843 * 14844 * @see #setOutlineProvider(ViewOutlineProvider) 14845 * @see #setClipToOutline(boolean) 14846 */ 14847 public final boolean getClipToOutline() { 14848 return mRenderNode.getClipToOutline(); 14849 } 14850 14851 /** 14852 * Sets whether the View's Outline should be used to clip the contents of the View. 14853 * <p> 14854 * Only a single non-rectangular clip can be applied on a View at any time. 14855 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 14856 * circular reveal} animation take priority over Outline clipping, and 14857 * child Outline clipping takes priority over Outline clipping done by a 14858 * parent. 14859 * <p> 14860 * Note that this flag will only be respected if the View's Outline returns true from 14861 * {@link Outline#canClip()}. 14862 * 14863 * @see #setOutlineProvider(ViewOutlineProvider) 14864 * @see #getClipToOutline() 14865 */ 14866 public void setClipToOutline(boolean clipToOutline) { 14867 damageInParent(); 14868 if (getClipToOutline() != clipToOutline) { 14869 mRenderNode.setClipToOutline(clipToOutline); 14870 } 14871 } 14872 14873 // correspond to the enum values of View_outlineProvider 14874 private static final int PROVIDER_BACKGROUND = 0; 14875 private static final int PROVIDER_NONE = 1; 14876 private static final int PROVIDER_BOUNDS = 2; 14877 private static final int PROVIDER_PADDED_BOUNDS = 3; 14878 private void setOutlineProviderFromAttribute(int providerInt) { 14879 switch (providerInt) { 14880 case PROVIDER_BACKGROUND: 14881 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 14882 break; 14883 case PROVIDER_NONE: 14884 setOutlineProvider(null); 14885 break; 14886 case PROVIDER_BOUNDS: 14887 setOutlineProvider(ViewOutlineProvider.BOUNDS); 14888 break; 14889 case PROVIDER_PADDED_BOUNDS: 14890 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 14891 break; 14892 } 14893 } 14894 14895 /** 14896 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 14897 * the shape of the shadow it casts, and enables outline clipping. 14898 * <p> 14899 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 14900 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 14901 * outline provider with this method allows this behavior to be overridden. 14902 * <p> 14903 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 14904 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 14905 * <p> 14906 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 14907 * 14908 * @see #setClipToOutline(boolean) 14909 * @see #getClipToOutline() 14910 * @see #getOutlineProvider() 14911 */ 14912 public void setOutlineProvider(ViewOutlineProvider provider) { 14913 mOutlineProvider = provider; 14914 invalidateOutline(); 14915 } 14916 14917 /** 14918 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 14919 * that defines the shape of the shadow it casts, and enables outline clipping. 14920 * 14921 * @see #setOutlineProvider(ViewOutlineProvider) 14922 */ 14923 public ViewOutlineProvider getOutlineProvider() { 14924 return mOutlineProvider; 14925 } 14926 14927 /** 14928 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 14929 * 14930 * @see #setOutlineProvider(ViewOutlineProvider) 14931 */ 14932 public void invalidateOutline() { 14933 rebuildOutline(); 14934 14935 notifySubtreeAccessibilityStateChangedIfNeeded(); 14936 invalidateViewProperty(false, false); 14937 } 14938 14939 /** 14940 * Internal version of {@link #invalidateOutline()} which invalidates the 14941 * outline without invalidating the view itself. This is intended to be called from 14942 * within methods in the View class itself which are the result of the view being 14943 * invalidated already. For example, when we are drawing the background of a View, 14944 * we invalidate the outline in case it changed in the meantime, but we do not 14945 * need to invalidate the view because we're already drawing the background as part 14946 * of drawing the view in response to an earlier invalidation of the view. 14947 */ 14948 private void rebuildOutline() { 14949 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 14950 if (mAttachInfo == null) return; 14951 14952 if (mOutlineProvider == null) { 14953 // no provider, remove outline 14954 mRenderNode.setOutline(null); 14955 } else { 14956 final Outline outline = mAttachInfo.mTmpOutline; 14957 outline.setEmpty(); 14958 outline.setAlpha(1.0f); 14959 14960 mOutlineProvider.getOutline(this, outline); 14961 mRenderNode.setOutline(outline); 14962 } 14963 } 14964 14965 /** 14966 * HierarchyViewer only 14967 * 14968 * @hide 14969 */ 14970 @ViewDebug.ExportedProperty(category = "drawing") 14971 public boolean hasShadow() { 14972 return mRenderNode.hasShadow(); 14973 } 14974 14975 14976 /** @hide */ 14977 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 14978 mRenderNode.setRevealClip(shouldClip, x, y, radius); 14979 invalidateViewProperty(false, false); 14980 } 14981 14982 /** 14983 * Hit rectangle in parent's coordinates 14984 * 14985 * @param outRect The hit rectangle of the view. 14986 */ 14987 public void getHitRect(Rect outRect) { 14988 if (hasIdentityMatrix() || mAttachInfo == null) { 14989 outRect.set(mLeft, mTop, mRight, mBottom); 14990 } else { 14991 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 14992 tmpRect.set(0, 0, getWidth(), getHeight()); 14993 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 14994 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 14995 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 14996 } 14997 } 14998 14999 /** 15000 * Determines whether the given point, in local coordinates is inside the view. 15001 */ 15002 /*package*/ final boolean pointInView(float localX, float localY) { 15003 return pointInView(localX, localY, 0); 15004 } 15005 15006 /** 15007 * Utility method to determine whether the given point, in local coordinates, 15008 * is inside the view, where the area of the view is expanded by the slop factor. 15009 * This method is called while processing touch-move events to determine if the event 15010 * is still within the view. 15011 * 15012 * @hide 15013 */ 15014 public boolean pointInView(float localX, float localY, float slop) { 15015 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 15016 localY < ((mBottom - mTop) + slop); 15017 } 15018 15019 /** 15020 * When a view has focus and the user navigates away from it, the next view is searched for 15021 * starting from the rectangle filled in by this method. 15022 * 15023 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 15024 * of the view. However, if your view maintains some idea of internal selection, 15025 * such as a cursor, or a selected row or column, you should override this method and 15026 * fill in a more specific rectangle. 15027 * 15028 * @param r The rectangle to fill in, in this view's coordinates. 15029 */ 15030 public void getFocusedRect(Rect r) { 15031 getDrawingRect(r); 15032 } 15033 15034 /** 15035 * If some part of this view is not clipped by any of its parents, then 15036 * return that area in r in global (root) coordinates. To convert r to local 15037 * coordinates (without taking possible View rotations into account), offset 15038 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 15039 * If the view is completely clipped or translated out, return false. 15040 * 15041 * @param r If true is returned, r holds the global coordinates of the 15042 * visible portion of this view. 15043 * @param globalOffset If true is returned, globalOffset holds the dx,dy 15044 * between this view and its root. globalOffet may be null. 15045 * @return true if r is non-empty (i.e. part of the view is visible at the 15046 * root level. 15047 */ 15048 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 15049 int width = mRight - mLeft; 15050 int height = mBottom - mTop; 15051 if (width > 0 && height > 0) { 15052 r.set(0, 0, width, height); 15053 if (globalOffset != null) { 15054 globalOffset.set(-mScrollX, -mScrollY); 15055 } 15056 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 15057 } 15058 return false; 15059 } 15060 15061 public final boolean getGlobalVisibleRect(Rect r) { 15062 return getGlobalVisibleRect(r, null); 15063 } 15064 15065 public final boolean getLocalVisibleRect(Rect r) { 15066 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 15067 if (getGlobalVisibleRect(r, offset)) { 15068 r.offset(-offset.x, -offset.y); // make r local 15069 return true; 15070 } 15071 return false; 15072 } 15073 15074 /** 15075 * Offset this view's vertical location by the specified number of pixels. 15076 * 15077 * @param offset the number of pixels to offset the view by 15078 */ 15079 public void offsetTopAndBottom(int offset) { 15080 if (offset != 0) { 15081 final boolean matrixIsIdentity = hasIdentityMatrix(); 15082 if (matrixIsIdentity) { 15083 if (isHardwareAccelerated()) { 15084 invalidateViewProperty(false, false); 15085 } else { 15086 final ViewParent p = mParent; 15087 if (p != null && mAttachInfo != null) { 15088 final Rect r = mAttachInfo.mTmpInvalRect; 15089 int minTop; 15090 int maxBottom; 15091 int yLoc; 15092 if (offset < 0) { 15093 minTop = mTop + offset; 15094 maxBottom = mBottom; 15095 yLoc = offset; 15096 } else { 15097 minTop = mTop; 15098 maxBottom = mBottom + offset; 15099 yLoc = 0; 15100 } 15101 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 15102 p.invalidateChild(this, r); 15103 } 15104 } 15105 } else { 15106 invalidateViewProperty(false, false); 15107 } 15108 15109 mTop += offset; 15110 mBottom += offset; 15111 mRenderNode.offsetTopAndBottom(offset); 15112 if (isHardwareAccelerated()) { 15113 invalidateViewProperty(false, false); 15114 invalidateParentIfNeededAndWasQuickRejected(); 15115 } else { 15116 if (!matrixIsIdentity) { 15117 invalidateViewProperty(false, true); 15118 } 15119 invalidateParentIfNeeded(); 15120 } 15121 notifySubtreeAccessibilityStateChangedIfNeeded(); 15122 } 15123 } 15124 15125 /** 15126 * Offset this view's horizontal location by the specified amount of pixels. 15127 * 15128 * @param offset the number of pixels to offset the view by 15129 */ 15130 public void offsetLeftAndRight(int offset) { 15131 if (offset != 0) { 15132 final boolean matrixIsIdentity = hasIdentityMatrix(); 15133 if (matrixIsIdentity) { 15134 if (isHardwareAccelerated()) { 15135 invalidateViewProperty(false, false); 15136 } else { 15137 final ViewParent p = mParent; 15138 if (p != null && mAttachInfo != null) { 15139 final Rect r = mAttachInfo.mTmpInvalRect; 15140 int minLeft; 15141 int maxRight; 15142 if (offset < 0) { 15143 minLeft = mLeft + offset; 15144 maxRight = mRight; 15145 } else { 15146 minLeft = mLeft; 15147 maxRight = mRight + offset; 15148 } 15149 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 15150 p.invalidateChild(this, r); 15151 } 15152 } 15153 } else { 15154 invalidateViewProperty(false, false); 15155 } 15156 15157 mLeft += offset; 15158 mRight += offset; 15159 mRenderNode.offsetLeftAndRight(offset); 15160 if (isHardwareAccelerated()) { 15161 invalidateViewProperty(false, false); 15162 invalidateParentIfNeededAndWasQuickRejected(); 15163 } else { 15164 if (!matrixIsIdentity) { 15165 invalidateViewProperty(false, true); 15166 } 15167 invalidateParentIfNeeded(); 15168 } 15169 notifySubtreeAccessibilityStateChangedIfNeeded(); 15170 } 15171 } 15172 15173 /** 15174 * Get the LayoutParams associated with this view. All views should have 15175 * layout parameters. These supply parameters to the <i>parent</i> of this 15176 * view specifying how it should be arranged. There are many subclasses of 15177 * ViewGroup.LayoutParams, and these correspond to the different subclasses 15178 * of ViewGroup that are responsible for arranging their children. 15179 * 15180 * This method may return null if this View is not attached to a parent 15181 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 15182 * was not invoked successfully. When a View is attached to a parent 15183 * ViewGroup, this method must not return null. 15184 * 15185 * @return The LayoutParams associated with this view, or null if no 15186 * parameters have been set yet 15187 */ 15188 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") 15189 public ViewGroup.LayoutParams getLayoutParams() { 15190 return mLayoutParams; 15191 } 15192 15193 /** 15194 * Set the layout parameters associated with this view. These supply 15195 * parameters to the <i>parent</i> of this view specifying how it should be 15196 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 15197 * correspond to the different subclasses of ViewGroup that are responsible 15198 * for arranging their children. 15199 * 15200 * @param params The layout parameters for this view, cannot be null 15201 */ 15202 public void setLayoutParams(ViewGroup.LayoutParams params) { 15203 if (params == null) { 15204 throw new NullPointerException("Layout parameters cannot be null"); 15205 } 15206 mLayoutParams = params; 15207 resolveLayoutParams(); 15208 if (mParent instanceof ViewGroup) { 15209 ((ViewGroup) mParent).onSetLayoutParams(this, params); 15210 } 15211 requestLayout(); 15212 } 15213 15214 /** 15215 * Resolve the layout parameters depending on the resolved layout direction 15216 * 15217 * @hide 15218 */ 15219 public void resolveLayoutParams() { 15220 if (mLayoutParams != null) { 15221 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 15222 } 15223 } 15224 15225 /** 15226 * Set the scrolled position of your view. This will cause a call to 15227 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15228 * invalidated. 15229 * @param x the x position to scroll to 15230 * @param y the y position to scroll to 15231 */ 15232 public void scrollTo(int x, int y) { 15233 if (mScrollX != x || mScrollY != y) { 15234 int oldX = mScrollX; 15235 int oldY = mScrollY; 15236 mScrollX = x; 15237 mScrollY = y; 15238 invalidateParentCaches(); 15239 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 15240 if (!awakenScrollBars()) { 15241 postInvalidateOnAnimation(); 15242 } 15243 } 15244 } 15245 15246 /** 15247 * Move the scrolled position of your view. This will cause a call to 15248 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15249 * invalidated. 15250 * @param x the amount of pixels to scroll by horizontally 15251 * @param y the amount of pixels to scroll by vertically 15252 */ 15253 public void scrollBy(int x, int y) { 15254 scrollTo(mScrollX + x, mScrollY + y); 15255 } 15256 15257 /** 15258 * <p>Trigger the scrollbars to draw. When invoked this method starts an 15259 * animation to fade the scrollbars out after a default delay. If a subclass 15260 * provides animated scrolling, the start delay should equal the duration 15261 * of the scrolling animation.</p> 15262 * 15263 * <p>The animation starts only if at least one of the scrollbars is 15264 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 15265 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15266 * this method returns true, and false otherwise. If the animation is 15267 * started, this method calls {@link #invalidate()}; in that case the 15268 * caller should not call {@link #invalidate()}.</p> 15269 * 15270 * <p>This method should be invoked every time a subclass directly updates 15271 * the scroll parameters.</p> 15272 * 15273 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 15274 * and {@link #scrollTo(int, int)}.</p> 15275 * 15276 * @return true if the animation is played, false otherwise 15277 * 15278 * @see #awakenScrollBars(int) 15279 * @see #scrollBy(int, int) 15280 * @see #scrollTo(int, int) 15281 * @see #isHorizontalScrollBarEnabled() 15282 * @see #isVerticalScrollBarEnabled() 15283 * @see #setHorizontalScrollBarEnabled(boolean) 15284 * @see #setVerticalScrollBarEnabled(boolean) 15285 */ 15286 protected boolean awakenScrollBars() { 15287 return mScrollCache != null && 15288 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 15289 } 15290 15291 /** 15292 * Trigger the scrollbars to draw. 15293 * This method differs from awakenScrollBars() only in its default duration. 15294 * initialAwakenScrollBars() will show the scroll bars for longer than 15295 * usual to give the user more of a chance to notice them. 15296 * 15297 * @return true if the animation is played, false otherwise. 15298 */ 15299 private boolean initialAwakenScrollBars() { 15300 return mScrollCache != null && 15301 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 15302 } 15303 15304 /** 15305 * <p> 15306 * Trigger the scrollbars to draw. When invoked this method starts an 15307 * animation to fade the scrollbars out after a fixed delay. If a subclass 15308 * provides animated scrolling, the start delay should equal the duration of 15309 * the scrolling animation. 15310 * </p> 15311 * 15312 * <p> 15313 * The animation starts only if at least one of the scrollbars is enabled, 15314 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15315 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15316 * this method returns true, and false otherwise. If the animation is 15317 * started, this method calls {@link #invalidate()}; in that case the caller 15318 * should not call {@link #invalidate()}. 15319 * </p> 15320 * 15321 * <p> 15322 * This method should be invoked every time a subclass directly updates the 15323 * scroll parameters. 15324 * </p> 15325 * 15326 * @param startDelay the delay, in milliseconds, after which the animation 15327 * should start; when the delay is 0, the animation starts 15328 * immediately 15329 * @return true if the animation is played, false otherwise 15330 * 15331 * @see #scrollBy(int, int) 15332 * @see #scrollTo(int, int) 15333 * @see #isHorizontalScrollBarEnabled() 15334 * @see #isVerticalScrollBarEnabled() 15335 * @see #setHorizontalScrollBarEnabled(boolean) 15336 * @see #setVerticalScrollBarEnabled(boolean) 15337 */ 15338 protected boolean awakenScrollBars(int startDelay) { 15339 return awakenScrollBars(startDelay, true); 15340 } 15341 15342 /** 15343 * <p> 15344 * Trigger the scrollbars to draw. When invoked this method starts an 15345 * animation to fade the scrollbars out after a fixed delay. If a subclass 15346 * provides animated scrolling, the start delay should equal the duration of 15347 * the scrolling animation. 15348 * </p> 15349 * 15350 * <p> 15351 * The animation starts only if at least one of the scrollbars is enabled, 15352 * as specified by {@link #isHorizontalScrollBarEnabled()} and 15353 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 15354 * this method returns true, and false otherwise. If the animation is 15355 * started, this method calls {@link #invalidate()} if the invalidate parameter 15356 * is set to true; in that case the caller 15357 * should not call {@link #invalidate()}. 15358 * </p> 15359 * 15360 * <p> 15361 * This method should be invoked every time a subclass directly updates the 15362 * scroll parameters. 15363 * </p> 15364 * 15365 * @param startDelay the delay, in milliseconds, after which the animation 15366 * should start; when the delay is 0, the animation starts 15367 * immediately 15368 * 15369 * @param invalidate Whether this method should call invalidate 15370 * 15371 * @return true if the animation is played, false otherwise 15372 * 15373 * @see #scrollBy(int, int) 15374 * @see #scrollTo(int, int) 15375 * @see #isHorizontalScrollBarEnabled() 15376 * @see #isVerticalScrollBarEnabled() 15377 * @see #setHorizontalScrollBarEnabled(boolean) 15378 * @see #setVerticalScrollBarEnabled(boolean) 15379 */ 15380 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 15381 final ScrollabilityCache scrollCache = mScrollCache; 15382 15383 if (scrollCache == null || !scrollCache.fadeScrollBars) { 15384 return false; 15385 } 15386 15387 if (scrollCache.scrollBar == null) { 15388 scrollCache.scrollBar = new ScrollBarDrawable(); 15389 scrollCache.scrollBar.setState(getDrawableState()); 15390 scrollCache.scrollBar.setCallback(this); 15391 } 15392 15393 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 15394 15395 if (invalidate) { 15396 // Invalidate to show the scrollbars 15397 postInvalidateOnAnimation(); 15398 } 15399 15400 if (scrollCache.state == ScrollabilityCache.OFF) { 15401 // FIXME: this is copied from WindowManagerService. 15402 // We should get this value from the system when it 15403 // is possible to do so. 15404 final int KEY_REPEAT_FIRST_DELAY = 750; 15405 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 15406 } 15407 15408 // Tell mScrollCache when we should start fading. This may 15409 // extend the fade start time if one was already scheduled 15410 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 15411 scrollCache.fadeStartTime = fadeStartTime; 15412 scrollCache.state = ScrollabilityCache.ON; 15413 15414 // Schedule our fader to run, unscheduling any old ones first 15415 if (mAttachInfo != null) { 15416 mAttachInfo.mHandler.removeCallbacks(scrollCache); 15417 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 15418 } 15419 15420 return true; 15421 } 15422 15423 return false; 15424 } 15425 15426 /** 15427 * Do not invalidate views which are not visible and which are not running an animation. They 15428 * will not get drawn and they should not set dirty flags as if they will be drawn 15429 */ 15430 private boolean skipInvalidate() { 15431 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 15432 (!(mParent instanceof ViewGroup) || 15433 !((ViewGroup) mParent).isViewTransitioning(this)); 15434 } 15435 15436 /** 15437 * Mark the area defined by dirty as needing to be drawn. If the view is 15438 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15439 * point in the future. 15440 * <p> 15441 * This must be called from a UI thread. To call from a non-UI thread, call 15442 * {@link #postInvalidate()}. 15443 * <p> 15444 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 15445 * {@code dirty}. 15446 * 15447 * @param dirty the rectangle representing the bounds of the dirty region 15448 */ 15449 public void invalidate(Rect dirty) { 15450 final int scrollX = mScrollX; 15451 final int scrollY = mScrollY; 15452 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 15453 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 15454 } 15455 15456 /** 15457 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 15458 * coordinates of the dirty rect are relative to the view. If the view is 15459 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 15460 * point in the future. 15461 * <p> 15462 * This must be called from a UI thread. To call from a non-UI thread, call 15463 * {@link #postInvalidate()}. 15464 * 15465 * @param l the left position of the dirty region 15466 * @param t the top position of the dirty region 15467 * @param r the right position of the dirty region 15468 * @param b the bottom position of the dirty region 15469 */ 15470 public void invalidate(int l, int t, int r, int b) { 15471 final int scrollX = mScrollX; 15472 final int scrollY = mScrollY; 15473 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 15474 } 15475 15476 /** 15477 * Invalidate the whole view. If the view is visible, 15478 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 15479 * the future. 15480 * <p> 15481 * This must be called from a UI thread. To call from a non-UI thread, call 15482 * {@link #postInvalidate()}. 15483 */ 15484 public void invalidate() { 15485 invalidate(true); 15486 } 15487 15488 /** 15489 * This is where the invalidate() work actually happens. A full invalidate() 15490 * causes the drawing cache to be invalidated, but this function can be 15491 * called with invalidateCache set to false to skip that invalidation step 15492 * for cases that do not need it (for example, a component that remains at 15493 * the same dimensions with the same content). 15494 * 15495 * @param invalidateCache Whether the drawing cache for this view should be 15496 * invalidated as well. This is usually true for a full 15497 * invalidate, but may be set to false if the View's contents or 15498 * dimensions have not changed. 15499 * @hide 15500 */ 15501 public void invalidate(boolean invalidateCache) { 15502 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 15503 } 15504 15505 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 15506 boolean fullInvalidate) { 15507 if (mGhostView != null) { 15508 mGhostView.invalidate(true); 15509 return; 15510 } 15511 15512 if (skipInvalidate()) { 15513 return; 15514 } 15515 15516 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 15517 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 15518 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 15519 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 15520 if (fullInvalidate) { 15521 mLastIsOpaque = isOpaque(); 15522 mPrivateFlags &= ~PFLAG_DRAWN; 15523 } 15524 15525 mPrivateFlags |= PFLAG_DIRTY; 15526 15527 if (invalidateCache) { 15528 mPrivateFlags |= PFLAG_INVALIDATED; 15529 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15530 } 15531 15532 // Propagate the damage rectangle to the parent view. 15533 final AttachInfo ai = mAttachInfo; 15534 final ViewParent p = mParent; 15535 if (p != null && ai != null && l < r && t < b) { 15536 final Rect damage = ai.mTmpInvalRect; 15537 damage.set(l, t, r, b); 15538 p.invalidateChild(this, damage); 15539 } 15540 15541 // Damage the entire projection receiver, if necessary. 15542 if (mBackground != null && mBackground.isProjected()) { 15543 final View receiver = getProjectionReceiver(); 15544 if (receiver != null) { 15545 receiver.damageInParent(); 15546 } 15547 } 15548 } 15549 } 15550 15551 /** 15552 * @return this view's projection receiver, or {@code null} if none exists 15553 */ 15554 private View getProjectionReceiver() { 15555 ViewParent p = getParent(); 15556 while (p != null && p instanceof View) { 15557 final View v = (View) p; 15558 if (v.isProjectionReceiver()) { 15559 return v; 15560 } 15561 p = p.getParent(); 15562 } 15563 15564 return null; 15565 } 15566 15567 /** 15568 * @return whether the view is a projection receiver 15569 */ 15570 private boolean isProjectionReceiver() { 15571 return mBackground != null; 15572 } 15573 15574 /** 15575 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 15576 * set any flags or handle all of the cases handled by the default invalidation methods. 15577 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 15578 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 15579 * walk up the hierarchy, transforming the dirty rect as necessary. 15580 * 15581 * The method also handles normal invalidation logic if display list properties are not 15582 * being used in this view. The invalidateParent and forceRedraw flags are used by that 15583 * backup approach, to handle these cases used in the various property-setting methods. 15584 * 15585 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 15586 * are not being used in this view 15587 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 15588 * list properties are not being used in this view 15589 */ 15590 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 15591 if (!isHardwareAccelerated() 15592 || !mRenderNode.isValid() 15593 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 15594 if (invalidateParent) { 15595 invalidateParentCaches(); 15596 } 15597 if (forceRedraw) { 15598 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 15599 } 15600 invalidate(false); 15601 } else { 15602 damageInParent(); 15603 } 15604 } 15605 15606 /** 15607 * Tells the parent view to damage this view's bounds. 15608 * 15609 * @hide 15610 */ 15611 protected void damageInParent() { 15612 if (mParent != null && mAttachInfo != null) { 15613 mParent.onDescendantInvalidated(this, this); 15614 } 15615 } 15616 15617 /** 15618 * Utility method to transform a given Rect by the current matrix of this view. 15619 */ 15620 void transformRect(final Rect rect) { 15621 if (!getMatrix().isIdentity()) { 15622 RectF boundingRect = mAttachInfo.mTmpTransformRect; 15623 boundingRect.set(rect); 15624 getMatrix().mapRect(boundingRect); 15625 rect.set((int) Math.floor(boundingRect.left), 15626 (int) Math.floor(boundingRect.top), 15627 (int) Math.ceil(boundingRect.right), 15628 (int) Math.ceil(boundingRect.bottom)); 15629 } 15630 } 15631 15632 /** 15633 * Used to indicate that the parent of this view should clear its caches. This functionality 15634 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15635 * which is necessary when various parent-managed properties of the view change, such as 15636 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 15637 * clears the parent caches and does not causes an invalidate event. 15638 * 15639 * @hide 15640 */ 15641 protected void invalidateParentCaches() { 15642 if (mParent instanceof View) { 15643 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 15644 } 15645 } 15646 15647 /** 15648 * Used to indicate that the parent of this view should be invalidated. This functionality 15649 * is used to force the parent to rebuild its display list (when hardware-accelerated), 15650 * which is necessary when various parent-managed properties of the view change, such as 15651 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 15652 * an invalidation event to the parent. 15653 * 15654 * @hide 15655 */ 15656 protected void invalidateParentIfNeeded() { 15657 if (isHardwareAccelerated() && mParent instanceof View) { 15658 ((View) mParent).invalidate(true); 15659 } 15660 } 15661 15662 /** 15663 * @hide 15664 */ 15665 protected void invalidateParentIfNeededAndWasQuickRejected() { 15666 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 15667 // View was rejected last time it was drawn by its parent; this may have changed 15668 invalidateParentIfNeeded(); 15669 } 15670 } 15671 15672 /** 15673 * Indicates whether this View is opaque. An opaque View guarantees that it will 15674 * draw all the pixels overlapping its bounds using a fully opaque color. 15675 * 15676 * Subclasses of View should override this method whenever possible to indicate 15677 * whether an instance is opaque. Opaque Views are treated in a special way by 15678 * the View hierarchy, possibly allowing it to perform optimizations during 15679 * invalidate/draw passes. 15680 * 15681 * @return True if this View is guaranteed to be fully opaque, false otherwise. 15682 */ 15683 @ViewDebug.ExportedProperty(category = "drawing") 15684 public boolean isOpaque() { 15685 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 15686 getFinalAlpha() >= 1.0f; 15687 } 15688 15689 /** 15690 * @hide 15691 */ 15692 protected void computeOpaqueFlags() { 15693 // Opaque if: 15694 // - Has a background 15695 // - Background is opaque 15696 // - Doesn't have scrollbars or scrollbars overlay 15697 15698 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 15699 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 15700 } else { 15701 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 15702 } 15703 15704 final int flags = mViewFlags; 15705 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 15706 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 15707 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 15708 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 15709 } else { 15710 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 15711 } 15712 } 15713 15714 /** 15715 * @hide 15716 */ 15717 protected boolean hasOpaqueScrollbars() { 15718 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 15719 } 15720 15721 /** 15722 * @return A handler associated with the thread running the View. This 15723 * handler can be used to pump events in the UI events queue. 15724 */ 15725 public Handler getHandler() { 15726 final AttachInfo attachInfo = mAttachInfo; 15727 if (attachInfo != null) { 15728 return attachInfo.mHandler; 15729 } 15730 return null; 15731 } 15732 15733 /** 15734 * Returns the queue of runnable for this view. 15735 * 15736 * @return the queue of runnables for this view 15737 */ 15738 private HandlerActionQueue getRunQueue() { 15739 if (mRunQueue == null) { 15740 mRunQueue = new HandlerActionQueue(); 15741 } 15742 return mRunQueue; 15743 } 15744 15745 /** 15746 * Gets the view root associated with the View. 15747 * @return The view root, or null if none. 15748 * @hide 15749 */ 15750 public ViewRootImpl getViewRootImpl() { 15751 if (mAttachInfo != null) { 15752 return mAttachInfo.mViewRootImpl; 15753 } 15754 return null; 15755 } 15756 15757 /** 15758 * @hide 15759 */ 15760 public ThreadedRenderer getThreadedRenderer() { 15761 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 15762 } 15763 15764 /** 15765 * <p>Causes the Runnable to be added to the message queue. 15766 * The runnable will be run on the user interface thread.</p> 15767 * 15768 * @param action The Runnable that will be executed. 15769 * 15770 * @return Returns true if the Runnable was successfully placed in to the 15771 * message queue. Returns false on failure, usually because the 15772 * looper processing the message queue is exiting. 15773 * 15774 * @see #postDelayed 15775 * @see #removeCallbacks 15776 */ 15777 public boolean post(Runnable action) { 15778 final AttachInfo attachInfo = mAttachInfo; 15779 if (attachInfo != null) { 15780 return attachInfo.mHandler.post(action); 15781 } 15782 15783 // Postpone the runnable until we know on which thread it needs to run. 15784 // Assume that the runnable will be successfully placed after attach. 15785 getRunQueue().post(action); 15786 return true; 15787 } 15788 15789 /** 15790 * <p>Causes the Runnable to be added to the message queue, to be run 15791 * after the specified amount of time elapses. 15792 * The runnable will be run on the user interface thread.</p> 15793 * 15794 * @param action The Runnable that will be executed. 15795 * @param delayMillis The delay (in milliseconds) until the Runnable 15796 * will be executed. 15797 * 15798 * @return true if the Runnable was successfully placed in to the 15799 * message queue. Returns false on failure, usually because the 15800 * looper processing the message queue is exiting. Note that a 15801 * result of true does not mean the Runnable will be processed -- 15802 * if the looper is quit before the delivery time of the message 15803 * occurs then the message will be dropped. 15804 * 15805 * @see #post 15806 * @see #removeCallbacks 15807 */ 15808 public boolean postDelayed(Runnable action, long delayMillis) { 15809 final AttachInfo attachInfo = mAttachInfo; 15810 if (attachInfo != null) { 15811 return attachInfo.mHandler.postDelayed(action, delayMillis); 15812 } 15813 15814 // Postpone the runnable until we know on which thread it needs to run. 15815 // Assume that the runnable will be successfully placed after attach. 15816 getRunQueue().postDelayed(action, delayMillis); 15817 return true; 15818 } 15819 15820 /** 15821 * <p>Causes the Runnable to execute on the next animation time step. 15822 * The runnable will be run on the user interface thread.</p> 15823 * 15824 * @param action The Runnable that will be executed. 15825 * 15826 * @see #postOnAnimationDelayed 15827 * @see #removeCallbacks 15828 */ 15829 public void postOnAnimation(Runnable action) { 15830 final AttachInfo attachInfo = mAttachInfo; 15831 if (attachInfo != null) { 15832 attachInfo.mViewRootImpl.mChoreographer.postCallback( 15833 Choreographer.CALLBACK_ANIMATION, action, null); 15834 } else { 15835 // Postpone the runnable until we know 15836 // on which thread it needs to run. 15837 getRunQueue().post(action); 15838 } 15839 } 15840 15841 /** 15842 * <p>Causes the Runnable to execute on the next animation time step, 15843 * after the specified amount of time elapses. 15844 * The runnable will be run on the user interface thread.</p> 15845 * 15846 * @param action The Runnable that will be executed. 15847 * @param delayMillis The delay (in milliseconds) until the Runnable 15848 * will be executed. 15849 * 15850 * @see #postOnAnimation 15851 * @see #removeCallbacks 15852 */ 15853 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 15854 final AttachInfo attachInfo = mAttachInfo; 15855 if (attachInfo != null) { 15856 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 15857 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 15858 } else { 15859 // Postpone the runnable until we know 15860 // on which thread it needs to run. 15861 getRunQueue().postDelayed(action, delayMillis); 15862 } 15863 } 15864 15865 /** 15866 * <p>Removes the specified Runnable from the message queue.</p> 15867 * 15868 * @param action The Runnable to remove from the message handling queue 15869 * 15870 * @return true if this view could ask the Handler to remove the Runnable, 15871 * false otherwise. When the returned value is true, the Runnable 15872 * may or may not have been actually removed from the message queue 15873 * (for instance, if the Runnable was not in the queue already.) 15874 * 15875 * @see #post 15876 * @see #postDelayed 15877 * @see #postOnAnimation 15878 * @see #postOnAnimationDelayed 15879 */ 15880 public boolean removeCallbacks(Runnable action) { 15881 if (action != null) { 15882 final AttachInfo attachInfo = mAttachInfo; 15883 if (attachInfo != null) { 15884 attachInfo.mHandler.removeCallbacks(action); 15885 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 15886 Choreographer.CALLBACK_ANIMATION, action, null); 15887 } 15888 getRunQueue().removeCallbacks(action); 15889 } 15890 return true; 15891 } 15892 15893 /** 15894 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 15895 * Use this to invalidate the View from a non-UI thread.</p> 15896 * 15897 * <p>This method can be invoked from outside of the UI thread 15898 * only when this View is attached to a window.</p> 15899 * 15900 * @see #invalidate() 15901 * @see #postInvalidateDelayed(long) 15902 */ 15903 public void postInvalidate() { 15904 postInvalidateDelayed(0); 15905 } 15906 15907 /** 15908 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15909 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 15910 * 15911 * <p>This method can be invoked from outside of the UI thread 15912 * only when this View is attached to a window.</p> 15913 * 15914 * @param left The left coordinate of the rectangle to invalidate. 15915 * @param top The top coordinate of the rectangle to invalidate. 15916 * @param right The right coordinate of the rectangle to invalidate. 15917 * @param bottom The bottom coordinate of the rectangle to invalidate. 15918 * 15919 * @see #invalidate(int, int, int, int) 15920 * @see #invalidate(Rect) 15921 * @see #postInvalidateDelayed(long, int, int, int, int) 15922 */ 15923 public void postInvalidate(int left, int top, int right, int bottom) { 15924 postInvalidateDelayed(0, left, top, right, bottom); 15925 } 15926 15927 /** 15928 * <p>Cause an invalidate to happen on a subsequent cycle through the event 15929 * loop. Waits for the specified amount of time.</p> 15930 * 15931 * <p>This method can be invoked from outside of the UI thread 15932 * only when this View is attached to a window.</p> 15933 * 15934 * @param delayMilliseconds the duration in milliseconds to delay the 15935 * invalidation by 15936 * 15937 * @see #invalidate() 15938 * @see #postInvalidate() 15939 */ 15940 public void postInvalidateDelayed(long delayMilliseconds) { 15941 // We try only with the AttachInfo because there's no point in invalidating 15942 // if we are not attached to our window 15943 final AttachInfo attachInfo = mAttachInfo; 15944 if (attachInfo != null) { 15945 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 15946 } 15947 } 15948 15949 /** 15950 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 15951 * through the event loop. Waits for the specified amount of time.</p> 15952 * 15953 * <p>This method can be invoked from outside of the UI thread 15954 * only when this View is attached to a window.</p> 15955 * 15956 * @param delayMilliseconds the duration in milliseconds to delay the 15957 * invalidation by 15958 * @param left The left coordinate of the rectangle to invalidate. 15959 * @param top The top coordinate of the rectangle to invalidate. 15960 * @param right The right coordinate of the rectangle to invalidate. 15961 * @param bottom The bottom coordinate of the rectangle to invalidate. 15962 * 15963 * @see #invalidate(int, int, int, int) 15964 * @see #invalidate(Rect) 15965 * @see #postInvalidate(int, int, int, int) 15966 */ 15967 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 15968 int right, int bottom) { 15969 15970 // We try only with the AttachInfo because there's no point in invalidating 15971 // if we are not attached to our window 15972 final AttachInfo attachInfo = mAttachInfo; 15973 if (attachInfo != null) { 15974 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 15975 info.target = this; 15976 info.left = left; 15977 info.top = top; 15978 info.right = right; 15979 info.bottom = bottom; 15980 15981 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 15982 } 15983 } 15984 15985 /** 15986 * <p>Cause an invalidate to happen on the next animation time step, typically the 15987 * next display frame.</p> 15988 * 15989 * <p>This method can be invoked from outside of the UI thread 15990 * only when this View is attached to a window.</p> 15991 * 15992 * @see #invalidate() 15993 */ 15994 public void postInvalidateOnAnimation() { 15995 // We try only with the AttachInfo because there's no point in invalidating 15996 // if we are not attached to our window 15997 final AttachInfo attachInfo = mAttachInfo; 15998 if (attachInfo != null) { 15999 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 16000 } 16001 } 16002 16003 /** 16004 * <p>Cause an invalidate of the specified area to happen on the next animation 16005 * time step, typically the next display frame.</p> 16006 * 16007 * <p>This method can be invoked from outside of the UI thread 16008 * only when this View is attached to a window.</p> 16009 * 16010 * @param left The left coordinate of the rectangle to invalidate. 16011 * @param top The top coordinate of the rectangle to invalidate. 16012 * @param right The right coordinate of the rectangle to invalidate. 16013 * @param bottom The bottom coordinate of the rectangle to invalidate. 16014 * 16015 * @see #invalidate(int, int, int, int) 16016 * @see #invalidate(Rect) 16017 */ 16018 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 16019 // We try only with the AttachInfo because there's no point in invalidating 16020 // if we are not attached to our window 16021 final AttachInfo attachInfo = mAttachInfo; 16022 if (attachInfo != null) { 16023 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 16024 info.target = this; 16025 info.left = left; 16026 info.top = top; 16027 info.right = right; 16028 info.bottom = bottom; 16029 16030 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 16031 } 16032 } 16033 16034 /** 16035 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 16036 * This event is sent at most once every 16037 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 16038 */ 16039 private void postSendViewScrolledAccessibilityEventCallback() { 16040 if (mSendViewScrolledAccessibilityEvent == null) { 16041 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 16042 } 16043 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 16044 mSendViewScrolledAccessibilityEvent.mIsPending = true; 16045 postDelayed(mSendViewScrolledAccessibilityEvent, 16046 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 16047 } 16048 } 16049 16050 /** 16051 * Called by a parent to request that a child update its values for mScrollX 16052 * and mScrollY if necessary. This will typically be done if the child is 16053 * animating a scroll using a {@link android.widget.Scroller Scroller} 16054 * object. 16055 */ 16056 public void computeScroll() { 16057 } 16058 16059 /** 16060 * <p>Indicate whether the horizontal edges are faded when the view is 16061 * scrolled horizontally.</p> 16062 * 16063 * @return true if the horizontal edges should are faded on scroll, false 16064 * otherwise 16065 * 16066 * @see #setHorizontalFadingEdgeEnabled(boolean) 16067 * 16068 * @attr ref android.R.styleable#View_requiresFadingEdge 16069 */ 16070 public boolean isHorizontalFadingEdgeEnabled() { 16071 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 16072 } 16073 16074 /** 16075 * <p>Define whether the horizontal edges should be faded when this view 16076 * is scrolled horizontally.</p> 16077 * 16078 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 16079 * be faded when the view is scrolled 16080 * horizontally 16081 * 16082 * @see #isHorizontalFadingEdgeEnabled() 16083 * 16084 * @attr ref android.R.styleable#View_requiresFadingEdge 16085 */ 16086 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 16087 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 16088 if (horizontalFadingEdgeEnabled) { 16089 initScrollCache(); 16090 } 16091 16092 mViewFlags ^= FADING_EDGE_HORIZONTAL; 16093 } 16094 } 16095 16096 /** 16097 * <p>Indicate whether the vertical edges are faded when the view is 16098 * scrolled horizontally.</p> 16099 * 16100 * @return true if the vertical edges should are faded on scroll, false 16101 * otherwise 16102 * 16103 * @see #setVerticalFadingEdgeEnabled(boolean) 16104 * 16105 * @attr ref android.R.styleable#View_requiresFadingEdge 16106 */ 16107 public boolean isVerticalFadingEdgeEnabled() { 16108 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 16109 } 16110 16111 /** 16112 * <p>Define whether the vertical edges should be faded when this view 16113 * is scrolled vertically.</p> 16114 * 16115 * @param verticalFadingEdgeEnabled true if the vertical edges should 16116 * be faded when the view is scrolled 16117 * vertically 16118 * 16119 * @see #isVerticalFadingEdgeEnabled() 16120 * 16121 * @attr ref android.R.styleable#View_requiresFadingEdge 16122 */ 16123 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 16124 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 16125 if (verticalFadingEdgeEnabled) { 16126 initScrollCache(); 16127 } 16128 16129 mViewFlags ^= FADING_EDGE_VERTICAL; 16130 } 16131 } 16132 16133 /** 16134 * Returns the strength, or intensity, of the top faded edge. The strength is 16135 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16136 * returns 0.0 or 1.0 but no value in between. 16137 * 16138 * Subclasses should override this method to provide a smoother fade transition 16139 * when scrolling occurs. 16140 * 16141 * @return the intensity of the top fade as a float between 0.0f and 1.0f 16142 */ 16143 protected float getTopFadingEdgeStrength() { 16144 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 16145 } 16146 16147 /** 16148 * Returns the strength, or intensity, of the bottom faded edge. The strength is 16149 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16150 * returns 0.0 or 1.0 but no value in between. 16151 * 16152 * Subclasses should override this method to provide a smoother fade transition 16153 * when scrolling occurs. 16154 * 16155 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 16156 */ 16157 protected float getBottomFadingEdgeStrength() { 16158 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 16159 computeVerticalScrollRange() ? 1.0f : 0.0f; 16160 } 16161 16162 /** 16163 * Returns the strength, or intensity, of the left faded edge. The strength is 16164 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16165 * returns 0.0 or 1.0 but no value in between. 16166 * 16167 * Subclasses should override this method to provide a smoother fade transition 16168 * when scrolling occurs. 16169 * 16170 * @return the intensity of the left fade as a float between 0.0f and 1.0f 16171 */ 16172 protected float getLeftFadingEdgeStrength() { 16173 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 16174 } 16175 16176 /** 16177 * Returns the strength, or intensity, of the right faded edge. The strength is 16178 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 16179 * returns 0.0 or 1.0 but no value in between. 16180 * 16181 * Subclasses should override this method to provide a smoother fade transition 16182 * when scrolling occurs. 16183 * 16184 * @return the intensity of the right fade as a float between 0.0f and 1.0f 16185 */ 16186 protected float getRightFadingEdgeStrength() { 16187 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 16188 computeHorizontalScrollRange() ? 1.0f : 0.0f; 16189 } 16190 16191 /** 16192 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 16193 * scrollbar is not drawn by default.</p> 16194 * 16195 * @return true if the horizontal scrollbar should be painted, false 16196 * otherwise 16197 * 16198 * @see #setHorizontalScrollBarEnabled(boolean) 16199 */ 16200 public boolean isHorizontalScrollBarEnabled() { 16201 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 16202 } 16203 16204 /** 16205 * <p>Define whether the horizontal scrollbar should be drawn or not. The 16206 * scrollbar is not drawn by default.</p> 16207 * 16208 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 16209 * be painted 16210 * 16211 * @see #isHorizontalScrollBarEnabled() 16212 */ 16213 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 16214 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 16215 mViewFlags ^= SCROLLBARS_HORIZONTAL; 16216 computeOpaqueFlags(); 16217 resolvePadding(); 16218 } 16219 } 16220 16221 /** 16222 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 16223 * scrollbar is not drawn by default.</p> 16224 * 16225 * @return true if the vertical scrollbar should be painted, false 16226 * otherwise 16227 * 16228 * @see #setVerticalScrollBarEnabled(boolean) 16229 */ 16230 public boolean isVerticalScrollBarEnabled() { 16231 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 16232 } 16233 16234 /** 16235 * <p>Define whether the vertical scrollbar should be drawn or not. The 16236 * scrollbar is not drawn by default.</p> 16237 * 16238 * @param verticalScrollBarEnabled true if the vertical scrollbar should 16239 * be painted 16240 * 16241 * @see #isVerticalScrollBarEnabled() 16242 */ 16243 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 16244 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 16245 mViewFlags ^= SCROLLBARS_VERTICAL; 16246 computeOpaqueFlags(); 16247 resolvePadding(); 16248 } 16249 } 16250 16251 /** 16252 * @hide 16253 */ 16254 protected void recomputePadding() { 16255 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 16256 } 16257 16258 /** 16259 * Define whether scrollbars will fade when the view is not scrolling. 16260 * 16261 * @param fadeScrollbars whether to enable fading 16262 * 16263 * @attr ref android.R.styleable#View_fadeScrollbars 16264 */ 16265 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 16266 initScrollCache(); 16267 final ScrollabilityCache scrollabilityCache = mScrollCache; 16268 scrollabilityCache.fadeScrollBars = fadeScrollbars; 16269 if (fadeScrollbars) { 16270 scrollabilityCache.state = ScrollabilityCache.OFF; 16271 } else { 16272 scrollabilityCache.state = ScrollabilityCache.ON; 16273 } 16274 } 16275 16276 /** 16277 * 16278 * Returns true if scrollbars will fade when this view is not scrolling 16279 * 16280 * @return true if scrollbar fading is enabled 16281 * 16282 * @attr ref android.R.styleable#View_fadeScrollbars 16283 */ 16284 public boolean isScrollbarFadingEnabled() { 16285 return mScrollCache != null && mScrollCache.fadeScrollBars; 16286 } 16287 16288 /** 16289 * 16290 * Returns the delay before scrollbars fade. 16291 * 16292 * @return the delay before scrollbars fade 16293 * 16294 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16295 */ 16296 public int getScrollBarDefaultDelayBeforeFade() { 16297 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 16298 mScrollCache.scrollBarDefaultDelayBeforeFade; 16299 } 16300 16301 /** 16302 * Define the delay before scrollbars fade. 16303 * 16304 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 16305 * 16306 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 16307 */ 16308 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 16309 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 16310 } 16311 16312 /** 16313 * 16314 * Returns the scrollbar fade duration. 16315 * 16316 * @return the scrollbar fade duration, in milliseconds 16317 * 16318 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16319 */ 16320 public int getScrollBarFadeDuration() { 16321 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 16322 mScrollCache.scrollBarFadeDuration; 16323 } 16324 16325 /** 16326 * Define the scrollbar fade duration. 16327 * 16328 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 16329 * 16330 * @attr ref android.R.styleable#View_scrollbarFadeDuration 16331 */ 16332 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 16333 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 16334 } 16335 16336 /** 16337 * 16338 * Returns the scrollbar size. 16339 * 16340 * @return the scrollbar size 16341 * 16342 * @attr ref android.R.styleable#View_scrollbarSize 16343 */ 16344 public int getScrollBarSize() { 16345 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 16346 mScrollCache.scrollBarSize; 16347 } 16348 16349 /** 16350 * Define the scrollbar size. 16351 * 16352 * @param scrollBarSize - the scrollbar size 16353 * 16354 * @attr ref android.R.styleable#View_scrollbarSize 16355 */ 16356 public void setScrollBarSize(int scrollBarSize) { 16357 getScrollCache().scrollBarSize = scrollBarSize; 16358 } 16359 16360 /** 16361 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 16362 * inset. When inset, they add to the padding of the view. And the scrollbars 16363 * can be drawn inside the padding area or on the edge of the view. For example, 16364 * if a view has a background drawable and you want to draw the scrollbars 16365 * inside the padding specified by the drawable, you can use 16366 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 16367 * appear at the edge of the view, ignoring the padding, then you can use 16368 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 16369 * @param style the style of the scrollbars. Should be one of 16370 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 16371 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 16372 * @see #SCROLLBARS_INSIDE_OVERLAY 16373 * @see #SCROLLBARS_INSIDE_INSET 16374 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16375 * @see #SCROLLBARS_OUTSIDE_INSET 16376 * 16377 * @attr ref android.R.styleable#View_scrollbarStyle 16378 */ 16379 public void setScrollBarStyle(@ScrollBarStyle int style) { 16380 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 16381 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 16382 computeOpaqueFlags(); 16383 resolvePadding(); 16384 } 16385 } 16386 16387 /** 16388 * <p>Returns the current scrollbar style.</p> 16389 * @return the current scrollbar style 16390 * @see #SCROLLBARS_INSIDE_OVERLAY 16391 * @see #SCROLLBARS_INSIDE_INSET 16392 * @see #SCROLLBARS_OUTSIDE_OVERLAY 16393 * @see #SCROLLBARS_OUTSIDE_INSET 16394 * 16395 * @attr ref android.R.styleable#View_scrollbarStyle 16396 */ 16397 @ViewDebug.ExportedProperty(mapping = { 16398 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 16399 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 16400 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 16401 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 16402 }) 16403 @ScrollBarStyle 16404 public int getScrollBarStyle() { 16405 return mViewFlags & SCROLLBARS_STYLE_MASK; 16406 } 16407 16408 /** 16409 * <p>Compute the horizontal range that the horizontal scrollbar 16410 * represents.</p> 16411 * 16412 * <p>The range is expressed in arbitrary units that must be the same as the 16413 * units used by {@link #computeHorizontalScrollExtent()} and 16414 * {@link #computeHorizontalScrollOffset()}.</p> 16415 * 16416 * <p>The default range is the drawing width of this view.</p> 16417 * 16418 * @return the total horizontal range represented by the horizontal 16419 * scrollbar 16420 * 16421 * @see #computeHorizontalScrollExtent() 16422 * @see #computeHorizontalScrollOffset() 16423 * @see android.widget.ScrollBarDrawable 16424 */ 16425 protected int computeHorizontalScrollRange() { 16426 return getWidth(); 16427 } 16428 16429 /** 16430 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 16431 * within the horizontal range. This value is used to compute the position 16432 * of the thumb within the scrollbar's track.</p> 16433 * 16434 * <p>The range is expressed in arbitrary units that must be the same as the 16435 * units used by {@link #computeHorizontalScrollRange()} and 16436 * {@link #computeHorizontalScrollExtent()}.</p> 16437 * 16438 * <p>The default offset is the scroll offset of this view.</p> 16439 * 16440 * @return the horizontal offset of the scrollbar's thumb 16441 * 16442 * @see #computeHorizontalScrollRange() 16443 * @see #computeHorizontalScrollExtent() 16444 * @see android.widget.ScrollBarDrawable 16445 */ 16446 protected int computeHorizontalScrollOffset() { 16447 return mScrollX; 16448 } 16449 16450 /** 16451 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 16452 * within the horizontal range. This value is used to compute the length 16453 * of the thumb within the scrollbar's track.</p> 16454 * 16455 * <p>The range is expressed in arbitrary units that must be the same as the 16456 * units used by {@link #computeHorizontalScrollRange()} and 16457 * {@link #computeHorizontalScrollOffset()}.</p> 16458 * 16459 * <p>The default extent is the drawing width of this view.</p> 16460 * 16461 * @return the horizontal extent of the scrollbar's thumb 16462 * 16463 * @see #computeHorizontalScrollRange() 16464 * @see #computeHorizontalScrollOffset() 16465 * @see android.widget.ScrollBarDrawable 16466 */ 16467 protected int computeHorizontalScrollExtent() { 16468 return getWidth(); 16469 } 16470 16471 /** 16472 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 16473 * 16474 * <p>The range is expressed in arbitrary units that must be the same as the 16475 * units used by {@link #computeVerticalScrollExtent()} and 16476 * {@link #computeVerticalScrollOffset()}.</p> 16477 * 16478 * @return the total vertical range represented by the vertical scrollbar 16479 * 16480 * <p>The default range is the drawing height of this view.</p> 16481 * 16482 * @see #computeVerticalScrollExtent() 16483 * @see #computeVerticalScrollOffset() 16484 * @see android.widget.ScrollBarDrawable 16485 */ 16486 protected int computeVerticalScrollRange() { 16487 return getHeight(); 16488 } 16489 16490 /** 16491 * <p>Compute the vertical offset of the vertical scrollbar's thumb 16492 * within the horizontal range. This value is used to compute the position 16493 * of the thumb within the scrollbar's track.</p> 16494 * 16495 * <p>The range is expressed in arbitrary units that must be the same as the 16496 * units used by {@link #computeVerticalScrollRange()} and 16497 * {@link #computeVerticalScrollExtent()}.</p> 16498 * 16499 * <p>The default offset is the scroll offset of this view.</p> 16500 * 16501 * @return the vertical offset of the scrollbar's thumb 16502 * 16503 * @see #computeVerticalScrollRange() 16504 * @see #computeVerticalScrollExtent() 16505 * @see android.widget.ScrollBarDrawable 16506 */ 16507 protected int computeVerticalScrollOffset() { 16508 return mScrollY; 16509 } 16510 16511 /** 16512 * <p>Compute the vertical extent of the vertical scrollbar's thumb 16513 * within the vertical range. This value is used to compute the length 16514 * of the thumb within the scrollbar's track.</p> 16515 * 16516 * <p>The range is expressed in arbitrary units that must be the same as the 16517 * units used by {@link #computeVerticalScrollRange()} and 16518 * {@link #computeVerticalScrollOffset()}.</p> 16519 * 16520 * <p>The default extent is the drawing height of this view.</p> 16521 * 16522 * @return the vertical extent of the scrollbar's thumb 16523 * 16524 * @see #computeVerticalScrollRange() 16525 * @see #computeVerticalScrollOffset() 16526 * @see android.widget.ScrollBarDrawable 16527 */ 16528 protected int computeVerticalScrollExtent() { 16529 return getHeight(); 16530 } 16531 16532 /** 16533 * Check if this view can be scrolled horizontally in a certain direction. 16534 * 16535 * @param direction Negative to check scrolling left, positive to check scrolling right. 16536 * @return true if this view can be scrolled in the specified direction, false otherwise. 16537 */ 16538 public boolean canScrollHorizontally(int direction) { 16539 final int offset = computeHorizontalScrollOffset(); 16540 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 16541 if (range == 0) return false; 16542 if (direction < 0) { 16543 return offset > 0; 16544 } else { 16545 return offset < range - 1; 16546 } 16547 } 16548 16549 /** 16550 * Check if this view can be scrolled vertically in a certain direction. 16551 * 16552 * @param direction Negative to check scrolling up, positive to check scrolling down. 16553 * @return true if this view can be scrolled in the specified direction, false otherwise. 16554 */ 16555 public boolean canScrollVertically(int direction) { 16556 final int offset = computeVerticalScrollOffset(); 16557 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 16558 if (range == 0) return false; 16559 if (direction < 0) { 16560 return offset > 0; 16561 } else { 16562 return offset < range - 1; 16563 } 16564 } 16565 16566 void getScrollIndicatorBounds(@NonNull Rect out) { 16567 out.left = mScrollX; 16568 out.right = mScrollX + mRight - mLeft; 16569 out.top = mScrollY; 16570 out.bottom = mScrollY + mBottom - mTop; 16571 } 16572 16573 private void onDrawScrollIndicators(Canvas c) { 16574 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 16575 // No scroll indicators enabled. 16576 return; 16577 } 16578 16579 final Drawable dr = mScrollIndicatorDrawable; 16580 if (dr == null) { 16581 // Scroll indicators aren't supported here. 16582 return; 16583 } 16584 16585 final int h = dr.getIntrinsicHeight(); 16586 final int w = dr.getIntrinsicWidth(); 16587 final Rect rect = mAttachInfo.mTmpInvalRect; 16588 getScrollIndicatorBounds(rect); 16589 16590 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 16591 final boolean canScrollUp = canScrollVertically(-1); 16592 if (canScrollUp) { 16593 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 16594 dr.draw(c); 16595 } 16596 } 16597 16598 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 16599 final boolean canScrollDown = canScrollVertically(1); 16600 if (canScrollDown) { 16601 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 16602 dr.draw(c); 16603 } 16604 } 16605 16606 final int leftRtl; 16607 final int rightRtl; 16608 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 16609 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 16610 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 16611 } else { 16612 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 16613 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 16614 } 16615 16616 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 16617 if ((mPrivateFlags3 & leftMask) != 0) { 16618 final boolean canScrollLeft = canScrollHorizontally(-1); 16619 if (canScrollLeft) { 16620 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 16621 dr.draw(c); 16622 } 16623 } 16624 16625 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 16626 if ((mPrivateFlags3 & rightMask) != 0) { 16627 final boolean canScrollRight = canScrollHorizontally(1); 16628 if (canScrollRight) { 16629 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 16630 dr.draw(c); 16631 } 16632 } 16633 } 16634 16635 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 16636 @Nullable Rect touchBounds) { 16637 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16638 if (bounds == null) { 16639 return; 16640 } 16641 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16642 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16643 && !isVerticalScrollBarHidden(); 16644 final int size = getHorizontalScrollbarHeight(); 16645 final int verticalScrollBarGap = drawVerticalScrollBar ? 16646 getVerticalScrollbarWidth() : 0; 16647 final int width = mRight - mLeft; 16648 final int height = mBottom - mTop; 16649 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 16650 bounds.left = mScrollX + (mPaddingLeft & inside); 16651 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 16652 bounds.bottom = bounds.top + size; 16653 16654 if (touchBounds == null) { 16655 return; 16656 } 16657 if (touchBounds != bounds) { 16658 touchBounds.set(bounds); 16659 } 16660 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16661 if (touchBounds.height() < minTouchTarget) { 16662 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16663 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 16664 touchBounds.top = touchBounds.bottom - minTouchTarget; 16665 } 16666 if (touchBounds.width() < minTouchTarget) { 16667 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16668 touchBounds.left -= adjust; 16669 touchBounds.right = touchBounds.left + minTouchTarget; 16670 } 16671 } 16672 16673 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 16674 if (mRoundScrollbarRenderer == null) { 16675 getStraightVerticalScrollBarBounds(bounds, touchBounds); 16676 } else { 16677 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 16678 } 16679 } 16680 16681 private void getRoundVerticalScrollBarBounds(Rect bounds) { 16682 final int width = mRight - mLeft; 16683 final int height = mBottom - mTop; 16684 // Do not take padding into account as we always want the scrollbars 16685 // to hug the screen for round wearable devices. 16686 bounds.left = mScrollX; 16687 bounds.top = mScrollY; 16688 bounds.right = bounds.left + width; 16689 bounds.bottom = mScrollY + height; 16690 } 16691 16692 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 16693 @Nullable Rect touchBounds) { 16694 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 16695 if (bounds == null) { 16696 return; 16697 } 16698 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 16699 final int size = getVerticalScrollbarWidth(); 16700 int verticalScrollbarPosition = mVerticalScrollbarPosition; 16701 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 16702 verticalScrollbarPosition = isLayoutRtl() ? 16703 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 16704 } 16705 final int width = mRight - mLeft; 16706 final int height = mBottom - mTop; 16707 switch (verticalScrollbarPosition) { 16708 default: 16709 case SCROLLBAR_POSITION_RIGHT: 16710 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 16711 break; 16712 case SCROLLBAR_POSITION_LEFT: 16713 bounds.left = mScrollX + (mUserPaddingLeft & inside); 16714 break; 16715 } 16716 bounds.top = mScrollY + (mPaddingTop & inside); 16717 bounds.right = bounds.left + size; 16718 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 16719 16720 if (touchBounds == null) { 16721 return; 16722 } 16723 if (touchBounds != bounds) { 16724 touchBounds.set(bounds); 16725 } 16726 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 16727 if (touchBounds.width() < minTouchTarget) { 16728 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 16729 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 16730 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 16731 touchBounds.left = touchBounds.right - minTouchTarget; 16732 } else { 16733 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 16734 touchBounds.right = touchBounds.left + minTouchTarget; 16735 } 16736 } 16737 if (touchBounds.height() < minTouchTarget) { 16738 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 16739 touchBounds.top -= adjust; 16740 touchBounds.bottom = touchBounds.top + minTouchTarget; 16741 } 16742 } 16743 16744 /** 16745 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 16746 * scrollbars are painted only if they have been awakened first.</p> 16747 * 16748 * @param canvas the canvas on which to draw the scrollbars 16749 * 16750 * @see #awakenScrollBars(int) 16751 */ 16752 protected final void onDrawScrollBars(Canvas canvas) { 16753 // scrollbars are drawn only when the animation is running 16754 final ScrollabilityCache cache = mScrollCache; 16755 16756 if (cache != null) { 16757 16758 int state = cache.state; 16759 16760 if (state == ScrollabilityCache.OFF) { 16761 return; 16762 } 16763 16764 boolean invalidate = false; 16765 16766 if (state == ScrollabilityCache.FADING) { 16767 // We're fading -- get our fade interpolation 16768 if (cache.interpolatorValues == null) { 16769 cache.interpolatorValues = new float[1]; 16770 } 16771 16772 float[] values = cache.interpolatorValues; 16773 16774 // Stops the animation if we're done 16775 if (cache.scrollBarInterpolator.timeToValues(values) == 16776 Interpolator.Result.FREEZE_END) { 16777 cache.state = ScrollabilityCache.OFF; 16778 } else { 16779 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 16780 } 16781 16782 // This will make the scroll bars inval themselves after 16783 // drawing. We only want this when we're fading so that 16784 // we prevent excessive redraws 16785 invalidate = true; 16786 } else { 16787 // We're just on -- but we may have been fading before so 16788 // reset alpha 16789 cache.scrollBar.mutate().setAlpha(255); 16790 } 16791 16792 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 16793 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 16794 && !isVerticalScrollBarHidden(); 16795 16796 // Fork out the scroll bar drawing for round wearable devices. 16797 if (mRoundScrollbarRenderer != null) { 16798 if (drawVerticalScrollBar) { 16799 final Rect bounds = cache.mScrollBarBounds; 16800 getVerticalScrollBarBounds(bounds, null); 16801 mRoundScrollbarRenderer.drawRoundScrollbars( 16802 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 16803 if (invalidate) { 16804 invalidate(); 16805 } 16806 } 16807 // Do not draw horizontal scroll bars for round wearable devices. 16808 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 16809 final ScrollBarDrawable scrollBar = cache.scrollBar; 16810 16811 if (drawHorizontalScrollBar) { 16812 scrollBar.setParameters(computeHorizontalScrollRange(), 16813 computeHorizontalScrollOffset(), 16814 computeHorizontalScrollExtent(), false); 16815 final Rect bounds = cache.mScrollBarBounds; 16816 getHorizontalScrollBarBounds(bounds, null); 16817 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16818 bounds.right, bounds.bottom); 16819 if (invalidate) { 16820 invalidate(bounds); 16821 } 16822 } 16823 16824 if (drawVerticalScrollBar) { 16825 scrollBar.setParameters(computeVerticalScrollRange(), 16826 computeVerticalScrollOffset(), 16827 computeVerticalScrollExtent(), true); 16828 final Rect bounds = cache.mScrollBarBounds; 16829 getVerticalScrollBarBounds(bounds, null); 16830 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 16831 bounds.right, bounds.bottom); 16832 if (invalidate) { 16833 invalidate(bounds); 16834 } 16835 } 16836 } 16837 } 16838 } 16839 16840 /** 16841 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 16842 * FastScroller is visible. 16843 * @return whether to temporarily hide the vertical scrollbar 16844 * @hide 16845 */ 16846 protected boolean isVerticalScrollBarHidden() { 16847 return false; 16848 } 16849 16850 /** 16851 * <p>Draw the horizontal scrollbar if 16852 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 16853 * 16854 * @param canvas the canvas on which to draw the scrollbar 16855 * @param scrollBar the scrollbar's drawable 16856 * 16857 * @see #isHorizontalScrollBarEnabled() 16858 * @see #computeHorizontalScrollRange() 16859 * @see #computeHorizontalScrollExtent() 16860 * @see #computeHorizontalScrollOffset() 16861 * @see android.widget.ScrollBarDrawable 16862 * @hide 16863 */ 16864 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 16865 int l, int t, int r, int b) { 16866 scrollBar.setBounds(l, t, r, b); 16867 scrollBar.draw(canvas); 16868 } 16869 16870 /** 16871 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 16872 * returns true.</p> 16873 * 16874 * @param canvas the canvas on which to draw the scrollbar 16875 * @param scrollBar the scrollbar's drawable 16876 * 16877 * @see #isVerticalScrollBarEnabled() 16878 * @see #computeVerticalScrollRange() 16879 * @see #computeVerticalScrollExtent() 16880 * @see #computeVerticalScrollOffset() 16881 * @see android.widget.ScrollBarDrawable 16882 * @hide 16883 */ 16884 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 16885 int l, int t, int r, int b) { 16886 scrollBar.setBounds(l, t, r, b); 16887 scrollBar.draw(canvas); 16888 } 16889 16890 /** 16891 * Implement this to do your drawing. 16892 * 16893 * @param canvas the canvas on which the background will be drawn 16894 */ 16895 protected void onDraw(Canvas canvas) { 16896 } 16897 16898 /* 16899 * Caller is responsible for calling requestLayout if necessary. 16900 * (This allows addViewInLayout to not request a new layout.) 16901 */ 16902 void assignParent(ViewParent parent) { 16903 if (mParent == null) { 16904 mParent = parent; 16905 } else if (parent == null) { 16906 mParent = null; 16907 } else { 16908 throw new RuntimeException("view " + this + " being added, but" 16909 + " it already has a parent"); 16910 } 16911 } 16912 16913 /** 16914 * This is called when the view is attached to a window. At this point it 16915 * has a Surface and will start drawing. Note that this function is 16916 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 16917 * however it may be called any time before the first onDraw -- including 16918 * before or after {@link #onMeasure(int, int)}. 16919 * 16920 * @see #onDetachedFromWindow() 16921 */ 16922 @CallSuper 16923 protected void onAttachedToWindow() { 16924 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 16925 mParent.requestTransparentRegion(this); 16926 } 16927 16928 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 16929 16930 jumpDrawablesToCurrentState(); 16931 16932 resetSubtreeAccessibilityStateChanged(); 16933 16934 // rebuild, since Outline not maintained while View is detached 16935 rebuildOutline(); 16936 16937 if (isFocused()) { 16938 InputMethodManager imm = InputMethodManager.peekInstance(); 16939 if (imm != null) { 16940 imm.focusIn(this); 16941 } 16942 } 16943 } 16944 16945 /** 16946 * Resolve all RTL related properties. 16947 * 16948 * @return true if resolution of RTL properties has been done 16949 * 16950 * @hide 16951 */ 16952 public boolean resolveRtlPropertiesIfNeeded() { 16953 if (!needRtlPropertiesResolution()) return false; 16954 16955 // Order is important here: LayoutDirection MUST be resolved first 16956 if (!isLayoutDirectionResolved()) { 16957 resolveLayoutDirection(); 16958 resolveLayoutParams(); 16959 } 16960 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 16961 if (!isTextDirectionResolved()) { 16962 resolveTextDirection(); 16963 } 16964 if (!isTextAlignmentResolved()) { 16965 resolveTextAlignment(); 16966 } 16967 // Should resolve Drawables before Padding because we need the layout direction of the 16968 // Drawable to correctly resolve Padding. 16969 if (!areDrawablesResolved()) { 16970 resolveDrawables(); 16971 } 16972 if (!isPaddingResolved()) { 16973 resolvePadding(); 16974 } 16975 onRtlPropertiesChanged(getLayoutDirection()); 16976 return true; 16977 } 16978 16979 /** 16980 * Reset resolution of all RTL related properties. 16981 * 16982 * @hide 16983 */ 16984 public void resetRtlProperties() { 16985 resetResolvedLayoutDirection(); 16986 resetResolvedTextDirection(); 16987 resetResolvedTextAlignment(); 16988 resetResolvedPadding(); 16989 resetResolvedDrawables(); 16990 } 16991 16992 /** 16993 * @see #onScreenStateChanged(int) 16994 */ 16995 void dispatchScreenStateChanged(int screenState) { 16996 onScreenStateChanged(screenState); 16997 } 16998 16999 /** 17000 * This method is called whenever the state of the screen this view is 17001 * attached to changes. A state change will usually occurs when the screen 17002 * turns on or off (whether it happens automatically or the user does it 17003 * manually.) 17004 * 17005 * @param screenState The new state of the screen. Can be either 17006 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 17007 */ 17008 public void onScreenStateChanged(int screenState) { 17009 } 17010 17011 /** 17012 * @see #onMovedToDisplay(int, Configuration) 17013 */ 17014 void dispatchMovedToDisplay(Display display, Configuration config) { 17015 mAttachInfo.mDisplay = display; 17016 mAttachInfo.mDisplayState = display.getState(); 17017 onMovedToDisplay(display.getDisplayId(), config); 17018 } 17019 17020 /** 17021 * Called by the system when the hosting activity is moved from one display to another without 17022 * recreation. This means that the activity is declared to handle all changes to configuration 17023 * that happened when it was switched to another display, so it wasn't destroyed and created 17024 * again. 17025 * 17026 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 17027 * applied configuration actually changed. It is up to app developer to choose whether to handle 17028 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 17029 * call. 17030 * 17031 * <p>Use this callback to track changes to the displays if some functionality relies on an 17032 * association with some display properties. 17033 * 17034 * @param displayId The id of the display to which the view was moved. 17035 * @param config Configuration of the resources on new display after move. 17036 * 17037 * @see #onConfigurationChanged(Configuration) 17038 * @hide 17039 */ 17040 public void onMovedToDisplay(int displayId, Configuration config) { 17041 } 17042 17043 /** 17044 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 17045 */ 17046 private boolean hasRtlSupport() { 17047 return mContext.getApplicationInfo().hasRtlSupport(); 17048 } 17049 17050 /** 17051 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 17052 * RTL not supported) 17053 */ 17054 private boolean isRtlCompatibilityMode() { 17055 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 17056 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 17057 } 17058 17059 /** 17060 * @return true if RTL properties need resolution. 17061 * 17062 */ 17063 private boolean needRtlPropertiesResolution() { 17064 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 17065 } 17066 17067 /** 17068 * Called when any RTL property (layout direction or text direction or text alignment) has 17069 * been changed. 17070 * 17071 * Subclasses need to override this method to take care of cached information that depends on the 17072 * resolved layout direction, or to inform child views that inherit their layout direction. 17073 * 17074 * The default implementation does nothing. 17075 * 17076 * @param layoutDirection the direction of the layout 17077 * 17078 * @see #LAYOUT_DIRECTION_LTR 17079 * @see #LAYOUT_DIRECTION_RTL 17080 */ 17081 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 17082 } 17083 17084 /** 17085 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 17086 * that the parent directionality can and will be resolved before its children. 17087 * 17088 * @return true if resolution has been done, false otherwise. 17089 * 17090 * @hide 17091 */ 17092 public boolean resolveLayoutDirection() { 17093 // Clear any previous layout direction resolution 17094 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17095 17096 if (hasRtlSupport()) { 17097 // Set resolved depending on layout direction 17098 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 17099 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 17100 case LAYOUT_DIRECTION_INHERIT: 17101 // We cannot resolve yet. LTR is by default and let the resolution happen again 17102 // later to get the correct resolved value 17103 if (!canResolveLayoutDirection()) return false; 17104 17105 // Parent has not yet resolved, LTR is still the default 17106 try { 17107 if (!mParent.isLayoutDirectionResolved()) return false; 17108 17109 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 17110 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17111 } 17112 } catch (AbstractMethodError e) { 17113 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17114 " does not fully implement ViewParent", e); 17115 } 17116 break; 17117 case LAYOUT_DIRECTION_RTL: 17118 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17119 break; 17120 case LAYOUT_DIRECTION_LOCALE: 17121 if((LAYOUT_DIRECTION_RTL == 17122 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 17123 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 17124 } 17125 break; 17126 default: 17127 // Nothing to do, LTR by default 17128 } 17129 } 17130 17131 // Set to resolved 17132 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17133 return true; 17134 } 17135 17136 /** 17137 * Check if layout direction resolution can be done. 17138 * 17139 * @return true if layout direction resolution can be done otherwise return false. 17140 */ 17141 public boolean canResolveLayoutDirection() { 17142 switch (getRawLayoutDirection()) { 17143 case LAYOUT_DIRECTION_INHERIT: 17144 if (mParent != null) { 17145 try { 17146 return mParent.canResolveLayoutDirection(); 17147 } catch (AbstractMethodError e) { 17148 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 17149 " does not fully implement ViewParent", e); 17150 } 17151 } 17152 return false; 17153 17154 default: 17155 return true; 17156 } 17157 } 17158 17159 /** 17160 * Reset the resolved layout direction. Layout direction will be resolved during a call to 17161 * {@link #onMeasure(int, int)}. 17162 * 17163 * @hide 17164 */ 17165 public void resetResolvedLayoutDirection() { 17166 // Reset the current resolved bits 17167 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 17168 } 17169 17170 /** 17171 * @return true if the layout direction is inherited. 17172 * 17173 * @hide 17174 */ 17175 public boolean isLayoutDirectionInherited() { 17176 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 17177 } 17178 17179 /** 17180 * @return true if layout direction has been resolved. 17181 */ 17182 public boolean isLayoutDirectionResolved() { 17183 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 17184 } 17185 17186 /** 17187 * Return if padding has been resolved 17188 * 17189 * @hide 17190 */ 17191 boolean isPaddingResolved() { 17192 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 17193 } 17194 17195 /** 17196 * Resolves padding depending on layout direction, if applicable, and 17197 * recomputes internal padding values to adjust for scroll bars. 17198 * 17199 * @hide 17200 */ 17201 public void resolvePadding() { 17202 final int resolvedLayoutDirection = getLayoutDirection(); 17203 17204 if (!isRtlCompatibilityMode()) { 17205 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 17206 // If start / end padding are defined, they will be resolved (hence overriding) to 17207 // left / right or right / left depending on the resolved layout direction. 17208 // If start / end padding are not defined, use the left / right ones. 17209 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 17210 Rect padding = sThreadLocal.get(); 17211 if (padding == null) { 17212 padding = new Rect(); 17213 sThreadLocal.set(padding); 17214 } 17215 mBackground.getPadding(padding); 17216 if (!mLeftPaddingDefined) { 17217 mUserPaddingLeftInitial = padding.left; 17218 } 17219 if (!mRightPaddingDefined) { 17220 mUserPaddingRightInitial = padding.right; 17221 } 17222 } 17223 switch (resolvedLayoutDirection) { 17224 case LAYOUT_DIRECTION_RTL: 17225 if (mUserPaddingStart != UNDEFINED_PADDING) { 17226 mUserPaddingRight = mUserPaddingStart; 17227 } else { 17228 mUserPaddingRight = mUserPaddingRightInitial; 17229 } 17230 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17231 mUserPaddingLeft = mUserPaddingEnd; 17232 } else { 17233 mUserPaddingLeft = mUserPaddingLeftInitial; 17234 } 17235 break; 17236 case LAYOUT_DIRECTION_LTR: 17237 default: 17238 if (mUserPaddingStart != UNDEFINED_PADDING) { 17239 mUserPaddingLeft = mUserPaddingStart; 17240 } else { 17241 mUserPaddingLeft = mUserPaddingLeftInitial; 17242 } 17243 if (mUserPaddingEnd != UNDEFINED_PADDING) { 17244 mUserPaddingRight = mUserPaddingEnd; 17245 } else { 17246 mUserPaddingRight = mUserPaddingRightInitial; 17247 } 17248 } 17249 17250 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 17251 } 17252 17253 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 17254 onRtlPropertiesChanged(resolvedLayoutDirection); 17255 17256 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 17257 } 17258 17259 /** 17260 * Reset the resolved layout direction. 17261 * 17262 * @hide 17263 */ 17264 public void resetResolvedPadding() { 17265 resetResolvedPaddingInternal(); 17266 } 17267 17268 /** 17269 * Used when we only want to reset *this* view's padding and not trigger overrides 17270 * in ViewGroup that reset children too. 17271 */ 17272 void resetResolvedPaddingInternal() { 17273 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 17274 } 17275 17276 /** 17277 * This is called when the view is detached from a window. At this point it 17278 * no longer has a surface for drawing. 17279 * 17280 * @see #onAttachedToWindow() 17281 */ 17282 @CallSuper 17283 protected void onDetachedFromWindow() { 17284 } 17285 17286 /** 17287 * This is a framework-internal mirror of onDetachedFromWindow() that's called 17288 * after onDetachedFromWindow(). 17289 * 17290 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 17291 * The super method should be called at the end of the overridden method to ensure 17292 * subclasses are destroyed first 17293 * 17294 * @hide 17295 */ 17296 @CallSuper 17297 protected void onDetachedFromWindowInternal() { 17298 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 17299 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 17300 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 17301 17302 removeUnsetPressCallback(); 17303 removeLongPressCallback(); 17304 removePerformClickCallback(); 17305 removeSendViewScrolledAccessibilityEventCallback(); 17306 stopNestedScroll(); 17307 17308 // Anything that started animating right before detach should already 17309 // be in its final state when re-attached. 17310 jumpDrawablesToCurrentState(); 17311 17312 destroyDrawingCache(); 17313 17314 cleanupDraw(); 17315 mCurrentAnimation = null; 17316 17317 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 17318 hideTooltip(); 17319 } 17320 } 17321 17322 private void cleanupDraw() { 17323 resetDisplayList(); 17324 if (mAttachInfo != null) { 17325 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 17326 } 17327 } 17328 17329 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 17330 } 17331 17332 /** 17333 * @return The number of times this view has been attached to a window 17334 */ 17335 protected int getWindowAttachCount() { 17336 return mWindowAttachCount; 17337 } 17338 17339 /** 17340 * Retrieve a unique token identifying the window this view is attached to. 17341 * @return Return the window's token for use in 17342 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 17343 */ 17344 public IBinder getWindowToken() { 17345 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 17346 } 17347 17348 /** 17349 * Retrieve the {@link WindowId} for the window this view is 17350 * currently attached to. 17351 */ 17352 public WindowId getWindowId() { 17353 if (mAttachInfo == null) { 17354 return null; 17355 } 17356 if (mAttachInfo.mWindowId == null) { 17357 try { 17358 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 17359 mAttachInfo.mWindowToken); 17360 mAttachInfo.mWindowId = new WindowId( 17361 mAttachInfo.mIWindowId); 17362 } catch (RemoteException e) { 17363 } 17364 } 17365 return mAttachInfo.mWindowId; 17366 } 17367 17368 /** 17369 * Retrieve a unique token identifying the top-level "real" window of 17370 * the window that this view is attached to. That is, this is like 17371 * {@link #getWindowToken}, except if the window this view in is a panel 17372 * window (attached to another containing window), then the token of 17373 * the containing window is returned instead. 17374 * 17375 * @return Returns the associated window token, either 17376 * {@link #getWindowToken()} or the containing window's token. 17377 */ 17378 public IBinder getApplicationWindowToken() { 17379 AttachInfo ai = mAttachInfo; 17380 if (ai != null) { 17381 IBinder appWindowToken = ai.mPanelParentWindowToken; 17382 if (appWindowToken == null) { 17383 appWindowToken = ai.mWindowToken; 17384 } 17385 return appWindowToken; 17386 } 17387 return null; 17388 } 17389 17390 /** 17391 * Gets the logical display to which the view's window has been attached. 17392 * 17393 * @return The logical display, or null if the view is not currently attached to a window. 17394 */ 17395 public Display getDisplay() { 17396 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 17397 } 17398 17399 /** 17400 * Retrieve private session object this view hierarchy is using to 17401 * communicate with the window manager. 17402 * @return the session object to communicate with the window manager 17403 */ 17404 /*package*/ IWindowSession getWindowSession() { 17405 return mAttachInfo != null ? mAttachInfo.mSession : null; 17406 } 17407 17408 /** 17409 * Return the visibility value of the least visible component passed. 17410 */ 17411 int combineVisibility(int vis1, int vis2) { 17412 // This works because VISIBLE < INVISIBLE < GONE. 17413 return Math.max(vis1, vis2); 17414 } 17415 17416 /** 17417 * @param info the {@link android.view.View.AttachInfo} to associated with 17418 * this view 17419 */ 17420 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 17421 mAttachInfo = info; 17422 if (mOverlay != null) { 17423 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 17424 } 17425 mWindowAttachCount++; 17426 // We will need to evaluate the drawable state at least once. 17427 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 17428 if (mFloatingTreeObserver != null) { 17429 info.mTreeObserver.merge(mFloatingTreeObserver); 17430 mFloatingTreeObserver = null; 17431 } 17432 17433 registerPendingFrameMetricsObservers(); 17434 17435 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 17436 mAttachInfo.mScrollContainers.add(this); 17437 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 17438 } 17439 // Transfer all pending runnables. 17440 if (mRunQueue != null) { 17441 mRunQueue.executeActions(info.mHandler); 17442 mRunQueue = null; 17443 } 17444 performCollectViewAttributes(mAttachInfo, visibility); 17445 onAttachedToWindow(); 17446 17447 ListenerInfo li = mListenerInfo; 17448 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17449 li != null ? li.mOnAttachStateChangeListeners : null; 17450 if (listeners != null && listeners.size() > 0) { 17451 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17452 // perform the dispatching. The iterator is a safe guard against listeners that 17453 // could mutate the list by calling the various add/remove methods. This prevents 17454 // the array from being modified while we iterate it. 17455 for (OnAttachStateChangeListener listener : listeners) { 17456 listener.onViewAttachedToWindow(this); 17457 } 17458 } 17459 17460 int vis = info.mWindowVisibility; 17461 if (vis != GONE) { 17462 onWindowVisibilityChanged(vis); 17463 if (isShown()) { 17464 // Calling onVisibilityAggregated directly here since the subtree will also 17465 // receive dispatchAttachedToWindow and this same call 17466 onVisibilityAggregated(vis == VISIBLE); 17467 } 17468 } 17469 17470 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 17471 // As all views in the subtree will already receive dispatchAttachedToWindow 17472 // traversing the subtree again here is not desired. 17473 onVisibilityChanged(this, visibility); 17474 17475 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 17476 // If nobody has evaluated the drawable state yet, then do it now. 17477 refreshDrawableState(); 17478 } 17479 needGlobalAttributesUpdate(false); 17480 17481 notifyEnterOrExitForAutoFillIfNeeded(true); 17482 } 17483 17484 void dispatchDetachedFromWindow() { 17485 AttachInfo info = mAttachInfo; 17486 if (info != null) { 17487 int vis = info.mWindowVisibility; 17488 if (vis != GONE) { 17489 onWindowVisibilityChanged(GONE); 17490 if (isShown()) { 17491 // Invoking onVisibilityAggregated directly here since the subtree 17492 // will also receive detached from window 17493 onVisibilityAggregated(false); 17494 } 17495 } 17496 } 17497 17498 onDetachedFromWindow(); 17499 onDetachedFromWindowInternal(); 17500 17501 InputMethodManager imm = InputMethodManager.peekInstance(); 17502 if (imm != null) { 17503 imm.onViewDetachedFromWindow(this); 17504 } 17505 17506 ListenerInfo li = mListenerInfo; 17507 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 17508 li != null ? li.mOnAttachStateChangeListeners : null; 17509 if (listeners != null && listeners.size() > 0) { 17510 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 17511 // perform the dispatching. The iterator is a safe guard against listeners that 17512 // could mutate the list by calling the various add/remove methods. This prevents 17513 // the array from being modified while we iterate it. 17514 for (OnAttachStateChangeListener listener : listeners) { 17515 listener.onViewDetachedFromWindow(this); 17516 } 17517 } 17518 17519 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 17520 mAttachInfo.mScrollContainers.remove(this); 17521 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 17522 } 17523 17524 mAttachInfo = null; 17525 if (mOverlay != null) { 17526 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 17527 } 17528 17529 notifyEnterOrExitForAutoFillIfNeeded(false); 17530 } 17531 17532 /** 17533 * Cancel any deferred high-level input events that were previously posted to the event queue. 17534 * 17535 * <p>Many views post high-level events such as click handlers to the event queue 17536 * to run deferred in order to preserve a desired user experience - clearing visible 17537 * pressed states before executing, etc. This method will abort any events of this nature 17538 * that are currently in flight.</p> 17539 * 17540 * <p>Custom views that generate their own high-level deferred input events should override 17541 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 17542 * 17543 * <p>This will also cancel pending input events for any child views.</p> 17544 * 17545 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 17546 * This will not impact newer events posted after this call that may occur as a result of 17547 * lower-level input events still waiting in the queue. If you are trying to prevent 17548 * double-submitted events for the duration of some sort of asynchronous transaction 17549 * you should also take other steps to protect against unexpected double inputs e.g. calling 17550 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 17551 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 17552 */ 17553 public final void cancelPendingInputEvents() { 17554 dispatchCancelPendingInputEvents(); 17555 } 17556 17557 /** 17558 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 17559 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 17560 */ 17561 void dispatchCancelPendingInputEvents() { 17562 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 17563 onCancelPendingInputEvents(); 17564 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 17565 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 17566 " did not call through to super.onCancelPendingInputEvents()"); 17567 } 17568 } 17569 17570 /** 17571 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 17572 * a parent view. 17573 * 17574 * <p>This method is responsible for removing any pending high-level input events that were 17575 * posted to the event queue to run later. Custom view classes that post their own deferred 17576 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 17577 * {@link android.os.Handler} should override this method, call 17578 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 17579 * </p> 17580 */ 17581 public void onCancelPendingInputEvents() { 17582 removePerformClickCallback(); 17583 cancelLongPress(); 17584 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 17585 } 17586 17587 /** 17588 * Store this view hierarchy's frozen state into the given container. 17589 * 17590 * @param container The SparseArray in which to save the view's state. 17591 * 17592 * @see #restoreHierarchyState(android.util.SparseArray) 17593 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17594 * @see #onSaveInstanceState() 17595 */ 17596 public void saveHierarchyState(SparseArray<Parcelable> container) { 17597 dispatchSaveInstanceState(container); 17598 } 17599 17600 /** 17601 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 17602 * this view and its children. May be overridden to modify how freezing happens to a 17603 * view's children; for example, some views may want to not store state for their children. 17604 * 17605 * @param container The SparseArray in which to save the view's state. 17606 * 17607 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17608 * @see #saveHierarchyState(android.util.SparseArray) 17609 * @see #onSaveInstanceState() 17610 */ 17611 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 17612 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 17613 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17614 Parcelable state = onSaveInstanceState(); 17615 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17616 throw new IllegalStateException( 17617 "Derived class did not call super.onSaveInstanceState()"); 17618 } 17619 if (state != null) { 17620 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 17621 // + ": " + state); 17622 container.put(mID, state); 17623 } 17624 } 17625 } 17626 17627 /** 17628 * Hook allowing a view to generate a representation of its internal state 17629 * that can later be used to create a new instance with that same state. 17630 * This state should only contain information that is not persistent or can 17631 * not be reconstructed later. For example, you will never store your 17632 * current position on screen because that will be computed again when a 17633 * new instance of the view is placed in its view hierarchy. 17634 * <p> 17635 * Some examples of things you may store here: the current cursor position 17636 * in a text view (but usually not the text itself since that is stored in a 17637 * content provider or other persistent storage), the currently selected 17638 * item in a list view. 17639 * 17640 * @return Returns a Parcelable object containing the view's current dynamic 17641 * state, or null if there is nothing interesting to save. 17642 * @see #onRestoreInstanceState(Parcelable) 17643 * @see #saveHierarchyState(SparseArray) 17644 * @see #dispatchSaveInstanceState(SparseArray) 17645 * @see #setSaveEnabled(boolean) 17646 */ 17647 @CallSuper 17648 @Nullable protected Parcelable onSaveInstanceState() { 17649 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17650 if (mStartActivityRequestWho != null || isAutofilled() 17651 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 17652 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 17653 17654 if (mStartActivityRequestWho != null) { 17655 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 17656 } 17657 17658 if (isAutofilled()) { 17659 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 17660 } 17661 17662 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 17663 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 17664 } 17665 17666 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 17667 state.mIsAutofilled = isAutofilled(); 17668 state.mAutofillViewId = mAutofillViewId; 17669 return state; 17670 } 17671 return BaseSavedState.EMPTY_STATE; 17672 } 17673 17674 /** 17675 * Restore this view hierarchy's frozen state from the given container. 17676 * 17677 * @param container The SparseArray which holds previously frozen states. 17678 * 17679 * @see #saveHierarchyState(android.util.SparseArray) 17680 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17681 * @see #onRestoreInstanceState(android.os.Parcelable) 17682 */ 17683 public void restoreHierarchyState(SparseArray<Parcelable> container) { 17684 dispatchRestoreInstanceState(container); 17685 } 17686 17687 /** 17688 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 17689 * state for this view and its children. May be overridden to modify how restoring 17690 * happens to a view's children; for example, some views may want to not store state 17691 * for their children. 17692 * 17693 * @param container The SparseArray which holds previously saved state. 17694 * 17695 * @see #dispatchSaveInstanceState(android.util.SparseArray) 17696 * @see #restoreHierarchyState(android.util.SparseArray) 17697 * @see #onRestoreInstanceState(android.os.Parcelable) 17698 */ 17699 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 17700 if (mID != NO_ID) { 17701 Parcelable state = container.get(mID); 17702 if (state != null) { 17703 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 17704 // + ": " + state); 17705 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 17706 onRestoreInstanceState(state); 17707 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 17708 throw new IllegalStateException( 17709 "Derived class did not call super.onRestoreInstanceState()"); 17710 } 17711 } 17712 } 17713 } 17714 17715 /** 17716 * Hook allowing a view to re-apply a representation of its internal state that had previously 17717 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 17718 * null state. 17719 * 17720 * @param state The frozen state that had previously been returned by 17721 * {@link #onSaveInstanceState}. 17722 * 17723 * @see #onSaveInstanceState() 17724 * @see #restoreHierarchyState(android.util.SparseArray) 17725 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 17726 */ 17727 @CallSuper 17728 protected void onRestoreInstanceState(Parcelable state) { 17729 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 17730 if (state != null && !(state instanceof AbsSavedState)) { 17731 throw new IllegalArgumentException("Wrong state class, expecting View State but " 17732 + "received " + state.getClass().toString() + " instead. This usually happens " 17733 + "when two views of different type have the same id in the same hierarchy. " 17734 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 17735 + "other views do not use the same id."); 17736 } 17737 if (state != null && state instanceof BaseSavedState) { 17738 BaseSavedState baseState = (BaseSavedState) state; 17739 17740 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 17741 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 17742 } 17743 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 17744 setAutofilled(baseState.mIsAutofilled); 17745 } 17746 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 17747 // It can happen that views have the same view id and the restoration path will not 17748 // be able to distinguish between them. The autofill id needs to be unique though. 17749 // Hence prevent the same autofill view id from being restored multiple times. 17750 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 17751 17752 mAutofillViewId = baseState.mAutofillViewId; 17753 } 17754 } 17755 } 17756 17757 /** 17758 * <p>Return the time at which the drawing of the view hierarchy started.</p> 17759 * 17760 * @return the drawing start time in milliseconds 17761 */ 17762 public long getDrawingTime() { 17763 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 17764 } 17765 17766 /** 17767 * <p>Enables or disables the duplication of the parent's state into this view. When 17768 * duplication is enabled, this view gets its drawable state from its parent rather 17769 * than from its own internal properties.</p> 17770 * 17771 * <p>Note: in the current implementation, setting this property to true after the 17772 * view was added to a ViewGroup might have no effect at all. This property should 17773 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 17774 * 17775 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 17776 * property is enabled, an exception will be thrown.</p> 17777 * 17778 * <p>Note: if the child view uses and updates additional states which are unknown to the 17779 * parent, these states should not be affected by this method.</p> 17780 * 17781 * @param enabled True to enable duplication of the parent's drawable state, false 17782 * to disable it. 17783 * 17784 * @see #getDrawableState() 17785 * @see #isDuplicateParentStateEnabled() 17786 */ 17787 public void setDuplicateParentStateEnabled(boolean enabled) { 17788 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 17789 } 17790 17791 /** 17792 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 17793 * 17794 * @return True if this view's drawable state is duplicated from the parent, 17795 * false otherwise 17796 * 17797 * @see #getDrawableState() 17798 * @see #setDuplicateParentStateEnabled(boolean) 17799 */ 17800 public boolean isDuplicateParentStateEnabled() { 17801 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 17802 } 17803 17804 /** 17805 * <p>Specifies the type of layer backing this view. The layer can be 17806 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17807 * {@link #LAYER_TYPE_HARDWARE}.</p> 17808 * 17809 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17810 * instance that controls how the layer is composed on screen. The following 17811 * properties of the paint are taken into account when composing the layer:</p> 17812 * <ul> 17813 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17814 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17815 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17816 * </ul> 17817 * 17818 * <p>If this view has an alpha value set to < 1.0 by calling 17819 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 17820 * by this view's alpha value.</p> 17821 * 17822 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 17823 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 17824 * for more information on when and how to use layers.</p> 17825 * 17826 * @param layerType The type of layer to use with this view, must be one of 17827 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17828 * {@link #LAYER_TYPE_HARDWARE} 17829 * @param paint The paint used to compose the layer. This argument is optional 17830 * and can be null. It is ignored when the layer type is 17831 * {@link #LAYER_TYPE_NONE} 17832 * 17833 * @see #getLayerType() 17834 * @see #LAYER_TYPE_NONE 17835 * @see #LAYER_TYPE_SOFTWARE 17836 * @see #LAYER_TYPE_HARDWARE 17837 * @see #setAlpha(float) 17838 * 17839 * @attr ref android.R.styleable#View_layerType 17840 */ 17841 public void setLayerType(int layerType, @Nullable Paint paint) { 17842 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 17843 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 17844 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 17845 } 17846 17847 boolean typeChanged = mRenderNode.setLayerType(layerType); 17848 17849 if (!typeChanged) { 17850 setLayerPaint(paint); 17851 return; 17852 } 17853 17854 if (layerType != LAYER_TYPE_SOFTWARE) { 17855 // Destroy any previous software drawing cache if present 17856 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 17857 // drawing cache created in View#draw when drawing to a SW canvas. 17858 destroyDrawingCache(); 17859 } 17860 17861 mLayerType = layerType; 17862 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 17863 mRenderNode.setLayerPaint(mLayerPaint); 17864 17865 // draw() behaves differently if we are on a layer, so we need to 17866 // invalidate() here 17867 invalidateParentCaches(); 17868 invalidate(true); 17869 } 17870 17871 /** 17872 * Updates the {@link Paint} object used with the current layer (used only if the current 17873 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 17874 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 17875 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 17876 * ensure that the view gets redrawn immediately. 17877 * 17878 * <p>A layer is associated with an optional {@link android.graphics.Paint} 17879 * instance that controls how the layer is composed on screen. The following 17880 * properties of the paint are taken into account when composing the layer:</p> 17881 * <ul> 17882 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 17883 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 17884 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 17885 * </ul> 17886 * 17887 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 17888 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 17889 * 17890 * @param paint The paint used to compose the layer. This argument is optional 17891 * and can be null. It is ignored when the layer type is 17892 * {@link #LAYER_TYPE_NONE} 17893 * 17894 * @see #setLayerType(int, android.graphics.Paint) 17895 */ 17896 public void setLayerPaint(@Nullable Paint paint) { 17897 int layerType = getLayerType(); 17898 if (layerType != LAYER_TYPE_NONE) { 17899 mLayerPaint = paint; 17900 if (layerType == LAYER_TYPE_HARDWARE) { 17901 if (mRenderNode.setLayerPaint(paint)) { 17902 invalidateViewProperty(false, false); 17903 } 17904 } else { 17905 invalidate(); 17906 } 17907 } 17908 } 17909 17910 /** 17911 * Indicates what type of layer is currently associated with this view. By default 17912 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 17913 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 17914 * for more information on the different types of layers. 17915 * 17916 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 17917 * {@link #LAYER_TYPE_HARDWARE} 17918 * 17919 * @see #setLayerType(int, android.graphics.Paint) 17920 * @see #buildLayer() 17921 * @see #LAYER_TYPE_NONE 17922 * @see #LAYER_TYPE_SOFTWARE 17923 * @see #LAYER_TYPE_HARDWARE 17924 */ 17925 public int getLayerType() { 17926 return mLayerType; 17927 } 17928 17929 /** 17930 * Forces this view's layer to be created and this view to be rendered 17931 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 17932 * invoking this method will have no effect. 17933 * 17934 * This method can for instance be used to render a view into its layer before 17935 * starting an animation. If this view is complex, rendering into the layer 17936 * before starting the animation will avoid skipping frames. 17937 * 17938 * @throws IllegalStateException If this view is not attached to a window 17939 * 17940 * @see #setLayerType(int, android.graphics.Paint) 17941 */ 17942 public void buildLayer() { 17943 if (mLayerType == LAYER_TYPE_NONE) return; 17944 17945 final AttachInfo attachInfo = mAttachInfo; 17946 if (attachInfo == null) { 17947 throw new IllegalStateException("This view must be attached to a window first"); 17948 } 17949 17950 if (getWidth() == 0 || getHeight() == 0) { 17951 return; 17952 } 17953 17954 switch (mLayerType) { 17955 case LAYER_TYPE_HARDWARE: 17956 updateDisplayListIfDirty(); 17957 if (attachInfo.mThreadedRenderer != null && mRenderNode.isValid()) { 17958 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 17959 } 17960 break; 17961 case LAYER_TYPE_SOFTWARE: 17962 buildDrawingCache(true); 17963 break; 17964 } 17965 } 17966 17967 /** 17968 * Destroys all hardware rendering resources. This method is invoked 17969 * when the system needs to reclaim resources. Upon execution of this 17970 * method, you should free any OpenGL resources created by the view. 17971 * 17972 * Note: you <strong>must</strong> call 17973 * <code>super.destroyHardwareResources()</code> when overriding 17974 * this method. 17975 * 17976 * @hide 17977 */ 17978 @CallSuper 17979 protected void destroyHardwareResources() { 17980 if (mOverlay != null) { 17981 mOverlay.getOverlayView().destroyHardwareResources(); 17982 } 17983 if (mGhostView != null) { 17984 mGhostView.destroyHardwareResources(); 17985 } 17986 } 17987 17988 /** 17989 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 17990 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 17991 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 17992 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 17993 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 17994 * null.</p> 17995 * 17996 * <p>Enabling the drawing cache is similar to 17997 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 17998 * acceleration is turned off. When hardware acceleration is turned on, enabling the 17999 * drawing cache has no effect on rendering because the system uses a different mechanism 18000 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 18001 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 18002 * for information on how to enable software and hardware layers.</p> 18003 * 18004 * <p>This API can be used to manually generate 18005 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 18006 * {@link #getDrawingCache()}.</p> 18007 * 18008 * @param enabled true to enable the drawing cache, false otherwise 18009 * 18010 * @see #isDrawingCacheEnabled() 18011 * @see #getDrawingCache() 18012 * @see #buildDrawingCache() 18013 * @see #setLayerType(int, android.graphics.Paint) 18014 */ 18015 public void setDrawingCacheEnabled(boolean enabled) { 18016 mCachingFailed = false; 18017 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 18018 } 18019 18020 /** 18021 * <p>Indicates whether the drawing cache is enabled for this view.</p> 18022 * 18023 * @return true if the drawing cache is enabled 18024 * 18025 * @see #setDrawingCacheEnabled(boolean) 18026 * @see #getDrawingCache() 18027 */ 18028 @ViewDebug.ExportedProperty(category = "drawing") 18029 public boolean isDrawingCacheEnabled() { 18030 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 18031 } 18032 18033 /** 18034 * Debugging utility which recursively outputs the dirty state of a view and its 18035 * descendants. 18036 * 18037 * @hide 18038 */ 18039 @SuppressWarnings({"UnusedDeclaration"}) 18040 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 18041 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 18042 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 18043 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 18044 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 18045 if (clear) { 18046 mPrivateFlags &= clearMask; 18047 } 18048 if (this instanceof ViewGroup) { 18049 ViewGroup parent = (ViewGroup) this; 18050 final int count = parent.getChildCount(); 18051 for (int i = 0; i < count; i++) { 18052 final View child = parent.getChildAt(i); 18053 child.outputDirtyFlags(indent + " ", clear, clearMask); 18054 } 18055 } 18056 } 18057 18058 /** 18059 * This method is used by ViewGroup to cause its children to restore or recreate their 18060 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 18061 * to recreate its own display list, which would happen if it went through the normal 18062 * draw/dispatchDraw mechanisms. 18063 * 18064 * @hide 18065 */ 18066 protected void dispatchGetDisplayList() {} 18067 18068 /** 18069 * A view that is not attached or hardware accelerated cannot create a display list. 18070 * This method checks these conditions and returns the appropriate result. 18071 * 18072 * @return true if view has the ability to create a display list, false otherwise. 18073 * 18074 * @hide 18075 */ 18076 public boolean canHaveDisplayList() { 18077 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 18078 } 18079 18080 /** 18081 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 18082 * @hide 18083 */ 18084 @NonNull 18085 public RenderNode updateDisplayListIfDirty() { 18086 final RenderNode renderNode = mRenderNode; 18087 if (!canHaveDisplayList()) { 18088 // can't populate RenderNode, don't try 18089 return renderNode; 18090 } 18091 18092 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 18093 || !renderNode.isValid() 18094 || (mRecreateDisplayList)) { 18095 // Don't need to recreate the display list, just need to tell our 18096 // children to restore/recreate theirs 18097 if (renderNode.isValid() 18098 && !mRecreateDisplayList) { 18099 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18100 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18101 dispatchGetDisplayList(); 18102 18103 return renderNode; // no work needed 18104 } 18105 18106 // If we got here, we're recreating it. Mark it as such to ensure that 18107 // we copy in child display lists into ours in drawChild() 18108 mRecreateDisplayList = true; 18109 18110 int width = mRight - mLeft; 18111 int height = mBottom - mTop; 18112 int layerType = getLayerType(); 18113 18114 final DisplayListCanvas canvas = renderNode.start(width, height); 18115 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 18116 18117 try { 18118 if (layerType == LAYER_TYPE_SOFTWARE) { 18119 buildDrawingCache(true); 18120 Bitmap cache = getDrawingCache(true); 18121 if (cache != null) { 18122 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 18123 } 18124 } else { 18125 computeScroll(); 18126 18127 canvas.translate(-mScrollX, -mScrollY); 18128 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18129 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18130 18131 // Fast path for layouts with no backgrounds 18132 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18133 dispatchDraw(canvas); 18134 drawAutofilledHighlight(canvas); 18135 if (mOverlay != null && !mOverlay.isEmpty()) { 18136 mOverlay.getOverlayView().draw(canvas); 18137 } 18138 if (debugDraw()) { 18139 debugDrawFocus(canvas); 18140 } 18141 } else { 18142 draw(canvas); 18143 } 18144 } 18145 } finally { 18146 renderNode.end(canvas); 18147 setDisplayListProperties(renderNode); 18148 } 18149 } else { 18150 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 18151 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18152 } 18153 return renderNode; 18154 } 18155 18156 private void resetDisplayList() { 18157 mRenderNode.discardDisplayList(); 18158 if (mBackgroundRenderNode != null) { 18159 mBackgroundRenderNode.discardDisplayList(); 18160 } 18161 } 18162 18163 /** 18164 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 18165 * 18166 * @return A non-scaled bitmap representing this view or null if cache is disabled. 18167 * 18168 * @see #getDrawingCache(boolean) 18169 */ 18170 public Bitmap getDrawingCache() { 18171 return getDrawingCache(false); 18172 } 18173 18174 /** 18175 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 18176 * is null when caching is disabled. If caching is enabled and the cache is not ready, 18177 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 18178 * draw from the cache when the cache is enabled. To benefit from the cache, you must 18179 * request the drawing cache by calling this method and draw it on screen if the 18180 * returned bitmap is not null.</p> 18181 * 18182 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18183 * this method will create a bitmap of the same size as this view. Because this bitmap 18184 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18185 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18186 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18187 * size than the view. This implies that your application must be able to handle this 18188 * size.</p> 18189 * 18190 * @param autoScale Indicates whether the generated bitmap should be scaled based on 18191 * the current density of the screen when the application is in compatibility 18192 * mode. 18193 * 18194 * @return A bitmap representing this view or null if cache is disabled. 18195 * 18196 * @see #setDrawingCacheEnabled(boolean) 18197 * @see #isDrawingCacheEnabled() 18198 * @see #buildDrawingCache(boolean) 18199 * @see #destroyDrawingCache() 18200 */ 18201 public Bitmap getDrawingCache(boolean autoScale) { 18202 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 18203 return null; 18204 } 18205 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 18206 buildDrawingCache(autoScale); 18207 } 18208 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 18209 } 18210 18211 /** 18212 * <p>Frees the resources used by the drawing cache. If you call 18213 * {@link #buildDrawingCache()} manually without calling 18214 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18215 * should cleanup the cache with this method afterwards.</p> 18216 * 18217 * @see #setDrawingCacheEnabled(boolean) 18218 * @see #buildDrawingCache() 18219 * @see #getDrawingCache() 18220 */ 18221 public void destroyDrawingCache() { 18222 if (mDrawingCache != null) { 18223 mDrawingCache.recycle(); 18224 mDrawingCache = null; 18225 } 18226 if (mUnscaledDrawingCache != null) { 18227 mUnscaledDrawingCache.recycle(); 18228 mUnscaledDrawingCache = null; 18229 } 18230 } 18231 18232 /** 18233 * Setting a solid background color for the drawing cache's bitmaps will improve 18234 * performance and memory usage. Note, though that this should only be used if this 18235 * view will always be drawn on top of a solid color. 18236 * 18237 * @param color The background color to use for the drawing cache's bitmap 18238 * 18239 * @see #setDrawingCacheEnabled(boolean) 18240 * @see #buildDrawingCache() 18241 * @see #getDrawingCache() 18242 */ 18243 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 18244 if (color != mDrawingCacheBackgroundColor) { 18245 mDrawingCacheBackgroundColor = color; 18246 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18247 } 18248 } 18249 18250 /** 18251 * @see #setDrawingCacheBackgroundColor(int) 18252 * 18253 * @return The background color to used for the drawing cache's bitmap 18254 */ 18255 @ColorInt 18256 public int getDrawingCacheBackgroundColor() { 18257 return mDrawingCacheBackgroundColor; 18258 } 18259 18260 /** 18261 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 18262 * 18263 * @see #buildDrawingCache(boolean) 18264 */ 18265 public void buildDrawingCache() { 18266 buildDrawingCache(false); 18267 } 18268 18269 /** 18270 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 18271 * 18272 * <p>If you call {@link #buildDrawingCache()} manually without calling 18273 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 18274 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 18275 * 18276 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 18277 * this method will create a bitmap of the same size as this view. Because this bitmap 18278 * will be drawn scaled by the parent ViewGroup, the result on screen might show 18279 * scaling artifacts. To avoid such artifacts, you should call this method by setting 18280 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 18281 * size than the view. This implies that your application must be able to handle this 18282 * size.</p> 18283 * 18284 * <p>You should avoid calling this method when hardware acceleration is enabled. If 18285 * you do not need the drawing cache bitmap, calling this method will increase memory 18286 * usage and cause the view to be rendered in software once, thus negatively impacting 18287 * performance.</p> 18288 * 18289 * @see #getDrawingCache() 18290 * @see #destroyDrawingCache() 18291 */ 18292 public void buildDrawingCache(boolean autoScale) { 18293 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 18294 mDrawingCache == null : mUnscaledDrawingCache == null)) { 18295 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 18296 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 18297 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 18298 } 18299 try { 18300 buildDrawingCacheImpl(autoScale); 18301 } finally { 18302 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 18303 } 18304 } 18305 } 18306 18307 /** 18308 * private, internal implementation of buildDrawingCache, used to enable tracing 18309 */ 18310 private void buildDrawingCacheImpl(boolean autoScale) { 18311 mCachingFailed = false; 18312 18313 int width = mRight - mLeft; 18314 int height = mBottom - mTop; 18315 18316 final AttachInfo attachInfo = mAttachInfo; 18317 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 18318 18319 if (autoScale && scalingRequired) { 18320 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 18321 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 18322 } 18323 18324 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 18325 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 18326 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 18327 18328 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 18329 final long drawingCacheSize = 18330 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 18331 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 18332 if (width > 0 && height > 0) { 18333 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 18334 + " too large to fit into a software layer (or drawing cache), needs " 18335 + projectedBitmapSize + " bytes, only " 18336 + drawingCacheSize + " available"); 18337 } 18338 destroyDrawingCache(); 18339 mCachingFailed = true; 18340 return; 18341 } 18342 18343 boolean clear = true; 18344 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 18345 18346 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 18347 Bitmap.Config quality; 18348 if (!opaque) { 18349 // Never pick ARGB_4444 because it looks awful 18350 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 18351 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 18352 case DRAWING_CACHE_QUALITY_AUTO: 18353 case DRAWING_CACHE_QUALITY_LOW: 18354 case DRAWING_CACHE_QUALITY_HIGH: 18355 default: 18356 quality = Bitmap.Config.ARGB_8888; 18357 break; 18358 } 18359 } else { 18360 // Optimization for translucent windows 18361 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 18362 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 18363 } 18364 18365 // Try to cleanup memory 18366 if (bitmap != null) bitmap.recycle(); 18367 18368 try { 18369 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18370 width, height, quality); 18371 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 18372 if (autoScale) { 18373 mDrawingCache = bitmap; 18374 } else { 18375 mUnscaledDrawingCache = bitmap; 18376 } 18377 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 18378 } catch (OutOfMemoryError e) { 18379 // If there is not enough memory to create the bitmap cache, just 18380 // ignore the issue as bitmap caches are not required to draw the 18381 // view hierarchy 18382 if (autoScale) { 18383 mDrawingCache = null; 18384 } else { 18385 mUnscaledDrawingCache = null; 18386 } 18387 mCachingFailed = true; 18388 return; 18389 } 18390 18391 clear = drawingCacheBackgroundColor != 0; 18392 } 18393 18394 Canvas canvas; 18395 if (attachInfo != null) { 18396 canvas = attachInfo.mCanvas; 18397 if (canvas == null) { 18398 canvas = new Canvas(); 18399 } 18400 canvas.setBitmap(bitmap); 18401 // Temporarily clobber the cached Canvas in case one of our children 18402 // is also using a drawing cache. Without this, the children would 18403 // steal the canvas by attaching their own bitmap to it and bad, bad 18404 // thing would happen (invisible views, corrupted drawings, etc.) 18405 attachInfo.mCanvas = null; 18406 } else { 18407 // This case should hopefully never or seldom happen 18408 canvas = new Canvas(bitmap); 18409 } 18410 18411 if (clear) { 18412 bitmap.eraseColor(drawingCacheBackgroundColor); 18413 } 18414 18415 computeScroll(); 18416 final int restoreCount = canvas.save(); 18417 18418 if (autoScale && scalingRequired) { 18419 final float scale = attachInfo.mApplicationScale; 18420 canvas.scale(scale, scale); 18421 } 18422 18423 canvas.translate(-mScrollX, -mScrollY); 18424 18425 mPrivateFlags |= PFLAG_DRAWN; 18426 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 18427 mLayerType != LAYER_TYPE_NONE) { 18428 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 18429 } 18430 18431 // Fast path for layouts with no backgrounds 18432 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18433 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18434 dispatchDraw(canvas); 18435 drawAutofilledHighlight(canvas); 18436 if (mOverlay != null && !mOverlay.isEmpty()) { 18437 mOverlay.getOverlayView().draw(canvas); 18438 } 18439 } else { 18440 draw(canvas); 18441 } 18442 18443 canvas.restoreToCount(restoreCount); 18444 canvas.setBitmap(null); 18445 18446 if (attachInfo != null) { 18447 // Restore the cached Canvas for our siblings 18448 attachInfo.mCanvas = canvas; 18449 } 18450 } 18451 18452 /** 18453 * Create a snapshot of the view into a bitmap. We should probably make 18454 * some form of this public, but should think about the API. 18455 * 18456 * @hide 18457 */ 18458 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 18459 int width = mRight - mLeft; 18460 int height = mBottom - mTop; 18461 18462 final AttachInfo attachInfo = mAttachInfo; 18463 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 18464 width = (int) ((width * scale) + 0.5f); 18465 height = (int) ((height * scale) + 0.5f); 18466 18467 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 18468 width > 0 ? width : 1, height > 0 ? height : 1, quality); 18469 if (bitmap == null) { 18470 throw new OutOfMemoryError(); 18471 } 18472 18473 Resources resources = getResources(); 18474 if (resources != null) { 18475 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 18476 } 18477 18478 Canvas canvas; 18479 if (attachInfo != null) { 18480 canvas = attachInfo.mCanvas; 18481 if (canvas == null) { 18482 canvas = new Canvas(); 18483 } 18484 canvas.setBitmap(bitmap); 18485 // Temporarily clobber the cached Canvas in case one of our children 18486 // is also using a drawing cache. Without this, the children would 18487 // steal the canvas by attaching their own bitmap to it and bad, bad 18488 // things would happen (invisible views, corrupted drawings, etc.) 18489 attachInfo.mCanvas = null; 18490 } else { 18491 // This case should hopefully never or seldom happen 18492 canvas = new Canvas(bitmap); 18493 } 18494 boolean enabledHwBitmapsInSwMode = canvas.isHwBitmapsInSwModeEnabled(); 18495 canvas.setHwBitmapsInSwModeEnabled(true); 18496 if ((backgroundColor & 0xff000000) != 0) { 18497 bitmap.eraseColor(backgroundColor); 18498 } 18499 18500 computeScroll(); 18501 final int restoreCount = canvas.save(); 18502 canvas.scale(scale, scale); 18503 canvas.translate(-mScrollX, -mScrollY); 18504 18505 // Temporarily remove the dirty mask 18506 int flags = mPrivateFlags; 18507 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 18508 18509 // Fast path for layouts with no backgrounds 18510 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 18511 dispatchDraw(canvas); 18512 drawAutofilledHighlight(canvas); 18513 if (mOverlay != null && !mOverlay.isEmpty()) { 18514 mOverlay.getOverlayView().draw(canvas); 18515 } 18516 } else { 18517 draw(canvas); 18518 } 18519 18520 mPrivateFlags = flags; 18521 18522 canvas.restoreToCount(restoreCount); 18523 canvas.setBitmap(null); 18524 canvas.setHwBitmapsInSwModeEnabled(enabledHwBitmapsInSwMode); 18525 18526 if (attachInfo != null) { 18527 // Restore the cached Canvas for our siblings 18528 attachInfo.mCanvas = canvas; 18529 } 18530 18531 return bitmap; 18532 } 18533 18534 /** 18535 * Indicates whether this View is currently in edit mode. A View is usually 18536 * in edit mode when displayed within a developer tool. For instance, if 18537 * this View is being drawn by a visual user interface builder, this method 18538 * should return true. 18539 * 18540 * Subclasses should check the return value of this method to provide 18541 * different behaviors if their normal behavior might interfere with the 18542 * host environment. For instance: the class spawns a thread in its 18543 * constructor, the drawing code relies on device-specific features, etc. 18544 * 18545 * This method is usually checked in the drawing code of custom widgets. 18546 * 18547 * @return True if this View is in edit mode, false otherwise. 18548 */ 18549 public boolean isInEditMode() { 18550 return false; 18551 } 18552 18553 /** 18554 * If the View draws content inside its padding and enables fading edges, 18555 * it needs to support padding offsets. Padding offsets are added to the 18556 * fading edges to extend the length of the fade so that it covers pixels 18557 * drawn inside the padding. 18558 * 18559 * Subclasses of this class should override this method if they need 18560 * to draw content inside the padding. 18561 * 18562 * @return True if padding offset must be applied, false otherwise. 18563 * 18564 * @see #getLeftPaddingOffset() 18565 * @see #getRightPaddingOffset() 18566 * @see #getTopPaddingOffset() 18567 * @see #getBottomPaddingOffset() 18568 * 18569 * @since CURRENT 18570 */ 18571 protected boolean isPaddingOffsetRequired() { 18572 return false; 18573 } 18574 18575 /** 18576 * Amount by which to extend the left fading region. Called only when 18577 * {@link #isPaddingOffsetRequired()} returns true. 18578 * 18579 * @return The left padding offset in pixels. 18580 * 18581 * @see #isPaddingOffsetRequired() 18582 * 18583 * @since CURRENT 18584 */ 18585 protected int getLeftPaddingOffset() { 18586 return 0; 18587 } 18588 18589 /** 18590 * Amount by which to extend the right fading region. Called only when 18591 * {@link #isPaddingOffsetRequired()} returns true. 18592 * 18593 * @return The right padding offset in pixels. 18594 * 18595 * @see #isPaddingOffsetRequired() 18596 * 18597 * @since CURRENT 18598 */ 18599 protected int getRightPaddingOffset() { 18600 return 0; 18601 } 18602 18603 /** 18604 * Amount by which to extend the top fading region. Called only when 18605 * {@link #isPaddingOffsetRequired()} returns true. 18606 * 18607 * @return The top padding offset in pixels. 18608 * 18609 * @see #isPaddingOffsetRequired() 18610 * 18611 * @since CURRENT 18612 */ 18613 protected int getTopPaddingOffset() { 18614 return 0; 18615 } 18616 18617 /** 18618 * Amount by which to extend the bottom fading region. Called only when 18619 * {@link #isPaddingOffsetRequired()} returns true. 18620 * 18621 * @return The bottom padding offset in pixels. 18622 * 18623 * @see #isPaddingOffsetRequired() 18624 * 18625 * @since CURRENT 18626 */ 18627 protected int getBottomPaddingOffset() { 18628 return 0; 18629 } 18630 18631 /** 18632 * @hide 18633 * @param offsetRequired 18634 */ 18635 protected int getFadeTop(boolean offsetRequired) { 18636 int top = mPaddingTop; 18637 if (offsetRequired) top += getTopPaddingOffset(); 18638 return top; 18639 } 18640 18641 /** 18642 * @hide 18643 * @param offsetRequired 18644 */ 18645 protected int getFadeHeight(boolean offsetRequired) { 18646 int padding = mPaddingTop; 18647 if (offsetRequired) padding += getTopPaddingOffset(); 18648 return mBottom - mTop - mPaddingBottom - padding; 18649 } 18650 18651 /** 18652 * <p>Indicates whether this view is attached to a hardware accelerated 18653 * window or not.</p> 18654 * 18655 * <p>Even if this method returns true, it does not mean that every call 18656 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 18657 * accelerated {@link android.graphics.Canvas}. For instance, if this view 18658 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 18659 * window is hardware accelerated, 18660 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 18661 * return false, and this method will return true.</p> 18662 * 18663 * @return True if the view is attached to a window and the window is 18664 * hardware accelerated; false in any other case. 18665 */ 18666 @ViewDebug.ExportedProperty(category = "drawing") 18667 public boolean isHardwareAccelerated() { 18668 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 18669 } 18670 18671 /** 18672 * Sets a rectangular area on this view to which the view will be clipped 18673 * when it is drawn. Setting the value to null will remove the clip bounds 18674 * and the view will draw normally, using its full bounds. 18675 * 18676 * @param clipBounds The rectangular area, in the local coordinates of 18677 * this view, to which future drawing operations will be clipped. 18678 */ 18679 public void setClipBounds(Rect clipBounds) { 18680 if (clipBounds == mClipBounds 18681 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 18682 return; 18683 } 18684 if (clipBounds != null) { 18685 if (mClipBounds == null) { 18686 mClipBounds = new Rect(clipBounds); 18687 } else { 18688 mClipBounds.set(clipBounds); 18689 } 18690 } else { 18691 mClipBounds = null; 18692 } 18693 mRenderNode.setClipBounds(mClipBounds); 18694 invalidateViewProperty(false, false); 18695 } 18696 18697 /** 18698 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 18699 * 18700 * @return A copy of the current clip bounds if clip bounds are set, 18701 * otherwise null. 18702 */ 18703 public Rect getClipBounds() { 18704 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 18705 } 18706 18707 18708 /** 18709 * Populates an output rectangle with the clip bounds of the view, 18710 * returning {@code true} if successful or {@code false} if the view's 18711 * clip bounds are {@code null}. 18712 * 18713 * @param outRect rectangle in which to place the clip bounds of the view 18714 * @return {@code true} if successful or {@code false} if the view's 18715 * clip bounds are {@code null} 18716 */ 18717 public boolean getClipBounds(Rect outRect) { 18718 if (mClipBounds != null) { 18719 outRect.set(mClipBounds); 18720 return true; 18721 } 18722 return false; 18723 } 18724 18725 /** 18726 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 18727 * case of an active Animation being run on the view. 18728 */ 18729 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 18730 Animation a, boolean scalingRequired) { 18731 Transformation invalidationTransform; 18732 final int flags = parent.mGroupFlags; 18733 final boolean initialized = a.isInitialized(); 18734 if (!initialized) { 18735 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 18736 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 18737 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 18738 onAnimationStart(); 18739 } 18740 18741 final Transformation t = parent.getChildTransformation(); 18742 boolean more = a.getTransformation(drawingTime, t, 1f); 18743 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 18744 if (parent.mInvalidationTransformation == null) { 18745 parent.mInvalidationTransformation = new Transformation(); 18746 } 18747 invalidationTransform = parent.mInvalidationTransformation; 18748 a.getTransformation(drawingTime, invalidationTransform, 1f); 18749 } else { 18750 invalidationTransform = t; 18751 } 18752 18753 if (more) { 18754 if (!a.willChangeBounds()) { 18755 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 18756 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 18757 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 18758 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 18759 // The child need to draw an animation, potentially offscreen, so 18760 // make sure we do not cancel invalidate requests 18761 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18762 parent.invalidate(mLeft, mTop, mRight, mBottom); 18763 } 18764 } else { 18765 if (parent.mInvalidateRegion == null) { 18766 parent.mInvalidateRegion = new RectF(); 18767 } 18768 final RectF region = parent.mInvalidateRegion; 18769 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 18770 invalidationTransform); 18771 18772 // The child need to draw an animation, potentially offscreen, so 18773 // make sure we do not cancel invalidate requests 18774 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 18775 18776 final int left = mLeft + (int) region.left; 18777 final int top = mTop + (int) region.top; 18778 parent.invalidate(left, top, left + (int) (region.width() + .5f), 18779 top + (int) (region.height() + .5f)); 18780 } 18781 } 18782 return more; 18783 } 18784 18785 /** 18786 * This method is called by getDisplayList() when a display list is recorded for a View. 18787 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 18788 */ 18789 void setDisplayListProperties(RenderNode renderNode) { 18790 if (renderNode != null) { 18791 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 18792 renderNode.setClipToBounds(mParent instanceof ViewGroup 18793 && ((ViewGroup) mParent).getClipChildren()); 18794 18795 float alpha = 1; 18796 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 18797 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18798 ViewGroup parentVG = (ViewGroup) mParent; 18799 final Transformation t = parentVG.getChildTransformation(); 18800 if (parentVG.getChildStaticTransformation(this, t)) { 18801 final int transformType = t.getTransformationType(); 18802 if (transformType != Transformation.TYPE_IDENTITY) { 18803 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 18804 alpha = t.getAlpha(); 18805 } 18806 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 18807 renderNode.setStaticMatrix(t.getMatrix()); 18808 } 18809 } 18810 } 18811 } 18812 if (mTransformationInfo != null) { 18813 alpha *= getFinalAlpha(); 18814 if (alpha < 1) { 18815 final int multipliedAlpha = (int) (255 * alpha); 18816 if (onSetAlpha(multipliedAlpha)) { 18817 alpha = 1; 18818 } 18819 } 18820 renderNode.setAlpha(alpha); 18821 } else if (alpha < 1) { 18822 renderNode.setAlpha(alpha); 18823 } 18824 } 18825 } 18826 18827 /** 18828 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 18829 * 18830 * This is where the View specializes rendering behavior based on layer type, 18831 * and hardware acceleration. 18832 */ 18833 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 18834 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 18835 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 18836 * 18837 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 18838 * HW accelerated, it can't handle drawing RenderNodes. 18839 */ 18840 boolean drawingWithRenderNode = mAttachInfo != null 18841 && mAttachInfo.mHardwareAccelerated 18842 && hardwareAcceleratedCanvas; 18843 18844 boolean more = false; 18845 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 18846 final int parentFlags = parent.mGroupFlags; 18847 18848 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 18849 parent.getChildTransformation().clear(); 18850 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18851 } 18852 18853 Transformation transformToApply = null; 18854 boolean concatMatrix = false; 18855 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 18856 final Animation a = getAnimation(); 18857 if (a != null) { 18858 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 18859 concatMatrix = a.willChangeTransformationMatrix(); 18860 if (concatMatrix) { 18861 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18862 } 18863 transformToApply = parent.getChildTransformation(); 18864 } else { 18865 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 18866 // No longer animating: clear out old animation matrix 18867 mRenderNode.setAnimationMatrix(null); 18868 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 18869 } 18870 if (!drawingWithRenderNode 18871 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 18872 final Transformation t = parent.getChildTransformation(); 18873 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 18874 if (hasTransform) { 18875 final int transformType = t.getTransformationType(); 18876 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 18877 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 18878 } 18879 } 18880 } 18881 18882 concatMatrix |= !childHasIdentityMatrix; 18883 18884 // Sets the flag as early as possible to allow draw() implementations 18885 // to call invalidate() successfully when doing animations 18886 mPrivateFlags |= PFLAG_DRAWN; 18887 18888 if (!concatMatrix && 18889 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 18890 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 18891 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 18892 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 18893 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 18894 return more; 18895 } 18896 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 18897 18898 if (hardwareAcceleratedCanvas) { 18899 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 18900 // retain the flag's value temporarily in the mRecreateDisplayList flag 18901 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 18902 mPrivateFlags &= ~PFLAG_INVALIDATED; 18903 } 18904 18905 RenderNode renderNode = null; 18906 Bitmap cache = null; 18907 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 18908 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 18909 if (layerType != LAYER_TYPE_NONE) { 18910 // If not drawing with RenderNode, treat HW layers as SW 18911 layerType = LAYER_TYPE_SOFTWARE; 18912 buildDrawingCache(true); 18913 } 18914 cache = getDrawingCache(true); 18915 } 18916 18917 if (drawingWithRenderNode) { 18918 // Delay getting the display list until animation-driven alpha values are 18919 // set up and possibly passed on to the view 18920 renderNode = updateDisplayListIfDirty(); 18921 if (!renderNode.isValid()) { 18922 // Uncommon, but possible. If a view is removed from the hierarchy during the call 18923 // to getDisplayList(), the display list will be marked invalid and we should not 18924 // try to use it again. 18925 renderNode = null; 18926 drawingWithRenderNode = false; 18927 } 18928 } 18929 18930 int sx = 0; 18931 int sy = 0; 18932 if (!drawingWithRenderNode) { 18933 computeScroll(); 18934 sx = mScrollX; 18935 sy = mScrollY; 18936 } 18937 18938 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 18939 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 18940 18941 int restoreTo = -1; 18942 if (!drawingWithRenderNode || transformToApply != null) { 18943 restoreTo = canvas.save(); 18944 } 18945 if (offsetForScroll) { 18946 canvas.translate(mLeft - sx, mTop - sy); 18947 } else { 18948 if (!drawingWithRenderNode) { 18949 canvas.translate(mLeft, mTop); 18950 } 18951 if (scalingRequired) { 18952 if (drawingWithRenderNode) { 18953 // TODO: Might not need this if we put everything inside the DL 18954 restoreTo = canvas.save(); 18955 } 18956 // mAttachInfo cannot be null, otherwise scalingRequired == false 18957 final float scale = 1.0f / mAttachInfo.mApplicationScale; 18958 canvas.scale(scale, scale); 18959 } 18960 } 18961 18962 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 18963 if (transformToApply != null 18964 || alpha < 1 18965 || !hasIdentityMatrix() 18966 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 18967 if (transformToApply != null || !childHasIdentityMatrix) { 18968 int transX = 0; 18969 int transY = 0; 18970 18971 if (offsetForScroll) { 18972 transX = -sx; 18973 transY = -sy; 18974 } 18975 18976 if (transformToApply != null) { 18977 if (concatMatrix) { 18978 if (drawingWithRenderNode) { 18979 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 18980 } else { 18981 // Undo the scroll translation, apply the transformation matrix, 18982 // then redo the scroll translate to get the correct result. 18983 canvas.translate(-transX, -transY); 18984 canvas.concat(transformToApply.getMatrix()); 18985 canvas.translate(transX, transY); 18986 } 18987 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18988 } 18989 18990 float transformAlpha = transformToApply.getAlpha(); 18991 if (transformAlpha < 1) { 18992 alpha *= transformAlpha; 18993 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 18994 } 18995 } 18996 18997 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 18998 canvas.translate(-transX, -transY); 18999 canvas.concat(getMatrix()); 19000 canvas.translate(transX, transY); 19001 } 19002 } 19003 19004 // Deal with alpha if it is or used to be <1 19005 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 19006 if (alpha < 1) { 19007 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 19008 } else { 19009 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 19010 } 19011 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 19012 if (!drawingWithDrawingCache) { 19013 final int multipliedAlpha = (int) (255 * alpha); 19014 if (!onSetAlpha(multipliedAlpha)) { 19015 if (drawingWithRenderNode) { 19016 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 19017 } else if (layerType == LAYER_TYPE_NONE) { 19018 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 19019 multipliedAlpha); 19020 } 19021 } else { 19022 // Alpha is handled by the child directly, clobber the layer's alpha 19023 mPrivateFlags |= PFLAG_ALPHA_SET; 19024 } 19025 } 19026 } 19027 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 19028 onSetAlpha(255); 19029 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19030 } 19031 19032 if (!drawingWithRenderNode) { 19033 // apply clips directly, since RenderNode won't do it for this draw 19034 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 19035 if (offsetForScroll) { 19036 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 19037 } else { 19038 if (!scalingRequired || cache == null) { 19039 canvas.clipRect(0, 0, getWidth(), getHeight()); 19040 } else { 19041 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 19042 } 19043 } 19044 } 19045 19046 if (mClipBounds != null) { 19047 // clip bounds ignore scroll 19048 canvas.clipRect(mClipBounds); 19049 } 19050 } 19051 19052 if (!drawingWithDrawingCache) { 19053 if (drawingWithRenderNode) { 19054 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19055 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 19056 } else { 19057 // Fast path for layouts with no backgrounds 19058 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 19059 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19060 dispatchDraw(canvas); 19061 } else { 19062 draw(canvas); 19063 } 19064 } 19065 } else if (cache != null) { 19066 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 19067 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 19068 // no layer paint, use temporary paint to draw bitmap 19069 Paint cachePaint = parent.mCachePaint; 19070 if (cachePaint == null) { 19071 cachePaint = new Paint(); 19072 cachePaint.setDither(false); 19073 parent.mCachePaint = cachePaint; 19074 } 19075 cachePaint.setAlpha((int) (alpha * 255)); 19076 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 19077 } else { 19078 // use layer paint to draw the bitmap, merging the two alphas, but also restore 19079 int layerPaintAlpha = mLayerPaint.getAlpha(); 19080 if (alpha < 1) { 19081 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 19082 } 19083 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 19084 if (alpha < 1) { 19085 mLayerPaint.setAlpha(layerPaintAlpha); 19086 } 19087 } 19088 } 19089 19090 if (restoreTo >= 0) { 19091 canvas.restoreToCount(restoreTo); 19092 } 19093 19094 if (a != null && !more) { 19095 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 19096 onSetAlpha(255); 19097 } 19098 parent.finishAnimatingView(this, a); 19099 } 19100 19101 if (more && hardwareAcceleratedCanvas) { 19102 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 19103 // alpha animations should cause the child to recreate its display list 19104 invalidate(true); 19105 } 19106 } 19107 19108 mRecreateDisplayList = false; 19109 19110 return more; 19111 } 19112 19113 static Paint getDebugPaint() { 19114 if (sDebugPaint == null) { 19115 sDebugPaint = new Paint(); 19116 sDebugPaint.setAntiAlias(false); 19117 } 19118 return sDebugPaint; 19119 } 19120 19121 final int dipsToPixels(int dips) { 19122 float scale = getContext().getResources().getDisplayMetrics().density; 19123 return (int) (dips * scale + 0.5f); 19124 } 19125 19126 final private void debugDrawFocus(Canvas canvas) { 19127 if (isFocused()) { 19128 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 19129 final int l = mScrollX; 19130 final int r = l + mRight - mLeft; 19131 final int t = mScrollY; 19132 final int b = t + mBottom - mTop; 19133 19134 final Paint paint = getDebugPaint(); 19135 paint.setColor(DEBUG_CORNERS_COLOR); 19136 19137 // Draw squares in corners. 19138 paint.setStyle(Paint.Style.FILL); 19139 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 19140 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 19141 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 19142 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 19143 19144 // Draw big X across the view. 19145 paint.setStyle(Paint.Style.STROKE); 19146 canvas.drawLine(l, t, r, b, paint); 19147 canvas.drawLine(l, b, r, t, paint); 19148 } 19149 } 19150 19151 /** 19152 * Manually render this view (and all of its children) to the given Canvas. 19153 * The view must have already done a full layout before this function is 19154 * called. When implementing a view, implement 19155 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 19156 * If you do need to override this method, call the superclass version. 19157 * 19158 * @param canvas The Canvas to which the View is rendered. 19159 */ 19160 @CallSuper 19161 public void draw(Canvas canvas) { 19162 final int privateFlags = mPrivateFlags; 19163 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 19164 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 19165 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 19166 19167 /* 19168 * Draw traversal performs several drawing steps which must be executed 19169 * in the appropriate order: 19170 * 19171 * 1. Draw the background 19172 * 2. If necessary, save the canvas' layers to prepare for fading 19173 * 3. Draw view's content 19174 * 4. Draw children 19175 * 5. If necessary, draw the fading edges and restore layers 19176 * 6. Draw decorations (scrollbars for instance) 19177 */ 19178 19179 // Step 1, draw the background, if needed 19180 int saveCount; 19181 19182 if (!dirtyOpaque) { 19183 drawBackground(canvas); 19184 } 19185 19186 // skip step 2 & 5 if possible (common case) 19187 final int viewFlags = mViewFlags; 19188 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 19189 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 19190 if (!verticalEdges && !horizontalEdges) { 19191 // Step 3, draw the content 19192 if (!dirtyOpaque) onDraw(canvas); 19193 19194 // Step 4, draw the children 19195 dispatchDraw(canvas); 19196 19197 drawAutofilledHighlight(canvas); 19198 19199 // Overlay is part of the content and draws beneath Foreground 19200 if (mOverlay != null && !mOverlay.isEmpty()) { 19201 mOverlay.getOverlayView().dispatchDraw(canvas); 19202 } 19203 19204 // Step 6, draw decorations (foreground, scrollbars) 19205 onDrawForeground(canvas); 19206 19207 // Step 7, draw the default focus highlight 19208 drawDefaultFocusHighlight(canvas); 19209 19210 if (debugDraw()) { 19211 debugDrawFocus(canvas); 19212 } 19213 19214 // we're done... 19215 return; 19216 } 19217 19218 /* 19219 * Here we do the full fledged routine... 19220 * (this is an uncommon case where speed matters less, 19221 * this is why we repeat some of the tests that have been 19222 * done above) 19223 */ 19224 19225 boolean drawTop = false; 19226 boolean drawBottom = false; 19227 boolean drawLeft = false; 19228 boolean drawRight = false; 19229 19230 float topFadeStrength = 0.0f; 19231 float bottomFadeStrength = 0.0f; 19232 float leftFadeStrength = 0.0f; 19233 float rightFadeStrength = 0.0f; 19234 19235 // Step 2, save the canvas' layers 19236 int paddingLeft = mPaddingLeft; 19237 19238 final boolean offsetRequired = isPaddingOffsetRequired(); 19239 if (offsetRequired) { 19240 paddingLeft += getLeftPaddingOffset(); 19241 } 19242 19243 int left = mScrollX + paddingLeft; 19244 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 19245 int top = mScrollY + getFadeTop(offsetRequired); 19246 int bottom = top + getFadeHeight(offsetRequired); 19247 19248 if (offsetRequired) { 19249 right += getRightPaddingOffset(); 19250 bottom += getBottomPaddingOffset(); 19251 } 19252 19253 final ScrollabilityCache scrollabilityCache = mScrollCache; 19254 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 19255 int length = (int) fadeHeight; 19256 19257 // clip the fade length if top and bottom fades overlap 19258 // overlapping fades produce odd-looking artifacts 19259 if (verticalEdges && (top + length > bottom - length)) { 19260 length = (bottom - top) / 2; 19261 } 19262 19263 // also clip horizontal fades if necessary 19264 if (horizontalEdges && (left + length > right - length)) { 19265 length = (right - left) / 2; 19266 } 19267 19268 if (verticalEdges) { 19269 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 19270 drawTop = topFadeStrength * fadeHeight > 1.0f; 19271 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 19272 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 19273 } 19274 19275 if (horizontalEdges) { 19276 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 19277 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 19278 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 19279 drawRight = rightFadeStrength * fadeHeight > 1.0f; 19280 } 19281 19282 saveCount = canvas.getSaveCount(); 19283 19284 int solidColor = getSolidColor(); 19285 if (solidColor == 0) { 19286 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 19287 19288 if (drawTop) { 19289 canvas.saveLayer(left, top, right, top + length, null, flags); 19290 } 19291 19292 if (drawBottom) { 19293 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 19294 } 19295 19296 if (drawLeft) { 19297 canvas.saveLayer(left, top, left + length, bottom, null, flags); 19298 } 19299 19300 if (drawRight) { 19301 canvas.saveLayer(right - length, top, right, bottom, null, flags); 19302 } 19303 } else { 19304 scrollabilityCache.setFadeColor(solidColor); 19305 } 19306 19307 // Step 3, draw the content 19308 if (!dirtyOpaque) onDraw(canvas); 19309 19310 // Step 4, draw the children 19311 dispatchDraw(canvas); 19312 19313 // Step 5, draw the fade effect and restore layers 19314 final Paint p = scrollabilityCache.paint; 19315 final Matrix matrix = scrollabilityCache.matrix; 19316 final Shader fade = scrollabilityCache.shader; 19317 19318 if (drawTop) { 19319 matrix.setScale(1, fadeHeight * topFadeStrength); 19320 matrix.postTranslate(left, top); 19321 fade.setLocalMatrix(matrix); 19322 p.setShader(fade); 19323 canvas.drawRect(left, top, right, top + length, p); 19324 } 19325 19326 if (drawBottom) { 19327 matrix.setScale(1, fadeHeight * bottomFadeStrength); 19328 matrix.postRotate(180); 19329 matrix.postTranslate(left, bottom); 19330 fade.setLocalMatrix(matrix); 19331 p.setShader(fade); 19332 canvas.drawRect(left, bottom - length, right, bottom, p); 19333 } 19334 19335 if (drawLeft) { 19336 matrix.setScale(1, fadeHeight * leftFadeStrength); 19337 matrix.postRotate(-90); 19338 matrix.postTranslate(left, top); 19339 fade.setLocalMatrix(matrix); 19340 p.setShader(fade); 19341 canvas.drawRect(left, top, left + length, bottom, p); 19342 } 19343 19344 if (drawRight) { 19345 matrix.setScale(1, fadeHeight * rightFadeStrength); 19346 matrix.postRotate(90); 19347 matrix.postTranslate(right, top); 19348 fade.setLocalMatrix(matrix); 19349 p.setShader(fade); 19350 canvas.drawRect(right - length, top, right, bottom, p); 19351 } 19352 19353 canvas.restoreToCount(saveCount); 19354 19355 drawAutofilledHighlight(canvas); 19356 19357 // Overlay is part of the content and draws beneath Foreground 19358 if (mOverlay != null && !mOverlay.isEmpty()) { 19359 mOverlay.getOverlayView().dispatchDraw(canvas); 19360 } 19361 19362 // Step 6, draw decorations (foreground, scrollbars) 19363 onDrawForeground(canvas); 19364 19365 if (debugDraw()) { 19366 debugDrawFocus(canvas); 19367 } 19368 } 19369 19370 /** 19371 * Draws the background onto the specified canvas. 19372 * 19373 * @param canvas Canvas on which to draw the background 19374 */ 19375 private void drawBackground(Canvas canvas) { 19376 final Drawable background = mBackground; 19377 if (background == null) { 19378 return; 19379 } 19380 19381 setBackgroundBounds(); 19382 19383 // Attempt to use a display list if requested. 19384 if (canvas.isHardwareAccelerated() && mAttachInfo != null 19385 && mAttachInfo.mThreadedRenderer != null) { 19386 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 19387 19388 final RenderNode renderNode = mBackgroundRenderNode; 19389 if (renderNode != null && renderNode.isValid()) { 19390 setBackgroundRenderNodeProperties(renderNode); 19391 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 19392 return; 19393 } 19394 } 19395 19396 final int scrollX = mScrollX; 19397 final int scrollY = mScrollY; 19398 if ((scrollX | scrollY) == 0) { 19399 background.draw(canvas); 19400 } else { 19401 canvas.translate(scrollX, scrollY); 19402 background.draw(canvas); 19403 canvas.translate(-scrollX, -scrollY); 19404 } 19405 } 19406 19407 /** 19408 * Sets the correct background bounds and rebuilds the outline, if needed. 19409 * <p/> 19410 * This is called by LayoutLib. 19411 */ 19412 void setBackgroundBounds() { 19413 if (mBackgroundSizeChanged && mBackground != null) { 19414 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 19415 mBackgroundSizeChanged = false; 19416 rebuildOutline(); 19417 } 19418 } 19419 19420 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 19421 renderNode.setTranslationX(mScrollX); 19422 renderNode.setTranslationY(mScrollY); 19423 } 19424 19425 /** 19426 * Creates a new display list or updates the existing display list for the 19427 * specified Drawable. 19428 * 19429 * @param drawable Drawable for which to create a display list 19430 * @param renderNode Existing RenderNode, or {@code null} 19431 * @return A valid display list for the specified drawable 19432 */ 19433 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 19434 if (renderNode == null) { 19435 renderNode = RenderNode.create(drawable.getClass().getName(), this); 19436 } 19437 19438 final Rect bounds = drawable.getBounds(); 19439 final int width = bounds.width(); 19440 final int height = bounds.height(); 19441 final DisplayListCanvas canvas = renderNode.start(width, height); 19442 19443 // Reverse left/top translation done by drawable canvas, which will 19444 // instead be applied by rendernode's LTRB bounds below. This way, the 19445 // drawable's bounds match with its rendernode bounds and its content 19446 // will lie within those bounds in the rendernode tree. 19447 canvas.translate(-bounds.left, -bounds.top); 19448 19449 try { 19450 drawable.draw(canvas); 19451 } finally { 19452 renderNode.end(canvas); 19453 } 19454 19455 // Set up drawable properties that are view-independent. 19456 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 19457 renderNode.setProjectBackwards(drawable.isProjected()); 19458 renderNode.setProjectionReceiver(true); 19459 renderNode.setClipToBounds(false); 19460 return renderNode; 19461 } 19462 19463 /** 19464 * Returns the overlay for this view, creating it if it does not yet exist. 19465 * Adding drawables to the overlay will cause them to be displayed whenever 19466 * the view itself is redrawn. Objects in the overlay should be actively 19467 * managed: remove them when they should not be displayed anymore. The 19468 * overlay will always have the same size as its host view. 19469 * 19470 * <p>Note: Overlays do not currently work correctly with {@link 19471 * SurfaceView} or {@link TextureView}; contents in overlays for these 19472 * types of views may not display correctly.</p> 19473 * 19474 * @return The ViewOverlay object for this view. 19475 * @see ViewOverlay 19476 */ 19477 public ViewOverlay getOverlay() { 19478 if (mOverlay == null) { 19479 mOverlay = new ViewOverlay(mContext, this); 19480 } 19481 return mOverlay; 19482 } 19483 19484 /** 19485 * Override this if your view is known to always be drawn on top of a solid color background, 19486 * and needs to draw fading edges. Returning a non-zero color enables the view system to 19487 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 19488 * should be set to 0xFF. 19489 * 19490 * @see #setVerticalFadingEdgeEnabled(boolean) 19491 * @see #setHorizontalFadingEdgeEnabled(boolean) 19492 * 19493 * @return The known solid color background for this view, or 0 if the color may vary 19494 */ 19495 @ViewDebug.ExportedProperty(category = "drawing") 19496 @ColorInt 19497 public int getSolidColor() { 19498 return 0; 19499 } 19500 19501 /** 19502 * Build a human readable string representation of the specified view flags. 19503 * 19504 * @param flags the view flags to convert to a string 19505 * @return a String representing the supplied flags 19506 */ 19507 private static String printFlags(int flags) { 19508 String output = ""; 19509 int numFlags = 0; 19510 if ((flags & FOCUSABLE) == FOCUSABLE) { 19511 output += "TAKES_FOCUS"; 19512 numFlags++; 19513 } 19514 19515 switch (flags & VISIBILITY_MASK) { 19516 case INVISIBLE: 19517 if (numFlags > 0) { 19518 output += " "; 19519 } 19520 output += "INVISIBLE"; 19521 // USELESS HERE numFlags++; 19522 break; 19523 case GONE: 19524 if (numFlags > 0) { 19525 output += " "; 19526 } 19527 output += "GONE"; 19528 // USELESS HERE numFlags++; 19529 break; 19530 default: 19531 break; 19532 } 19533 return output; 19534 } 19535 19536 /** 19537 * Build a human readable string representation of the specified private 19538 * view flags. 19539 * 19540 * @param privateFlags the private view flags to convert to a string 19541 * @return a String representing the supplied flags 19542 */ 19543 private static String printPrivateFlags(int privateFlags) { 19544 String output = ""; 19545 int numFlags = 0; 19546 19547 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 19548 output += "WANTS_FOCUS"; 19549 numFlags++; 19550 } 19551 19552 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 19553 if (numFlags > 0) { 19554 output += " "; 19555 } 19556 output += "FOCUSED"; 19557 numFlags++; 19558 } 19559 19560 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 19561 if (numFlags > 0) { 19562 output += " "; 19563 } 19564 output += "SELECTED"; 19565 numFlags++; 19566 } 19567 19568 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 19569 if (numFlags > 0) { 19570 output += " "; 19571 } 19572 output += "IS_ROOT_NAMESPACE"; 19573 numFlags++; 19574 } 19575 19576 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 19577 if (numFlags > 0) { 19578 output += " "; 19579 } 19580 output += "HAS_BOUNDS"; 19581 numFlags++; 19582 } 19583 19584 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 19585 if (numFlags > 0) { 19586 output += " "; 19587 } 19588 output += "DRAWN"; 19589 // USELESS HERE numFlags++; 19590 } 19591 return output; 19592 } 19593 19594 /** 19595 * <p>Indicates whether or not this view's layout will be requested during 19596 * the next hierarchy layout pass.</p> 19597 * 19598 * @return true if the layout will be forced during next layout pass 19599 */ 19600 public boolean isLayoutRequested() { 19601 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 19602 } 19603 19604 /** 19605 * Return true if o is a ViewGroup that is laying out using optical bounds. 19606 * @hide 19607 */ 19608 public static boolean isLayoutModeOptical(Object o) { 19609 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 19610 } 19611 19612 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 19613 Insets parentInsets = mParent instanceof View ? 19614 ((View) mParent).getOpticalInsets() : Insets.NONE; 19615 Insets childInsets = getOpticalInsets(); 19616 return setFrame( 19617 left + parentInsets.left - childInsets.left, 19618 top + parentInsets.top - childInsets.top, 19619 right + parentInsets.left + childInsets.right, 19620 bottom + parentInsets.top + childInsets.bottom); 19621 } 19622 19623 /** 19624 * Assign a size and position to a view and all of its 19625 * descendants 19626 * 19627 * <p>This is the second phase of the layout mechanism. 19628 * (The first is measuring). In this phase, each parent calls 19629 * layout on all of its children to position them. 19630 * This is typically done using the child measurements 19631 * that were stored in the measure pass().</p> 19632 * 19633 * <p>Derived classes should not override this method. 19634 * Derived classes with children should override 19635 * onLayout. In that method, they should 19636 * call layout on each of their children.</p> 19637 * 19638 * @param l Left position, relative to parent 19639 * @param t Top position, relative to parent 19640 * @param r Right position, relative to parent 19641 * @param b Bottom position, relative to parent 19642 */ 19643 @SuppressWarnings({"unchecked"}) 19644 public void layout(int l, int t, int r, int b) { 19645 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 19646 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 19647 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19648 } 19649 19650 int oldL = mLeft; 19651 int oldT = mTop; 19652 int oldB = mBottom; 19653 int oldR = mRight; 19654 19655 boolean changed = isLayoutModeOptical(mParent) ? 19656 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 19657 19658 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 19659 onLayout(changed, l, t, r, b); 19660 19661 if (shouldDrawRoundScrollbar()) { 19662 if(mRoundScrollbarRenderer == null) { 19663 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 19664 } 19665 } else { 19666 mRoundScrollbarRenderer = null; 19667 } 19668 19669 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 19670 19671 ListenerInfo li = mListenerInfo; 19672 if (li != null && li.mOnLayoutChangeListeners != null) { 19673 ArrayList<OnLayoutChangeListener> listenersCopy = 19674 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 19675 int numListeners = listenersCopy.size(); 19676 for (int i = 0; i < numListeners; ++i) { 19677 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 19678 } 19679 } 19680 } 19681 19682 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 19683 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 19684 19685 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 19686 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 19687 notifyEnterOrExitForAutoFillIfNeeded(true); 19688 } 19689 } 19690 19691 /** 19692 * Called from layout when this view should 19693 * assign a size and position to each of its children. 19694 * 19695 * Derived classes with children should override 19696 * this method and call layout on each of 19697 * their children. 19698 * @param changed This is a new size or position for this view 19699 * @param left Left position, relative to parent 19700 * @param top Top position, relative to parent 19701 * @param right Right position, relative to parent 19702 * @param bottom Bottom position, relative to parent 19703 */ 19704 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 19705 } 19706 19707 /** 19708 * Assign a size and position to this view. 19709 * 19710 * This is called from layout. 19711 * 19712 * @param left Left position, relative to parent 19713 * @param top Top position, relative to parent 19714 * @param right Right position, relative to parent 19715 * @param bottom Bottom position, relative to parent 19716 * @return true if the new size and position are different than the 19717 * previous ones 19718 * {@hide} 19719 */ 19720 protected boolean setFrame(int left, int top, int right, int bottom) { 19721 boolean changed = false; 19722 19723 if (DBG) { 19724 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 19725 + right + "," + bottom + ")"); 19726 } 19727 19728 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 19729 changed = true; 19730 19731 // Remember our drawn bit 19732 int drawn = mPrivateFlags & PFLAG_DRAWN; 19733 19734 int oldWidth = mRight - mLeft; 19735 int oldHeight = mBottom - mTop; 19736 int newWidth = right - left; 19737 int newHeight = bottom - top; 19738 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 19739 19740 // Invalidate our old position 19741 invalidate(sizeChanged); 19742 19743 mLeft = left; 19744 mTop = top; 19745 mRight = right; 19746 mBottom = bottom; 19747 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 19748 19749 mPrivateFlags |= PFLAG_HAS_BOUNDS; 19750 19751 19752 if (sizeChanged) { 19753 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 19754 } 19755 19756 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 19757 // If we are visible, force the DRAWN bit to on so that 19758 // this invalidate will go through (at least to our parent). 19759 // This is because someone may have invalidated this view 19760 // before this call to setFrame came in, thereby clearing 19761 // the DRAWN bit. 19762 mPrivateFlags |= PFLAG_DRAWN; 19763 invalidate(sizeChanged); 19764 // parent display list may need to be recreated based on a change in the bounds 19765 // of any child 19766 invalidateParentCaches(); 19767 } 19768 19769 // Reset drawn bit to original value (invalidate turns it off) 19770 mPrivateFlags |= drawn; 19771 19772 mBackgroundSizeChanged = true; 19773 mDefaultFocusHighlightSizeChanged = true; 19774 if (mForegroundInfo != null) { 19775 mForegroundInfo.mBoundsChanged = true; 19776 } 19777 19778 notifySubtreeAccessibilityStateChangedIfNeeded(); 19779 } 19780 return changed; 19781 } 19782 19783 /** 19784 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 19785 * @hide 19786 */ 19787 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 19788 setFrame(left, top, right, bottom); 19789 } 19790 19791 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 19792 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 19793 if (mOverlay != null) { 19794 mOverlay.getOverlayView().setRight(newWidth); 19795 mOverlay.getOverlayView().setBottom(newHeight); 19796 } 19797 rebuildOutline(); 19798 } 19799 19800 /** 19801 * Finalize inflating a view from XML. This is called as the last phase 19802 * of inflation, after all child views have been added. 19803 * 19804 * <p>Even if the subclass overrides onFinishInflate, they should always be 19805 * sure to call the super method, so that we get called. 19806 */ 19807 @CallSuper 19808 protected void onFinishInflate() { 19809 } 19810 19811 /** 19812 * Returns the resources associated with this view. 19813 * 19814 * @return Resources object. 19815 */ 19816 public Resources getResources() { 19817 return mResources; 19818 } 19819 19820 /** 19821 * Invalidates the specified Drawable. 19822 * 19823 * @param drawable the drawable to invalidate 19824 */ 19825 @Override 19826 public void invalidateDrawable(@NonNull Drawable drawable) { 19827 if (verifyDrawable(drawable)) { 19828 final Rect dirty = drawable.getDirtyBounds(); 19829 final int scrollX = mScrollX; 19830 final int scrollY = mScrollY; 19831 19832 invalidate(dirty.left + scrollX, dirty.top + scrollY, 19833 dirty.right + scrollX, dirty.bottom + scrollY); 19834 rebuildOutline(); 19835 } 19836 } 19837 19838 /** 19839 * Schedules an action on a drawable to occur at a specified time. 19840 * 19841 * @param who the recipient of the action 19842 * @param what the action to run on the drawable 19843 * @param when the time at which the action must occur. Uses the 19844 * {@link SystemClock#uptimeMillis} timebase. 19845 */ 19846 @Override 19847 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 19848 if (verifyDrawable(who) && what != null) { 19849 final long delay = when - SystemClock.uptimeMillis(); 19850 if (mAttachInfo != null) { 19851 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 19852 Choreographer.CALLBACK_ANIMATION, what, who, 19853 Choreographer.subtractFrameDelay(delay)); 19854 } else { 19855 // Postpone the runnable until we know 19856 // on which thread it needs to run. 19857 getRunQueue().postDelayed(what, delay); 19858 } 19859 } 19860 } 19861 19862 /** 19863 * Cancels a scheduled action on a drawable. 19864 * 19865 * @param who the recipient of the action 19866 * @param what the action to cancel 19867 */ 19868 @Override 19869 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 19870 if (verifyDrawable(who) && what != null) { 19871 if (mAttachInfo != null) { 19872 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19873 Choreographer.CALLBACK_ANIMATION, what, who); 19874 } 19875 getRunQueue().removeCallbacks(what); 19876 } 19877 } 19878 19879 /** 19880 * Unschedule any events associated with the given Drawable. This can be 19881 * used when selecting a new Drawable into a view, so that the previous 19882 * one is completely unscheduled. 19883 * 19884 * @param who The Drawable to unschedule. 19885 * 19886 * @see #drawableStateChanged 19887 */ 19888 public void unscheduleDrawable(Drawable who) { 19889 if (mAttachInfo != null && who != null) { 19890 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 19891 Choreographer.CALLBACK_ANIMATION, null, who); 19892 } 19893 } 19894 19895 /** 19896 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 19897 * that the View directionality can and will be resolved before its Drawables. 19898 * 19899 * Will call {@link View#onResolveDrawables} when resolution is done. 19900 * 19901 * @hide 19902 */ 19903 protected void resolveDrawables() { 19904 // Drawables resolution may need to happen before resolving the layout direction (which is 19905 // done only during the measure() call). 19906 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 19907 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 19908 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 19909 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 19910 // direction to be resolved as its resolved value will be the same as its raw value. 19911 if (!isLayoutDirectionResolved() && 19912 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 19913 return; 19914 } 19915 19916 final int layoutDirection = isLayoutDirectionResolved() ? 19917 getLayoutDirection() : getRawLayoutDirection(); 19918 19919 if (mBackground != null) { 19920 mBackground.setLayoutDirection(layoutDirection); 19921 } 19922 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 19923 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 19924 } 19925 if (mDefaultFocusHighlight != null) { 19926 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 19927 } 19928 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 19929 onResolveDrawables(layoutDirection); 19930 } 19931 19932 boolean areDrawablesResolved() { 19933 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 19934 } 19935 19936 /** 19937 * Called when layout direction has been resolved. 19938 * 19939 * The default implementation does nothing. 19940 * 19941 * @param layoutDirection The resolved layout direction. 19942 * 19943 * @see #LAYOUT_DIRECTION_LTR 19944 * @see #LAYOUT_DIRECTION_RTL 19945 * 19946 * @hide 19947 */ 19948 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 19949 } 19950 19951 /** 19952 * @hide 19953 */ 19954 protected void resetResolvedDrawables() { 19955 resetResolvedDrawablesInternal(); 19956 } 19957 19958 void resetResolvedDrawablesInternal() { 19959 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 19960 } 19961 19962 /** 19963 * If your view subclass is displaying its own Drawable objects, it should 19964 * override this function and return true for any Drawable it is 19965 * displaying. This allows animations for those drawables to be 19966 * scheduled. 19967 * 19968 * <p>Be sure to call through to the super class when overriding this 19969 * function. 19970 * 19971 * @param who The Drawable to verify. Return true if it is one you are 19972 * displaying, else return the result of calling through to the 19973 * super class. 19974 * 19975 * @return boolean If true than the Drawable is being displayed in the 19976 * view; else false and it is not allowed to animate. 19977 * 19978 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 19979 * @see #drawableStateChanged() 19980 */ 19981 @CallSuper 19982 protected boolean verifyDrawable(@NonNull Drawable who) { 19983 // Avoid verifying the scroll bar drawable so that we don't end up in 19984 // an invalidation loop. This effectively prevents the scroll bar 19985 // drawable from triggering invalidations and scheduling runnables. 19986 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 19987 || (mDefaultFocusHighlight == who); 19988 } 19989 19990 /** 19991 * This function is called whenever the state of the view changes in such 19992 * a way that it impacts the state of drawables being shown. 19993 * <p> 19994 * If the View has a StateListAnimator, it will also be called to run necessary state 19995 * change animations. 19996 * <p> 19997 * Be sure to call through to the superclass when overriding this function. 19998 * 19999 * @see Drawable#setState(int[]) 20000 */ 20001 @CallSuper 20002 protected void drawableStateChanged() { 20003 final int[] state = getDrawableState(); 20004 boolean changed = false; 20005 20006 final Drawable bg = mBackground; 20007 if (bg != null && bg.isStateful()) { 20008 changed |= bg.setState(state); 20009 } 20010 20011 final Drawable hl = mDefaultFocusHighlight; 20012 if (hl != null && hl.isStateful()) { 20013 changed |= hl.setState(state); 20014 } 20015 20016 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20017 if (fg != null && fg.isStateful()) { 20018 changed |= fg.setState(state); 20019 } 20020 20021 if (mScrollCache != null) { 20022 final Drawable scrollBar = mScrollCache.scrollBar; 20023 if (scrollBar != null && scrollBar.isStateful()) { 20024 changed |= scrollBar.setState(state) 20025 && mScrollCache.state != ScrollabilityCache.OFF; 20026 } 20027 } 20028 20029 if (mStateListAnimator != null) { 20030 mStateListAnimator.setState(state); 20031 } 20032 20033 if (changed) { 20034 invalidate(); 20035 } 20036 } 20037 20038 /** 20039 * This function is called whenever the view hotspot changes and needs to 20040 * be propagated to drawables or child views managed by the view. 20041 * <p> 20042 * Dispatching to child views is handled by 20043 * {@link #dispatchDrawableHotspotChanged(float, float)}. 20044 * <p> 20045 * Be sure to call through to the superclass when overriding this function. 20046 * 20047 * @param x hotspot x coordinate 20048 * @param y hotspot y coordinate 20049 */ 20050 @CallSuper 20051 public void drawableHotspotChanged(float x, float y) { 20052 if (mBackground != null) { 20053 mBackground.setHotspot(x, y); 20054 } 20055 if (mDefaultFocusHighlight != null) { 20056 mDefaultFocusHighlight.setHotspot(x, y); 20057 } 20058 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20059 mForegroundInfo.mDrawable.setHotspot(x, y); 20060 } 20061 20062 dispatchDrawableHotspotChanged(x, y); 20063 } 20064 20065 /** 20066 * Dispatches drawableHotspotChanged to all of this View's children. 20067 * 20068 * @param x hotspot x coordinate 20069 * @param y hotspot y coordinate 20070 * @see #drawableHotspotChanged(float, float) 20071 */ 20072 public void dispatchDrawableHotspotChanged(float x, float y) { 20073 } 20074 20075 /** 20076 * Call this to force a view to update its drawable state. This will cause 20077 * drawableStateChanged to be called on this view. Views that are interested 20078 * in the new state should call getDrawableState. 20079 * 20080 * @see #drawableStateChanged 20081 * @see #getDrawableState 20082 */ 20083 public void refreshDrawableState() { 20084 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20085 drawableStateChanged(); 20086 20087 ViewParent parent = mParent; 20088 if (parent != null) { 20089 parent.childDrawableStateChanged(this); 20090 } 20091 } 20092 20093 /** 20094 * Create a default focus highlight if it doesn't exist. 20095 * @return a default focus highlight. 20096 */ 20097 private Drawable getDefaultFocusHighlightDrawable() { 20098 if (mDefaultFocusHighlightCache == null) { 20099 if (mContext != null) { 20100 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 20101 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 20102 mDefaultFocusHighlightCache = ta.getDrawable(0); 20103 ta.recycle(); 20104 } 20105 } 20106 return mDefaultFocusHighlightCache; 20107 } 20108 20109 /** 20110 * Set the current default focus highlight. 20111 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 20112 */ 20113 private void setDefaultFocusHighlight(Drawable highlight) { 20114 mDefaultFocusHighlight = highlight; 20115 mDefaultFocusHighlightSizeChanged = true; 20116 if (highlight != null) { 20117 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20118 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20119 } 20120 highlight.setLayoutDirection(getLayoutDirection()); 20121 if (highlight.isStateful()) { 20122 highlight.setState(getDrawableState()); 20123 } 20124 if (isAttachedToWindow()) { 20125 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20126 } 20127 // Set callback last, since the view may still be initializing. 20128 highlight.setCallback(this); 20129 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20130 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20131 mPrivateFlags |= PFLAG_SKIP_DRAW; 20132 } 20133 invalidate(); 20134 } 20135 20136 /** 20137 * Check whether we need to draw a default focus highlight when this view gets focused, 20138 * which requires: 20139 * <ul> 20140 * <li>In both background and foreground, {@link android.R.attr#state_focused} 20141 * is not defined.</li> 20142 * <li>This view is not in touch mode.</li> 20143 * <li>This view doesn't opt out for a default focus highlight, via 20144 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 20145 * <li>This view is attached to window.</li> 20146 * </ul> 20147 * @return {@code true} if a default focus highlight is needed. 20148 * @hide 20149 */ 20150 @TestApi 20151 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 20152 final boolean lackFocusState = (background == null || !background.isStateful() 20153 || !background.hasFocusStateSpecified()) 20154 && (foreground == null || !foreground.isStateful() 20155 || !foreground.hasFocusStateSpecified()); 20156 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 20157 && isAttachedToWindow() && sUseDefaultFocusHighlight; 20158 } 20159 20160 /** 20161 * When this view is focused, switches on/off the default focused highlight. 20162 * <p> 20163 * This always happens when this view is focused, and only at this moment the default focus 20164 * highlight can be visible. 20165 */ 20166 private void switchDefaultFocusHighlight() { 20167 if (isFocused()) { 20168 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 20169 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 20170 final boolean active = mDefaultFocusHighlight != null; 20171 if (needed && !active) { 20172 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 20173 } else if (!needed && active) { 20174 // The highlight is no longer needed, so tear it down. 20175 setDefaultFocusHighlight(null); 20176 } 20177 } 20178 } 20179 20180 /** 20181 * Draw the default focus highlight onto the canvas. 20182 * @param canvas the canvas where we're drawing the highlight. 20183 */ 20184 private void drawDefaultFocusHighlight(Canvas canvas) { 20185 if (mDefaultFocusHighlight != null) { 20186 if (mDefaultFocusHighlightSizeChanged) { 20187 mDefaultFocusHighlightSizeChanged = false; 20188 final int l = mScrollX; 20189 final int r = l + mRight - mLeft; 20190 final int t = mScrollY; 20191 final int b = t + mBottom - mTop; 20192 mDefaultFocusHighlight.setBounds(l, t, r, b); 20193 } 20194 mDefaultFocusHighlight.draw(canvas); 20195 } 20196 } 20197 20198 /** 20199 * Return an array of resource IDs of the drawable states representing the 20200 * current state of the view. 20201 * 20202 * @return The current drawable state 20203 * 20204 * @see Drawable#setState(int[]) 20205 * @see #drawableStateChanged() 20206 * @see #onCreateDrawableState(int) 20207 */ 20208 public final int[] getDrawableState() { 20209 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 20210 return mDrawableState; 20211 } else { 20212 mDrawableState = onCreateDrawableState(0); 20213 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 20214 return mDrawableState; 20215 } 20216 } 20217 20218 /** 20219 * Generate the new {@link android.graphics.drawable.Drawable} state for 20220 * this view. This is called by the view 20221 * system when the cached Drawable state is determined to be invalid. To 20222 * retrieve the current state, you should use {@link #getDrawableState}. 20223 * 20224 * @param extraSpace if non-zero, this is the number of extra entries you 20225 * would like in the returned array in which you can place your own 20226 * states. 20227 * 20228 * @return Returns an array holding the current {@link Drawable} state of 20229 * the view. 20230 * 20231 * @see #mergeDrawableStates(int[], int[]) 20232 */ 20233 protected int[] onCreateDrawableState(int extraSpace) { 20234 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 20235 mParent instanceof View) { 20236 return ((View) mParent).onCreateDrawableState(extraSpace); 20237 } 20238 20239 int[] drawableState; 20240 20241 int privateFlags = mPrivateFlags; 20242 20243 int viewStateIndex = 0; 20244 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 20245 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 20246 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 20247 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 20248 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 20249 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 20250 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 20251 ThreadedRenderer.isAvailable()) { 20252 // This is set if HW acceleration is requested, even if the current 20253 // process doesn't allow it. This is just to allow app preview 20254 // windows to better match their app. 20255 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 20256 } 20257 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 20258 20259 final int privateFlags2 = mPrivateFlags2; 20260 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 20261 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 20262 } 20263 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 20264 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 20265 } 20266 20267 drawableState = StateSet.get(viewStateIndex); 20268 20269 //noinspection ConstantIfStatement 20270 if (false) { 20271 Log.i("View", "drawableStateIndex=" + viewStateIndex); 20272 Log.i("View", toString() 20273 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 20274 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 20275 + " fo=" + hasFocus() 20276 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 20277 + " wf=" + hasWindowFocus() 20278 + ": " + Arrays.toString(drawableState)); 20279 } 20280 20281 if (extraSpace == 0) { 20282 return drawableState; 20283 } 20284 20285 final int[] fullState; 20286 if (drawableState != null) { 20287 fullState = new int[drawableState.length + extraSpace]; 20288 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 20289 } else { 20290 fullState = new int[extraSpace]; 20291 } 20292 20293 return fullState; 20294 } 20295 20296 /** 20297 * Merge your own state values in <var>additionalState</var> into the base 20298 * state values <var>baseState</var> that were returned by 20299 * {@link #onCreateDrawableState(int)}. 20300 * 20301 * @param baseState The base state values returned by 20302 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 20303 * own additional state values. 20304 * 20305 * @param additionalState The additional state values you would like 20306 * added to <var>baseState</var>; this array is not modified. 20307 * 20308 * @return As a convenience, the <var>baseState</var> array you originally 20309 * passed into the function is returned. 20310 * 20311 * @see #onCreateDrawableState(int) 20312 */ 20313 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 20314 final int N = baseState.length; 20315 int i = N - 1; 20316 while (i >= 0 && baseState[i] == 0) { 20317 i--; 20318 } 20319 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 20320 return baseState; 20321 } 20322 20323 /** 20324 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 20325 * on all Drawable objects associated with this view. 20326 * <p> 20327 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 20328 * attached to this view. 20329 */ 20330 @CallSuper 20331 public void jumpDrawablesToCurrentState() { 20332 if (mBackground != null) { 20333 mBackground.jumpToCurrentState(); 20334 } 20335 if (mStateListAnimator != null) { 20336 mStateListAnimator.jumpToCurrentState(); 20337 } 20338 if (mDefaultFocusHighlight != null) { 20339 mDefaultFocusHighlight.jumpToCurrentState(); 20340 } 20341 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 20342 mForegroundInfo.mDrawable.jumpToCurrentState(); 20343 } 20344 } 20345 20346 /** 20347 * Sets the background color for this view. 20348 * @param color the color of the background 20349 */ 20350 @RemotableViewMethod 20351 public void setBackgroundColor(@ColorInt int color) { 20352 if (mBackground instanceof ColorDrawable) { 20353 ((ColorDrawable) mBackground.mutate()).setColor(color); 20354 computeOpaqueFlags(); 20355 mBackgroundResource = 0; 20356 } else { 20357 setBackground(new ColorDrawable(color)); 20358 } 20359 } 20360 20361 /** 20362 * Set the background to a given resource. The resource should refer to 20363 * a Drawable object or 0 to remove the background. 20364 * @param resid The identifier of the resource. 20365 * 20366 * @attr ref android.R.styleable#View_background 20367 */ 20368 @RemotableViewMethod 20369 public void setBackgroundResource(@DrawableRes int resid) { 20370 if (resid != 0 && resid == mBackgroundResource) { 20371 return; 20372 } 20373 20374 Drawable d = null; 20375 if (resid != 0) { 20376 d = mContext.getDrawable(resid); 20377 } 20378 setBackground(d); 20379 20380 mBackgroundResource = resid; 20381 } 20382 20383 /** 20384 * Set the background to a given Drawable, or remove the background. If the 20385 * background has padding, this View's padding is set to the background's 20386 * padding. However, when a background is removed, this View's padding isn't 20387 * touched. If setting the padding is desired, please use 20388 * {@link #setPadding(int, int, int, int)}. 20389 * 20390 * @param background The Drawable to use as the background, or null to remove the 20391 * background 20392 */ 20393 public void setBackground(Drawable background) { 20394 //noinspection deprecation 20395 setBackgroundDrawable(background); 20396 } 20397 20398 /** 20399 * @deprecated use {@link #setBackground(Drawable)} instead 20400 */ 20401 @Deprecated 20402 public void setBackgroundDrawable(Drawable background) { 20403 computeOpaqueFlags(); 20404 20405 if (background == mBackground) { 20406 return; 20407 } 20408 20409 boolean requestLayout = false; 20410 20411 mBackgroundResource = 0; 20412 20413 /* 20414 * Regardless of whether we're setting a new background or not, we want 20415 * to clear the previous drawable. setVisible first while we still have the callback set. 20416 */ 20417 if (mBackground != null) { 20418 if (isAttachedToWindow()) { 20419 mBackground.setVisible(false, false); 20420 } 20421 mBackground.setCallback(null); 20422 unscheduleDrawable(mBackground); 20423 } 20424 20425 if (background != null) { 20426 Rect padding = sThreadLocal.get(); 20427 if (padding == null) { 20428 padding = new Rect(); 20429 sThreadLocal.set(padding); 20430 } 20431 resetResolvedDrawablesInternal(); 20432 background.setLayoutDirection(getLayoutDirection()); 20433 if (background.getPadding(padding)) { 20434 resetResolvedPaddingInternal(); 20435 switch (background.getLayoutDirection()) { 20436 case LAYOUT_DIRECTION_RTL: 20437 mUserPaddingLeftInitial = padding.right; 20438 mUserPaddingRightInitial = padding.left; 20439 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 20440 break; 20441 case LAYOUT_DIRECTION_LTR: 20442 default: 20443 mUserPaddingLeftInitial = padding.left; 20444 mUserPaddingRightInitial = padding.right; 20445 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 20446 } 20447 mLeftPaddingDefined = false; 20448 mRightPaddingDefined = false; 20449 } 20450 20451 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 20452 // if it has a different minimum size, we should layout again 20453 if (mBackground == null 20454 || mBackground.getMinimumHeight() != background.getMinimumHeight() 20455 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 20456 requestLayout = true; 20457 } 20458 20459 // Set mBackground before we set this as the callback and start making other 20460 // background drawable state change calls. In particular, the setVisible call below 20461 // can result in drawables attempting to start animations or otherwise invalidate, 20462 // which requires the view set as the callback (us) to recognize the drawable as 20463 // belonging to it as per verifyDrawable. 20464 mBackground = background; 20465 if (background.isStateful()) { 20466 background.setState(getDrawableState()); 20467 } 20468 if (isAttachedToWindow()) { 20469 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20470 } 20471 20472 applyBackgroundTint(); 20473 20474 // Set callback last, since the view may still be initializing. 20475 background.setCallback(this); 20476 20477 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20478 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20479 requestLayout = true; 20480 } 20481 } else { 20482 /* Remove the background */ 20483 mBackground = null; 20484 if ((mViewFlags & WILL_NOT_DRAW) != 0 20485 && (mDefaultFocusHighlight == null) 20486 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 20487 mPrivateFlags |= PFLAG_SKIP_DRAW; 20488 } 20489 20490 /* 20491 * When the background is set, we try to apply its padding to this 20492 * View. When the background is removed, we don't touch this View's 20493 * padding. This is noted in the Javadocs. Hence, we don't need to 20494 * requestLayout(), the invalidate() below is sufficient. 20495 */ 20496 20497 // The old background's minimum size could have affected this 20498 // View's layout, so let's requestLayout 20499 requestLayout = true; 20500 } 20501 20502 computeOpaqueFlags(); 20503 20504 if (requestLayout) { 20505 requestLayout(); 20506 } 20507 20508 mBackgroundSizeChanged = true; 20509 invalidate(true); 20510 invalidateOutline(); 20511 } 20512 20513 /** 20514 * Gets the background drawable 20515 * 20516 * @return The drawable used as the background for this view, if any. 20517 * 20518 * @see #setBackground(Drawable) 20519 * 20520 * @attr ref android.R.styleable#View_background 20521 */ 20522 public Drawable getBackground() { 20523 return mBackground; 20524 } 20525 20526 /** 20527 * Applies a tint to the background drawable. Does not modify the current tint 20528 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20529 * <p> 20530 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 20531 * mutate the drawable and apply the specified tint and tint mode using 20532 * {@link Drawable#setTintList(ColorStateList)}. 20533 * 20534 * @param tint the tint to apply, may be {@code null} to clear tint 20535 * 20536 * @attr ref android.R.styleable#View_backgroundTint 20537 * @see #getBackgroundTintList() 20538 * @see Drawable#setTintList(ColorStateList) 20539 */ 20540 public void setBackgroundTintList(@Nullable ColorStateList tint) { 20541 if (mBackgroundTint == null) { 20542 mBackgroundTint = new TintInfo(); 20543 } 20544 mBackgroundTint.mTintList = tint; 20545 mBackgroundTint.mHasTintList = true; 20546 20547 applyBackgroundTint(); 20548 } 20549 20550 /** 20551 * Return the tint applied to the background drawable, if specified. 20552 * 20553 * @return the tint applied to the background drawable 20554 * @attr ref android.R.styleable#View_backgroundTint 20555 * @see #setBackgroundTintList(ColorStateList) 20556 */ 20557 @Nullable 20558 public ColorStateList getBackgroundTintList() { 20559 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 20560 } 20561 20562 /** 20563 * Specifies the blending mode used to apply the tint specified by 20564 * {@link #setBackgroundTintList(ColorStateList)}} to the background 20565 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20566 * 20567 * @param tintMode the blending mode used to apply the tint, may be 20568 * {@code null} to clear tint 20569 * @attr ref android.R.styleable#View_backgroundTintMode 20570 * @see #getBackgroundTintMode() 20571 * @see Drawable#setTintMode(PorterDuff.Mode) 20572 */ 20573 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20574 if (mBackgroundTint == null) { 20575 mBackgroundTint = new TintInfo(); 20576 } 20577 mBackgroundTint.mTintMode = tintMode; 20578 mBackgroundTint.mHasTintMode = true; 20579 20580 applyBackgroundTint(); 20581 } 20582 20583 /** 20584 * Return the blending mode used to apply the tint to the background 20585 * drawable, if specified. 20586 * 20587 * @return the blending mode used to apply the tint to the background 20588 * drawable 20589 * @attr ref android.R.styleable#View_backgroundTintMode 20590 * @see #setBackgroundTintMode(PorterDuff.Mode) 20591 */ 20592 @Nullable 20593 public PorterDuff.Mode getBackgroundTintMode() { 20594 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 20595 } 20596 20597 private void applyBackgroundTint() { 20598 if (mBackground != null && mBackgroundTint != null) { 20599 final TintInfo tintInfo = mBackgroundTint; 20600 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20601 mBackground = mBackground.mutate(); 20602 20603 if (tintInfo.mHasTintList) { 20604 mBackground.setTintList(tintInfo.mTintList); 20605 } 20606 20607 if (tintInfo.mHasTintMode) { 20608 mBackground.setTintMode(tintInfo.mTintMode); 20609 } 20610 20611 // The drawable (or one of its children) may not have been 20612 // stateful before applying the tint, so let's try again. 20613 if (mBackground.isStateful()) { 20614 mBackground.setState(getDrawableState()); 20615 } 20616 } 20617 } 20618 } 20619 20620 /** 20621 * Returns the drawable used as the foreground of this View. The 20622 * foreground drawable, if non-null, is always drawn on top of the view's content. 20623 * 20624 * @return a Drawable or null if no foreground was set 20625 * 20626 * @see #onDrawForeground(Canvas) 20627 */ 20628 public Drawable getForeground() { 20629 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20630 } 20631 20632 /** 20633 * Supply a Drawable that is to be rendered on top of all of the content in the view. 20634 * 20635 * @param foreground the Drawable to be drawn on top of the children 20636 * 20637 * @attr ref android.R.styleable#View_foreground 20638 */ 20639 public void setForeground(Drawable foreground) { 20640 if (mForegroundInfo == null) { 20641 if (foreground == null) { 20642 // Nothing to do. 20643 return; 20644 } 20645 mForegroundInfo = new ForegroundInfo(); 20646 } 20647 20648 if (foreground == mForegroundInfo.mDrawable) { 20649 // Nothing to do 20650 return; 20651 } 20652 20653 if (mForegroundInfo.mDrawable != null) { 20654 if (isAttachedToWindow()) { 20655 mForegroundInfo.mDrawable.setVisible(false, false); 20656 } 20657 mForegroundInfo.mDrawable.setCallback(null); 20658 unscheduleDrawable(mForegroundInfo.mDrawable); 20659 } 20660 20661 mForegroundInfo.mDrawable = foreground; 20662 mForegroundInfo.mBoundsChanged = true; 20663 if (foreground != null) { 20664 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 20665 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 20666 } 20667 foreground.setLayoutDirection(getLayoutDirection()); 20668 if (foreground.isStateful()) { 20669 foreground.setState(getDrawableState()); 20670 } 20671 applyForegroundTint(); 20672 if (isAttachedToWindow()) { 20673 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 20674 } 20675 // Set callback last, since the view may still be initializing. 20676 foreground.setCallback(this); 20677 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 20678 && (mDefaultFocusHighlight == null)) { 20679 mPrivateFlags |= PFLAG_SKIP_DRAW; 20680 } 20681 requestLayout(); 20682 invalidate(); 20683 } 20684 20685 /** 20686 * Magic bit used to support features of framework-internal window decor implementation details. 20687 * This used to live exclusively in FrameLayout. 20688 * 20689 * @return true if the foreground should draw inside the padding region or false 20690 * if it should draw inset by the view's padding 20691 * @hide internal use only; only used by FrameLayout and internal screen layouts. 20692 */ 20693 public boolean isForegroundInsidePadding() { 20694 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 20695 } 20696 20697 /** 20698 * Describes how the foreground is positioned. 20699 * 20700 * @return foreground gravity. 20701 * 20702 * @see #setForegroundGravity(int) 20703 * 20704 * @attr ref android.R.styleable#View_foregroundGravity 20705 */ 20706 public int getForegroundGravity() { 20707 return mForegroundInfo != null ? mForegroundInfo.mGravity 20708 : Gravity.START | Gravity.TOP; 20709 } 20710 20711 /** 20712 * Describes how the foreground is positioned. Defaults to START and TOP. 20713 * 20714 * @param gravity see {@link android.view.Gravity} 20715 * 20716 * @see #getForegroundGravity() 20717 * 20718 * @attr ref android.R.styleable#View_foregroundGravity 20719 */ 20720 public void setForegroundGravity(int gravity) { 20721 if (mForegroundInfo == null) { 20722 mForegroundInfo = new ForegroundInfo(); 20723 } 20724 20725 if (mForegroundInfo.mGravity != gravity) { 20726 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 20727 gravity |= Gravity.START; 20728 } 20729 20730 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 20731 gravity |= Gravity.TOP; 20732 } 20733 20734 mForegroundInfo.mGravity = gravity; 20735 requestLayout(); 20736 } 20737 } 20738 20739 /** 20740 * Applies a tint to the foreground drawable. Does not modify the current tint 20741 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 20742 * <p> 20743 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 20744 * mutate the drawable and apply the specified tint and tint mode using 20745 * {@link Drawable#setTintList(ColorStateList)}. 20746 * 20747 * @param tint the tint to apply, may be {@code null} to clear tint 20748 * 20749 * @attr ref android.R.styleable#View_foregroundTint 20750 * @see #getForegroundTintList() 20751 * @see Drawable#setTintList(ColorStateList) 20752 */ 20753 public void setForegroundTintList(@Nullable ColorStateList tint) { 20754 if (mForegroundInfo == null) { 20755 mForegroundInfo = new ForegroundInfo(); 20756 } 20757 if (mForegroundInfo.mTintInfo == null) { 20758 mForegroundInfo.mTintInfo = new TintInfo(); 20759 } 20760 mForegroundInfo.mTintInfo.mTintList = tint; 20761 mForegroundInfo.mTintInfo.mHasTintList = true; 20762 20763 applyForegroundTint(); 20764 } 20765 20766 /** 20767 * Return the tint applied to the foreground drawable, if specified. 20768 * 20769 * @return the tint applied to the foreground drawable 20770 * @attr ref android.R.styleable#View_foregroundTint 20771 * @see #setForegroundTintList(ColorStateList) 20772 */ 20773 @Nullable 20774 public ColorStateList getForegroundTintList() { 20775 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20776 ? mForegroundInfo.mTintInfo.mTintList : null; 20777 } 20778 20779 /** 20780 * Specifies the blending mode used to apply the tint specified by 20781 * {@link #setForegroundTintList(ColorStateList)}} to the background 20782 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 20783 * 20784 * @param tintMode the blending mode used to apply the tint, may be 20785 * {@code null} to clear tint 20786 * @attr ref android.R.styleable#View_foregroundTintMode 20787 * @see #getForegroundTintMode() 20788 * @see Drawable#setTintMode(PorterDuff.Mode) 20789 */ 20790 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 20791 if (mForegroundInfo == null) { 20792 mForegroundInfo = new ForegroundInfo(); 20793 } 20794 if (mForegroundInfo.mTintInfo == null) { 20795 mForegroundInfo.mTintInfo = new TintInfo(); 20796 } 20797 mForegroundInfo.mTintInfo.mTintMode = tintMode; 20798 mForegroundInfo.mTintInfo.mHasTintMode = true; 20799 20800 applyForegroundTint(); 20801 } 20802 20803 /** 20804 * Return the blending mode used to apply the tint to the foreground 20805 * drawable, if specified. 20806 * 20807 * @return the blending mode used to apply the tint to the foreground 20808 * drawable 20809 * @attr ref android.R.styleable#View_foregroundTintMode 20810 * @see #setForegroundTintMode(PorterDuff.Mode) 20811 */ 20812 @Nullable 20813 public PorterDuff.Mode getForegroundTintMode() { 20814 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 20815 ? mForegroundInfo.mTintInfo.mTintMode : null; 20816 } 20817 20818 private void applyForegroundTint() { 20819 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20820 && mForegroundInfo.mTintInfo != null) { 20821 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 20822 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 20823 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 20824 20825 if (tintInfo.mHasTintList) { 20826 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 20827 } 20828 20829 if (tintInfo.mHasTintMode) { 20830 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 20831 } 20832 20833 // The drawable (or one of its children) may not have been 20834 // stateful before applying the tint, so let's try again. 20835 if (mForegroundInfo.mDrawable.isStateful()) { 20836 mForegroundInfo.mDrawable.setState(getDrawableState()); 20837 } 20838 } 20839 } 20840 } 20841 20842 /** 20843 * Get the drawable to be overlayed when a view is autofilled 20844 * 20845 * @return The drawable 20846 * 20847 * @throws IllegalStateException if the drawable could not be found. 20848 */ 20849 @Nullable private Drawable getAutofilledDrawable() { 20850 if (mAttachInfo == null) { 20851 return null; 20852 } 20853 // Lazily load the isAutofilled drawable. 20854 if (mAttachInfo.mAutofilledDrawable == null) { 20855 Context rootContext = getRootView().getContext(); 20856 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 20857 int attributeResourceId = a.getResourceId(0, 0); 20858 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 20859 a.recycle(); 20860 } 20861 20862 return mAttachInfo.mAutofilledDrawable; 20863 } 20864 20865 /** 20866 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 20867 * 20868 * @param canvas The canvas to draw on 20869 */ 20870 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 20871 if (isAutofilled()) { 20872 Drawable autofilledHighlight = getAutofilledDrawable(); 20873 20874 if (autofilledHighlight != null) { 20875 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 20876 autofilledHighlight.draw(canvas); 20877 } 20878 } 20879 } 20880 20881 /** 20882 * Draw any foreground content for this view. 20883 * 20884 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 20885 * drawable or other view-specific decorations. The foreground is drawn on top of the 20886 * primary view content.</p> 20887 * 20888 * @param canvas canvas to draw into 20889 */ 20890 public void onDrawForeground(Canvas canvas) { 20891 onDrawScrollIndicators(canvas); 20892 onDrawScrollBars(canvas); 20893 20894 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 20895 if (foreground != null) { 20896 if (mForegroundInfo.mBoundsChanged) { 20897 mForegroundInfo.mBoundsChanged = false; 20898 final Rect selfBounds = mForegroundInfo.mSelfBounds; 20899 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 20900 20901 if (mForegroundInfo.mInsidePadding) { 20902 selfBounds.set(0, 0, getWidth(), getHeight()); 20903 } else { 20904 selfBounds.set(getPaddingLeft(), getPaddingTop(), 20905 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 20906 } 20907 20908 final int ld = getLayoutDirection(); 20909 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 20910 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 20911 foreground.setBounds(overlayBounds); 20912 } 20913 20914 foreground.draw(canvas); 20915 } 20916 } 20917 20918 /** 20919 * Sets the padding. The view may add on the space required to display 20920 * the scrollbars, depending on the style and visibility of the scrollbars. 20921 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 20922 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 20923 * from the values set in this call. 20924 * 20925 * @attr ref android.R.styleable#View_padding 20926 * @attr ref android.R.styleable#View_paddingBottom 20927 * @attr ref android.R.styleable#View_paddingLeft 20928 * @attr ref android.R.styleable#View_paddingRight 20929 * @attr ref android.R.styleable#View_paddingTop 20930 * @param left the left padding in pixels 20931 * @param top the top padding in pixels 20932 * @param right the right padding in pixels 20933 * @param bottom the bottom padding in pixels 20934 */ 20935 public void setPadding(int left, int top, int right, int bottom) { 20936 resetResolvedPaddingInternal(); 20937 20938 mUserPaddingStart = UNDEFINED_PADDING; 20939 mUserPaddingEnd = UNDEFINED_PADDING; 20940 20941 mUserPaddingLeftInitial = left; 20942 mUserPaddingRightInitial = right; 20943 20944 mLeftPaddingDefined = true; 20945 mRightPaddingDefined = true; 20946 20947 internalSetPadding(left, top, right, bottom); 20948 } 20949 20950 /** 20951 * @hide 20952 */ 20953 protected void internalSetPadding(int left, int top, int right, int bottom) { 20954 mUserPaddingLeft = left; 20955 mUserPaddingRight = right; 20956 mUserPaddingBottom = bottom; 20957 20958 final int viewFlags = mViewFlags; 20959 boolean changed = false; 20960 20961 // Common case is there are no scroll bars. 20962 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 20963 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 20964 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 20965 ? 0 : getVerticalScrollbarWidth(); 20966 switch (mVerticalScrollbarPosition) { 20967 case SCROLLBAR_POSITION_DEFAULT: 20968 if (isLayoutRtl()) { 20969 left += offset; 20970 } else { 20971 right += offset; 20972 } 20973 break; 20974 case SCROLLBAR_POSITION_RIGHT: 20975 right += offset; 20976 break; 20977 case SCROLLBAR_POSITION_LEFT: 20978 left += offset; 20979 break; 20980 } 20981 } 20982 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 20983 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 20984 ? 0 : getHorizontalScrollbarHeight(); 20985 } 20986 } 20987 20988 if (mPaddingLeft != left) { 20989 changed = true; 20990 mPaddingLeft = left; 20991 } 20992 if (mPaddingTop != top) { 20993 changed = true; 20994 mPaddingTop = top; 20995 } 20996 if (mPaddingRight != right) { 20997 changed = true; 20998 mPaddingRight = right; 20999 } 21000 if (mPaddingBottom != bottom) { 21001 changed = true; 21002 mPaddingBottom = bottom; 21003 } 21004 21005 if (changed) { 21006 requestLayout(); 21007 invalidateOutline(); 21008 } 21009 } 21010 21011 /** 21012 * Sets the relative padding. The view may add on the space required to display 21013 * the scrollbars, depending on the style and visibility of the scrollbars. 21014 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 21015 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 21016 * from the values set in this call. 21017 * 21018 * @attr ref android.R.styleable#View_padding 21019 * @attr ref android.R.styleable#View_paddingBottom 21020 * @attr ref android.R.styleable#View_paddingStart 21021 * @attr ref android.R.styleable#View_paddingEnd 21022 * @attr ref android.R.styleable#View_paddingTop 21023 * @param start the start padding in pixels 21024 * @param top the top padding in pixels 21025 * @param end the end padding in pixels 21026 * @param bottom the bottom padding in pixels 21027 */ 21028 public void setPaddingRelative(int start, int top, int end, int bottom) { 21029 resetResolvedPaddingInternal(); 21030 21031 mUserPaddingStart = start; 21032 mUserPaddingEnd = end; 21033 mLeftPaddingDefined = true; 21034 mRightPaddingDefined = true; 21035 21036 switch(getLayoutDirection()) { 21037 case LAYOUT_DIRECTION_RTL: 21038 mUserPaddingLeftInitial = end; 21039 mUserPaddingRightInitial = start; 21040 internalSetPadding(end, top, start, bottom); 21041 break; 21042 case LAYOUT_DIRECTION_LTR: 21043 default: 21044 mUserPaddingLeftInitial = start; 21045 mUserPaddingRightInitial = end; 21046 internalSetPadding(start, top, end, bottom); 21047 } 21048 } 21049 21050 /** 21051 * Returns the top padding of this view. 21052 * 21053 * @return the top padding in pixels 21054 */ 21055 public int getPaddingTop() { 21056 return mPaddingTop; 21057 } 21058 21059 /** 21060 * Returns the bottom padding of this view. If there are inset and enabled 21061 * scrollbars, this value may include the space required to display the 21062 * scrollbars as well. 21063 * 21064 * @return the bottom padding in pixels 21065 */ 21066 public int getPaddingBottom() { 21067 return mPaddingBottom; 21068 } 21069 21070 /** 21071 * Returns the left padding of this view. If there are inset and enabled 21072 * scrollbars, this value may include the space required to display the 21073 * scrollbars as well. 21074 * 21075 * @return the left padding in pixels 21076 */ 21077 public int getPaddingLeft() { 21078 if (!isPaddingResolved()) { 21079 resolvePadding(); 21080 } 21081 return mPaddingLeft; 21082 } 21083 21084 /** 21085 * Returns the start padding of this view depending on its resolved layout direction. 21086 * If there are inset and enabled scrollbars, this value may include the space 21087 * required to display the scrollbars as well. 21088 * 21089 * @return the start padding in pixels 21090 */ 21091 public int getPaddingStart() { 21092 if (!isPaddingResolved()) { 21093 resolvePadding(); 21094 } 21095 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21096 mPaddingRight : mPaddingLeft; 21097 } 21098 21099 /** 21100 * Returns the right padding of this view. If there are inset and enabled 21101 * scrollbars, this value may include the space required to display the 21102 * scrollbars as well. 21103 * 21104 * @return the right padding in pixels 21105 */ 21106 public int getPaddingRight() { 21107 if (!isPaddingResolved()) { 21108 resolvePadding(); 21109 } 21110 return mPaddingRight; 21111 } 21112 21113 /** 21114 * Returns the end padding of this view depending on its resolved layout direction. 21115 * If there are inset and enabled scrollbars, this value may include the space 21116 * required to display the scrollbars as well. 21117 * 21118 * @return the end padding in pixels 21119 */ 21120 public int getPaddingEnd() { 21121 if (!isPaddingResolved()) { 21122 resolvePadding(); 21123 } 21124 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 21125 mPaddingLeft : mPaddingRight; 21126 } 21127 21128 /** 21129 * Return if the padding has been set through relative values 21130 * {@link #setPaddingRelative(int, int, int, int)} or through 21131 * @attr ref android.R.styleable#View_paddingStart or 21132 * @attr ref android.R.styleable#View_paddingEnd 21133 * 21134 * @return true if the padding is relative or false if it is not. 21135 */ 21136 public boolean isPaddingRelative() { 21137 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 21138 } 21139 21140 Insets computeOpticalInsets() { 21141 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 21142 } 21143 21144 /** 21145 * @hide 21146 */ 21147 public void resetPaddingToInitialValues() { 21148 if (isRtlCompatibilityMode()) { 21149 mPaddingLeft = mUserPaddingLeftInitial; 21150 mPaddingRight = mUserPaddingRightInitial; 21151 return; 21152 } 21153 if (isLayoutRtl()) { 21154 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 21155 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 21156 } else { 21157 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 21158 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 21159 } 21160 } 21161 21162 /** 21163 * @hide 21164 */ 21165 public Insets getOpticalInsets() { 21166 if (mLayoutInsets == null) { 21167 mLayoutInsets = computeOpticalInsets(); 21168 } 21169 return mLayoutInsets; 21170 } 21171 21172 /** 21173 * Set this view's optical insets. 21174 * 21175 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 21176 * property. Views that compute their own optical insets should call it as part of measurement. 21177 * This method does not request layout. If you are setting optical insets outside of 21178 * measure/layout itself you will want to call requestLayout() yourself. 21179 * </p> 21180 * @hide 21181 */ 21182 public void setOpticalInsets(Insets insets) { 21183 mLayoutInsets = insets; 21184 } 21185 21186 /** 21187 * Changes the selection state of this view. A view can be selected or not. 21188 * Note that selection is not the same as focus. Views are typically 21189 * selected in the context of an AdapterView like ListView or GridView; 21190 * the selected view is the view that is highlighted. 21191 * 21192 * @param selected true if the view must be selected, false otherwise 21193 */ 21194 public void setSelected(boolean selected) { 21195 //noinspection DoubleNegation 21196 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 21197 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 21198 if (!selected) resetPressedState(); 21199 invalidate(true); 21200 refreshDrawableState(); 21201 dispatchSetSelected(selected); 21202 if (selected) { 21203 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 21204 } else { 21205 notifyViewAccessibilityStateChangedIfNeeded( 21206 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 21207 } 21208 } 21209 } 21210 21211 /** 21212 * Dispatch setSelected to all of this View's children. 21213 * 21214 * @see #setSelected(boolean) 21215 * 21216 * @param selected The new selected state 21217 */ 21218 protected void dispatchSetSelected(boolean selected) { 21219 } 21220 21221 /** 21222 * Indicates the selection state of this view. 21223 * 21224 * @return true if the view is selected, false otherwise 21225 */ 21226 @ViewDebug.ExportedProperty 21227 public boolean isSelected() { 21228 return (mPrivateFlags & PFLAG_SELECTED) != 0; 21229 } 21230 21231 /** 21232 * Changes the activated state of this view. A view can be activated or not. 21233 * Note that activation is not the same as selection. Selection is 21234 * a transient property, representing the view (hierarchy) the user is 21235 * currently interacting with. Activation is a longer-term state that the 21236 * user can move views in and out of. For example, in a list view with 21237 * single or multiple selection enabled, the views in the current selection 21238 * set are activated. (Um, yeah, we are deeply sorry about the terminology 21239 * here.) The activated state is propagated down to children of the view it 21240 * is set on. 21241 * 21242 * @param activated true if the view must be activated, false otherwise 21243 */ 21244 public void setActivated(boolean activated) { 21245 //noinspection DoubleNegation 21246 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 21247 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 21248 invalidate(true); 21249 refreshDrawableState(); 21250 dispatchSetActivated(activated); 21251 } 21252 } 21253 21254 /** 21255 * Dispatch setActivated to all of this View's children. 21256 * 21257 * @see #setActivated(boolean) 21258 * 21259 * @param activated The new activated state 21260 */ 21261 protected void dispatchSetActivated(boolean activated) { 21262 } 21263 21264 /** 21265 * Indicates the activation state of this view. 21266 * 21267 * @return true if the view is activated, false otherwise 21268 */ 21269 @ViewDebug.ExportedProperty 21270 public boolean isActivated() { 21271 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 21272 } 21273 21274 /** 21275 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 21276 * observer can be used to get notifications when global events, like 21277 * layout, happen. 21278 * 21279 * The returned ViewTreeObserver observer is not guaranteed to remain 21280 * valid for the lifetime of this View. If the caller of this method keeps 21281 * a long-lived reference to ViewTreeObserver, it should always check for 21282 * the return value of {@link ViewTreeObserver#isAlive()}. 21283 * 21284 * @return The ViewTreeObserver for this view's hierarchy. 21285 */ 21286 public ViewTreeObserver getViewTreeObserver() { 21287 if (mAttachInfo != null) { 21288 return mAttachInfo.mTreeObserver; 21289 } 21290 if (mFloatingTreeObserver == null) { 21291 mFloatingTreeObserver = new ViewTreeObserver(mContext); 21292 } 21293 return mFloatingTreeObserver; 21294 } 21295 21296 /** 21297 * <p>Finds the topmost view in the current view hierarchy.</p> 21298 * 21299 * @return the topmost view containing this view 21300 */ 21301 public View getRootView() { 21302 if (mAttachInfo != null) { 21303 final View v = mAttachInfo.mRootView; 21304 if (v != null) { 21305 return v; 21306 } 21307 } 21308 21309 View parent = this; 21310 21311 while (parent.mParent != null && parent.mParent instanceof View) { 21312 parent = (View) parent.mParent; 21313 } 21314 21315 return parent; 21316 } 21317 21318 /** 21319 * Transforms a motion event from view-local coordinates to on-screen 21320 * coordinates. 21321 * 21322 * @param ev the view-local motion event 21323 * @return false if the transformation could not be applied 21324 * @hide 21325 */ 21326 public boolean toGlobalMotionEvent(MotionEvent ev) { 21327 final AttachInfo info = mAttachInfo; 21328 if (info == null) { 21329 return false; 21330 } 21331 21332 final Matrix m = info.mTmpMatrix; 21333 m.set(Matrix.IDENTITY_MATRIX); 21334 transformMatrixToGlobal(m); 21335 ev.transform(m); 21336 return true; 21337 } 21338 21339 /** 21340 * Transforms a motion event from on-screen coordinates to view-local 21341 * coordinates. 21342 * 21343 * @param ev the on-screen motion event 21344 * @return false if the transformation could not be applied 21345 * @hide 21346 */ 21347 public boolean toLocalMotionEvent(MotionEvent ev) { 21348 final AttachInfo info = mAttachInfo; 21349 if (info == null) { 21350 return false; 21351 } 21352 21353 final Matrix m = info.mTmpMatrix; 21354 m.set(Matrix.IDENTITY_MATRIX); 21355 transformMatrixToLocal(m); 21356 ev.transform(m); 21357 return true; 21358 } 21359 21360 /** 21361 * Modifies the input matrix such that it maps view-local coordinates to 21362 * on-screen coordinates. 21363 * 21364 * @param m input matrix to modify 21365 * @hide 21366 */ 21367 public void transformMatrixToGlobal(Matrix m) { 21368 final ViewParent parent = mParent; 21369 if (parent instanceof View) { 21370 final View vp = (View) parent; 21371 vp.transformMatrixToGlobal(m); 21372 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 21373 } else if (parent instanceof ViewRootImpl) { 21374 final ViewRootImpl vr = (ViewRootImpl) parent; 21375 vr.transformMatrixToGlobal(m); 21376 m.preTranslate(0, -vr.mCurScrollY); 21377 } 21378 21379 m.preTranslate(mLeft, mTop); 21380 21381 if (!hasIdentityMatrix()) { 21382 m.preConcat(getMatrix()); 21383 } 21384 } 21385 21386 /** 21387 * Modifies the input matrix such that it maps on-screen coordinates to 21388 * view-local coordinates. 21389 * 21390 * @param m input matrix to modify 21391 * @hide 21392 */ 21393 public void transformMatrixToLocal(Matrix m) { 21394 final ViewParent parent = mParent; 21395 if (parent instanceof View) { 21396 final View vp = (View) parent; 21397 vp.transformMatrixToLocal(m); 21398 m.postTranslate(vp.mScrollX, vp.mScrollY); 21399 } else if (parent instanceof ViewRootImpl) { 21400 final ViewRootImpl vr = (ViewRootImpl) parent; 21401 vr.transformMatrixToLocal(m); 21402 m.postTranslate(0, vr.mCurScrollY); 21403 } 21404 21405 m.postTranslate(-mLeft, -mTop); 21406 21407 if (!hasIdentityMatrix()) { 21408 m.postConcat(getInverseMatrix()); 21409 } 21410 } 21411 21412 /** 21413 * @hide 21414 */ 21415 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 21416 @ViewDebug.IntToString(from = 0, to = "x"), 21417 @ViewDebug.IntToString(from = 1, to = "y") 21418 }) 21419 public int[] getLocationOnScreen() { 21420 int[] location = new int[2]; 21421 getLocationOnScreen(location); 21422 return location; 21423 } 21424 21425 /** 21426 * <p>Computes the coordinates of this view on the screen. The argument 21427 * must be an array of two integers. After the method returns, the array 21428 * contains the x and y location in that order.</p> 21429 * 21430 * @param outLocation an array of two integers in which to hold the coordinates 21431 */ 21432 public void getLocationOnScreen(@Size(2) int[] outLocation) { 21433 getLocationInWindow(outLocation); 21434 21435 final AttachInfo info = mAttachInfo; 21436 if (info != null) { 21437 outLocation[0] += info.mWindowLeft; 21438 outLocation[1] += info.mWindowTop; 21439 } 21440 } 21441 21442 /** 21443 * <p>Computes the coordinates of this view in its window. The argument 21444 * must be an array of two integers. After the method returns, the array 21445 * contains the x and y location in that order.</p> 21446 * 21447 * @param outLocation an array of two integers in which to hold the coordinates 21448 */ 21449 public void getLocationInWindow(@Size(2) int[] outLocation) { 21450 if (outLocation == null || outLocation.length < 2) { 21451 throw new IllegalArgumentException("outLocation must be an array of two integers"); 21452 } 21453 21454 outLocation[0] = 0; 21455 outLocation[1] = 0; 21456 21457 transformFromViewToWindowSpace(outLocation); 21458 } 21459 21460 /** @hide */ 21461 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 21462 if (inOutLocation == null || inOutLocation.length < 2) { 21463 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 21464 } 21465 21466 if (mAttachInfo == null) { 21467 // When the view is not attached to a window, this method does not make sense 21468 inOutLocation[0] = inOutLocation[1] = 0; 21469 return; 21470 } 21471 21472 float position[] = mAttachInfo.mTmpTransformLocation; 21473 position[0] = inOutLocation[0]; 21474 position[1] = inOutLocation[1]; 21475 21476 if (!hasIdentityMatrix()) { 21477 getMatrix().mapPoints(position); 21478 } 21479 21480 position[0] += mLeft; 21481 position[1] += mTop; 21482 21483 ViewParent viewParent = mParent; 21484 while (viewParent instanceof View) { 21485 final View view = (View) viewParent; 21486 21487 position[0] -= view.mScrollX; 21488 position[1] -= view.mScrollY; 21489 21490 if (!view.hasIdentityMatrix()) { 21491 view.getMatrix().mapPoints(position); 21492 } 21493 21494 position[0] += view.mLeft; 21495 position[1] += view.mTop; 21496 21497 viewParent = view.mParent; 21498 } 21499 21500 if (viewParent instanceof ViewRootImpl) { 21501 // *cough* 21502 final ViewRootImpl vr = (ViewRootImpl) viewParent; 21503 position[1] -= vr.mCurScrollY; 21504 } 21505 21506 inOutLocation[0] = Math.round(position[0]); 21507 inOutLocation[1] = Math.round(position[1]); 21508 } 21509 21510 /** 21511 * @param id the id of the view to be found 21512 * @return the view of the specified id, null if cannot be found 21513 * @hide 21514 */ 21515 protected <T extends View> T findViewTraversal(@IdRes int id) { 21516 if (id == mID) { 21517 return (T) this; 21518 } 21519 return null; 21520 } 21521 21522 /** 21523 * @param tag the tag of the view to be found 21524 * @return the view of specified tag, null if cannot be found 21525 * @hide 21526 */ 21527 protected <T extends View> T findViewWithTagTraversal(Object tag) { 21528 if (tag != null && tag.equals(mTag)) { 21529 return (T) this; 21530 } 21531 return null; 21532 } 21533 21534 /** 21535 * @param predicate The predicate to evaluate. 21536 * @param childToSkip If not null, ignores this child during the recursive traversal. 21537 * @return The first view that matches the predicate or null. 21538 * @hide 21539 */ 21540 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 21541 View childToSkip) { 21542 if (predicate.test(this)) { 21543 return (T) this; 21544 } 21545 return null; 21546 } 21547 21548 /** 21549 * Finds the first descendant view with the given ID, the view itself if 21550 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 21551 * (< 0) or there is no matching view in the hierarchy. 21552 * <p> 21553 * <strong>Note:</strong> In most cases -- depending on compiler support -- 21554 * the resulting view is automatically cast to the target class type. If 21555 * the target class type is unconstrained, an explicit cast may be 21556 * necessary. 21557 * 21558 * @param id the ID to search for 21559 * @return a view with given ID if found, or {@code null} otherwise 21560 * @see View#findViewById(int) 21561 */ 21562 @Nullable 21563 public final <T extends View> T findViewById(@IdRes int id) { 21564 if (id == NO_ID) { 21565 return null; 21566 } 21567 return findViewTraversal(id); 21568 } 21569 21570 /** 21571 * Finds a view by its unuque and stable accessibility id. 21572 * 21573 * @param accessibilityId The searched accessibility id. 21574 * @return The found view. 21575 */ 21576 final <T extends View> T findViewByAccessibilityId(int accessibilityId) { 21577 if (accessibilityId < 0) { 21578 return null; 21579 } 21580 T view = findViewByAccessibilityIdTraversal(accessibilityId); 21581 if (view != null) { 21582 return view.includeForAccessibility() ? view : null; 21583 } 21584 return null; 21585 } 21586 21587 /** 21588 * Performs the traversal to find a view by its unique and stable accessibility id. 21589 * 21590 * <strong>Note:</strong>This method does not stop at the root namespace 21591 * boundary since the user can touch the screen at an arbitrary location 21592 * potentially crossing the root namespace boundary which will send an 21593 * accessibility event to accessibility services and they should be able 21594 * to obtain the event source. Also accessibility ids are guaranteed to be 21595 * unique in the window. 21596 * 21597 * @param accessibilityId The accessibility id. 21598 * @return The found view. 21599 * @hide 21600 */ 21601 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 21602 if (getAccessibilityViewId() == accessibilityId) { 21603 return (T) this; 21604 } 21605 return null; 21606 } 21607 21608 /** 21609 * Performs the traversal to find a view by its autofill id. 21610 * 21611 * <strong>Note:</strong>This method does not stop at the root namespace 21612 * boundary. 21613 * 21614 * @param autofillId The autofill id. 21615 * @return The found view. 21616 * @hide 21617 */ 21618 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 21619 if (getAutofillViewId() == autofillId) { 21620 return (T) this; 21621 } 21622 return null; 21623 } 21624 21625 /** 21626 * Look for a child view with the given tag. If this view has the given 21627 * tag, return this view. 21628 * 21629 * @param tag The tag to search for, using "tag.equals(getTag())". 21630 * @return The View that has the given tag in the hierarchy or null 21631 */ 21632 public final <T extends View> T findViewWithTag(Object tag) { 21633 if (tag == null) { 21634 return null; 21635 } 21636 return findViewWithTagTraversal(tag); 21637 } 21638 21639 /** 21640 * Look for a child view that matches the specified predicate. 21641 * If this view matches the predicate, return this view. 21642 * 21643 * @param predicate The predicate to evaluate. 21644 * @return The first view that matches the predicate or null. 21645 * @hide 21646 */ 21647 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 21648 return findViewByPredicateTraversal(predicate, null); 21649 } 21650 21651 /** 21652 * Look for a child view that matches the specified predicate, 21653 * starting with the specified view and its descendents and then 21654 * recusively searching the ancestors and siblings of that view 21655 * until this view is reached. 21656 * 21657 * This method is useful in cases where the predicate does not match 21658 * a single unique view (perhaps multiple views use the same id) 21659 * and we are trying to find the view that is "closest" in scope to the 21660 * starting view. 21661 * 21662 * @param start The view to start from. 21663 * @param predicate The predicate to evaluate. 21664 * @return The first view that matches the predicate or null. 21665 * @hide 21666 */ 21667 public final <T extends View> T findViewByPredicateInsideOut( 21668 View start, Predicate<View> predicate) { 21669 View childToSkip = null; 21670 for (;;) { 21671 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 21672 if (view != null || start == this) { 21673 return view; 21674 } 21675 21676 ViewParent parent = start.getParent(); 21677 if (parent == null || !(parent instanceof View)) { 21678 return null; 21679 } 21680 21681 childToSkip = start; 21682 start = (View) parent; 21683 } 21684 } 21685 21686 /** 21687 * Sets the identifier for this view. The identifier does not have to be 21688 * unique in this view's hierarchy. The identifier should be a positive 21689 * number. 21690 * 21691 * @see #NO_ID 21692 * @see #getId() 21693 * @see #findViewById(int) 21694 * 21695 * @param id a number used to identify the view 21696 * 21697 * @attr ref android.R.styleable#View_id 21698 */ 21699 public void setId(@IdRes int id) { 21700 mID = id; 21701 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 21702 mID = generateViewId(); 21703 } 21704 } 21705 21706 /** 21707 * {@hide} 21708 * 21709 * @param isRoot true if the view belongs to the root namespace, false 21710 * otherwise 21711 */ 21712 public void setIsRootNamespace(boolean isRoot) { 21713 if (isRoot) { 21714 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 21715 } else { 21716 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 21717 } 21718 } 21719 21720 /** 21721 * {@hide} 21722 * 21723 * @return true if the view belongs to the root namespace, false otherwise 21724 */ 21725 public boolean isRootNamespace() { 21726 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 21727 } 21728 21729 /** 21730 * Returns this view's identifier. 21731 * 21732 * @return a positive integer used to identify the view or {@link #NO_ID} 21733 * if the view has no ID 21734 * 21735 * @see #setId(int) 21736 * @see #findViewById(int) 21737 * @attr ref android.R.styleable#View_id 21738 */ 21739 @IdRes 21740 @ViewDebug.CapturedViewProperty 21741 public int getId() { 21742 return mID; 21743 } 21744 21745 /** 21746 * Returns this view's tag. 21747 * 21748 * @return the Object stored in this view as a tag, or {@code null} if not 21749 * set 21750 * 21751 * @see #setTag(Object) 21752 * @see #getTag(int) 21753 */ 21754 @ViewDebug.ExportedProperty 21755 public Object getTag() { 21756 return mTag; 21757 } 21758 21759 /** 21760 * Sets the tag associated with this view. A tag can be used to mark 21761 * a view in its hierarchy and does not have to be unique within the 21762 * hierarchy. Tags can also be used to store data within a view without 21763 * resorting to another data structure. 21764 * 21765 * @param tag an Object to tag the view with 21766 * 21767 * @see #getTag() 21768 * @see #setTag(int, Object) 21769 */ 21770 public void setTag(final Object tag) { 21771 mTag = tag; 21772 } 21773 21774 /** 21775 * Returns the tag associated with this view and the specified key. 21776 * 21777 * @param key The key identifying the tag 21778 * 21779 * @return the Object stored in this view as a tag, or {@code null} if not 21780 * set 21781 * 21782 * @see #setTag(int, Object) 21783 * @see #getTag() 21784 */ 21785 public Object getTag(int key) { 21786 if (mKeyedTags != null) return mKeyedTags.get(key); 21787 return null; 21788 } 21789 21790 /** 21791 * Sets a tag associated with this view and a key. A tag can be used 21792 * to mark a view in its hierarchy and does not have to be unique within 21793 * the hierarchy. Tags can also be used to store data within a view 21794 * without resorting to another data structure. 21795 * 21796 * The specified key should be an id declared in the resources of the 21797 * application to ensure it is unique (see the <a 21798 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 21799 * Keys identified as belonging to 21800 * the Android framework or not associated with any package will cause 21801 * an {@link IllegalArgumentException} to be thrown. 21802 * 21803 * @param key The key identifying the tag 21804 * @param tag An Object to tag the view with 21805 * 21806 * @throws IllegalArgumentException If they specified key is not valid 21807 * 21808 * @see #setTag(Object) 21809 * @see #getTag(int) 21810 */ 21811 public void setTag(int key, final Object tag) { 21812 // If the package id is 0x00 or 0x01, it's either an undefined package 21813 // or a framework id 21814 if ((key >>> 24) < 2) { 21815 throw new IllegalArgumentException("The key must be an application-specific " 21816 + "resource id."); 21817 } 21818 21819 setKeyedTag(key, tag); 21820 } 21821 21822 /** 21823 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 21824 * framework id. 21825 * 21826 * @hide 21827 */ 21828 public void setTagInternal(int key, Object tag) { 21829 if ((key >>> 24) != 0x1) { 21830 throw new IllegalArgumentException("The key must be a framework-specific " 21831 + "resource id."); 21832 } 21833 21834 setKeyedTag(key, tag); 21835 } 21836 21837 private void setKeyedTag(int key, Object tag) { 21838 if (mKeyedTags == null) { 21839 mKeyedTags = new SparseArray<Object>(2); 21840 } 21841 21842 mKeyedTags.put(key, tag); 21843 } 21844 21845 /** 21846 * Prints information about this view in the log output, with the tag 21847 * {@link #VIEW_LOG_TAG}. 21848 * 21849 * @hide 21850 */ 21851 public void debug() { 21852 debug(0); 21853 } 21854 21855 /** 21856 * Prints information about this view in the log output, with the tag 21857 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 21858 * indentation defined by the <code>depth</code>. 21859 * 21860 * @param depth the indentation level 21861 * 21862 * @hide 21863 */ 21864 protected void debug(int depth) { 21865 String output = debugIndent(depth - 1); 21866 21867 output += "+ " + this; 21868 int id = getId(); 21869 if (id != -1) { 21870 output += " (id=" + id + ")"; 21871 } 21872 Object tag = getTag(); 21873 if (tag != null) { 21874 output += " (tag=" + tag + ")"; 21875 } 21876 Log.d(VIEW_LOG_TAG, output); 21877 21878 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 21879 output = debugIndent(depth) + " FOCUSED"; 21880 Log.d(VIEW_LOG_TAG, output); 21881 } 21882 21883 output = debugIndent(depth); 21884 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 21885 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 21886 + "} "; 21887 Log.d(VIEW_LOG_TAG, output); 21888 21889 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 21890 || mPaddingBottom != 0) { 21891 output = debugIndent(depth); 21892 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 21893 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 21894 Log.d(VIEW_LOG_TAG, output); 21895 } 21896 21897 output = debugIndent(depth); 21898 output += "mMeasureWidth=" + mMeasuredWidth + 21899 " mMeasureHeight=" + mMeasuredHeight; 21900 Log.d(VIEW_LOG_TAG, output); 21901 21902 output = debugIndent(depth); 21903 if (mLayoutParams == null) { 21904 output += "BAD! no layout params"; 21905 } else { 21906 output = mLayoutParams.debug(output); 21907 } 21908 Log.d(VIEW_LOG_TAG, output); 21909 21910 output = debugIndent(depth); 21911 output += "flags={"; 21912 output += View.printFlags(mViewFlags); 21913 output += "}"; 21914 Log.d(VIEW_LOG_TAG, output); 21915 21916 output = debugIndent(depth); 21917 output += "privateFlags={"; 21918 output += View.printPrivateFlags(mPrivateFlags); 21919 output += "}"; 21920 Log.d(VIEW_LOG_TAG, output); 21921 } 21922 21923 /** 21924 * Creates a string of whitespaces used for indentation. 21925 * 21926 * @param depth the indentation level 21927 * @return a String containing (depth * 2 + 3) * 2 white spaces 21928 * 21929 * @hide 21930 */ 21931 protected static String debugIndent(int depth) { 21932 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 21933 for (int i = 0; i < (depth * 2) + 3; i++) { 21934 spaces.append(' ').append(' '); 21935 } 21936 return spaces.toString(); 21937 } 21938 21939 /** 21940 * <p>Return the offset of the widget's text baseline from the widget's top 21941 * boundary. If this widget does not support baseline alignment, this 21942 * method returns -1. </p> 21943 * 21944 * @return the offset of the baseline within the widget's bounds or -1 21945 * if baseline alignment is not supported 21946 */ 21947 @ViewDebug.ExportedProperty(category = "layout") 21948 public int getBaseline() { 21949 return -1; 21950 } 21951 21952 /** 21953 * Returns whether the view hierarchy is currently undergoing a layout pass. This 21954 * information is useful to avoid situations such as calling {@link #requestLayout()} during 21955 * a layout pass. 21956 * 21957 * @return whether the view hierarchy is currently undergoing a layout pass 21958 */ 21959 public boolean isInLayout() { 21960 ViewRootImpl viewRoot = getViewRootImpl(); 21961 return (viewRoot != null && viewRoot.isInLayout()); 21962 } 21963 21964 /** 21965 * Call this when something has changed which has invalidated the 21966 * layout of this view. This will schedule a layout pass of the view 21967 * tree. This should not be called while the view hierarchy is currently in a layout 21968 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 21969 * end of the current layout pass (and then layout will run again) or after the current 21970 * frame is drawn and the next layout occurs. 21971 * 21972 * <p>Subclasses which override this method should call the superclass method to 21973 * handle possible request-during-layout errors correctly.</p> 21974 */ 21975 @CallSuper 21976 public void requestLayout() { 21977 if (mMeasureCache != null) mMeasureCache.clear(); 21978 21979 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 21980 // Only trigger request-during-layout logic if this is the view requesting it, 21981 // not the views in its parent hierarchy 21982 ViewRootImpl viewRoot = getViewRootImpl(); 21983 if (viewRoot != null && viewRoot.isInLayout()) { 21984 if (!viewRoot.requestLayoutDuringLayout(this)) { 21985 return; 21986 } 21987 } 21988 mAttachInfo.mViewRequestingLayout = this; 21989 } 21990 21991 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 21992 mPrivateFlags |= PFLAG_INVALIDATED; 21993 21994 if (mParent != null && !mParent.isLayoutRequested()) { 21995 mParent.requestLayout(); 21996 } 21997 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 21998 mAttachInfo.mViewRequestingLayout = null; 21999 } 22000 } 22001 22002 /** 22003 * Forces this view to be laid out during the next layout pass. 22004 * This method does not call requestLayout() or forceLayout() 22005 * on the parent. 22006 */ 22007 public void forceLayout() { 22008 if (mMeasureCache != null) mMeasureCache.clear(); 22009 22010 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 22011 mPrivateFlags |= PFLAG_INVALIDATED; 22012 } 22013 22014 /** 22015 * <p> 22016 * This is called to find out how big a view should be. The parent 22017 * supplies constraint information in the width and height parameters. 22018 * </p> 22019 * 22020 * <p> 22021 * The actual measurement work of a view is performed in 22022 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 22023 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 22024 * </p> 22025 * 22026 * 22027 * @param widthMeasureSpec Horizontal space requirements as imposed by the 22028 * parent 22029 * @param heightMeasureSpec Vertical space requirements as imposed by the 22030 * parent 22031 * 22032 * @see #onMeasure(int, int) 22033 */ 22034 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 22035 boolean optical = isLayoutModeOptical(this); 22036 if (optical != isLayoutModeOptical(mParent)) { 22037 Insets insets = getOpticalInsets(); 22038 int oWidth = insets.left + insets.right; 22039 int oHeight = insets.top + insets.bottom; 22040 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 22041 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 22042 } 22043 22044 // Suppress sign extension for the low bytes 22045 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 22046 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 22047 22048 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 22049 22050 // Optimize layout by avoiding an extra EXACTLY pass when the view is 22051 // already measured as the correct size. In API 23 and below, this 22052 // extra pass is required to make LinearLayout re-distribute weight. 22053 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 22054 || heightMeasureSpec != mOldHeightMeasureSpec; 22055 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 22056 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 22057 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 22058 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 22059 final boolean needsLayout = specChanged 22060 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 22061 22062 if (forceLayout || needsLayout) { 22063 // first clears the measured dimension flag 22064 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 22065 22066 resolveRtlPropertiesIfNeeded(); 22067 22068 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 22069 if (cacheIndex < 0 || sIgnoreMeasureCache) { 22070 // measure ourselves, this should set the measured dimension flag back 22071 onMeasure(widthMeasureSpec, heightMeasureSpec); 22072 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22073 } else { 22074 long value = mMeasureCache.valueAt(cacheIndex); 22075 // Casting a long to int drops the high 32 bits, no mask needed 22076 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 22077 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22078 } 22079 22080 // flag not set, setMeasuredDimension() was not invoked, we raise 22081 // an exception to warn the developer 22082 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 22083 throw new IllegalStateException("View with id " + getId() + ": " 22084 + getClass().getName() + "#onMeasure() did not set the" 22085 + " measured dimension by calling" 22086 + " setMeasuredDimension()"); 22087 } 22088 22089 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 22090 } 22091 22092 mOldWidthMeasureSpec = widthMeasureSpec; 22093 mOldHeightMeasureSpec = heightMeasureSpec; 22094 22095 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 22096 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 22097 } 22098 22099 /** 22100 * <p> 22101 * Measure the view and its content to determine the measured width and the 22102 * measured height. This method is invoked by {@link #measure(int, int)} and 22103 * should be overridden by subclasses to provide accurate and efficient 22104 * measurement of their contents. 22105 * </p> 22106 * 22107 * <p> 22108 * <strong>CONTRACT:</strong> When overriding this method, you 22109 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 22110 * measured width and height of this view. Failure to do so will trigger an 22111 * <code>IllegalStateException</code>, thrown by 22112 * {@link #measure(int, int)}. Calling the superclass' 22113 * {@link #onMeasure(int, int)} is a valid use. 22114 * </p> 22115 * 22116 * <p> 22117 * The base class implementation of measure defaults to the background size, 22118 * unless a larger size is allowed by the MeasureSpec. Subclasses should 22119 * override {@link #onMeasure(int, int)} to provide better measurements of 22120 * their content. 22121 * </p> 22122 * 22123 * <p> 22124 * If this method is overridden, it is the subclass's responsibility to make 22125 * sure the measured height and width are at least the view's minimum height 22126 * and width ({@link #getSuggestedMinimumHeight()} and 22127 * {@link #getSuggestedMinimumWidth()}). 22128 * </p> 22129 * 22130 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 22131 * The requirements are encoded with 22132 * {@link android.view.View.MeasureSpec}. 22133 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 22134 * The requirements are encoded with 22135 * {@link android.view.View.MeasureSpec}. 22136 * 22137 * @see #getMeasuredWidth() 22138 * @see #getMeasuredHeight() 22139 * @see #setMeasuredDimension(int, int) 22140 * @see #getSuggestedMinimumHeight() 22141 * @see #getSuggestedMinimumWidth() 22142 * @see android.view.View.MeasureSpec#getMode(int) 22143 * @see android.view.View.MeasureSpec#getSize(int) 22144 */ 22145 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 22146 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 22147 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 22148 } 22149 22150 /** 22151 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 22152 * measured width and measured height. Failing to do so will trigger an 22153 * exception at measurement time.</p> 22154 * 22155 * @param measuredWidth The measured width of this view. May be a complex 22156 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22157 * {@link #MEASURED_STATE_TOO_SMALL}. 22158 * @param measuredHeight The measured height of this view. May be a complex 22159 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22160 * {@link #MEASURED_STATE_TOO_SMALL}. 22161 */ 22162 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 22163 boolean optical = isLayoutModeOptical(this); 22164 if (optical != isLayoutModeOptical(mParent)) { 22165 Insets insets = getOpticalInsets(); 22166 int opticalWidth = insets.left + insets.right; 22167 int opticalHeight = insets.top + insets.bottom; 22168 22169 measuredWidth += optical ? opticalWidth : -opticalWidth; 22170 measuredHeight += optical ? opticalHeight : -opticalHeight; 22171 } 22172 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 22173 } 22174 22175 /** 22176 * Sets the measured dimension without extra processing for things like optical bounds. 22177 * Useful for reapplying consistent values that have already been cooked with adjustments 22178 * for optical bounds, etc. such as those from the measurement cache. 22179 * 22180 * @param measuredWidth The measured width of this view. May be a complex 22181 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22182 * {@link #MEASURED_STATE_TOO_SMALL}. 22183 * @param measuredHeight The measured height of this view. May be a complex 22184 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 22185 * {@link #MEASURED_STATE_TOO_SMALL}. 22186 */ 22187 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 22188 mMeasuredWidth = measuredWidth; 22189 mMeasuredHeight = measuredHeight; 22190 22191 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 22192 } 22193 22194 /** 22195 * Merge two states as returned by {@link #getMeasuredState()}. 22196 * @param curState The current state as returned from a view or the result 22197 * of combining multiple views. 22198 * @param newState The new view state to combine. 22199 * @return Returns a new integer reflecting the combination of the two 22200 * states. 22201 */ 22202 public static int combineMeasuredStates(int curState, int newState) { 22203 return curState | newState; 22204 } 22205 22206 /** 22207 * Version of {@link #resolveSizeAndState(int, int, int)} 22208 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 22209 */ 22210 public static int resolveSize(int size, int measureSpec) { 22211 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 22212 } 22213 22214 /** 22215 * Utility to reconcile a desired size and state, with constraints imposed 22216 * by a MeasureSpec. Will take the desired size, unless a different size 22217 * is imposed by the constraints. The returned value is a compound integer, 22218 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 22219 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 22220 * resulting size is smaller than the size the view wants to be. 22221 * 22222 * @param size How big the view wants to be. 22223 * @param measureSpec Constraints imposed by the parent. 22224 * @param childMeasuredState Size information bit mask for the view's 22225 * children. 22226 * @return Size information bit mask as defined by 22227 * {@link #MEASURED_SIZE_MASK} and 22228 * {@link #MEASURED_STATE_TOO_SMALL}. 22229 */ 22230 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 22231 final int specMode = MeasureSpec.getMode(measureSpec); 22232 final int specSize = MeasureSpec.getSize(measureSpec); 22233 final int result; 22234 switch (specMode) { 22235 case MeasureSpec.AT_MOST: 22236 if (specSize < size) { 22237 result = specSize | MEASURED_STATE_TOO_SMALL; 22238 } else { 22239 result = size; 22240 } 22241 break; 22242 case MeasureSpec.EXACTLY: 22243 result = specSize; 22244 break; 22245 case MeasureSpec.UNSPECIFIED: 22246 default: 22247 result = size; 22248 } 22249 return result | (childMeasuredState & MEASURED_STATE_MASK); 22250 } 22251 22252 /** 22253 * Utility to return a default size. Uses the supplied size if the 22254 * MeasureSpec imposed no constraints. Will get larger if allowed 22255 * by the MeasureSpec. 22256 * 22257 * @param size Default size for this view 22258 * @param measureSpec Constraints imposed by the parent 22259 * @return The size this view should be. 22260 */ 22261 public static int getDefaultSize(int size, int measureSpec) { 22262 int result = size; 22263 int specMode = MeasureSpec.getMode(measureSpec); 22264 int specSize = MeasureSpec.getSize(measureSpec); 22265 22266 switch (specMode) { 22267 case MeasureSpec.UNSPECIFIED: 22268 result = size; 22269 break; 22270 case MeasureSpec.AT_MOST: 22271 case MeasureSpec.EXACTLY: 22272 result = specSize; 22273 break; 22274 } 22275 return result; 22276 } 22277 22278 /** 22279 * Returns the suggested minimum height that the view should use. This 22280 * returns the maximum of the view's minimum height 22281 * and the background's minimum height 22282 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 22283 * <p> 22284 * When being used in {@link #onMeasure(int, int)}, the caller should still 22285 * ensure the returned height is within the requirements of the parent. 22286 * 22287 * @return The suggested minimum height of the view. 22288 */ 22289 protected int getSuggestedMinimumHeight() { 22290 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 22291 22292 } 22293 22294 /** 22295 * Returns the suggested minimum width that the view should use. This 22296 * returns the maximum of the view's minimum width 22297 * and the background's minimum width 22298 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 22299 * <p> 22300 * When being used in {@link #onMeasure(int, int)}, the caller should still 22301 * ensure the returned width is within the requirements of the parent. 22302 * 22303 * @return The suggested minimum width of the view. 22304 */ 22305 protected int getSuggestedMinimumWidth() { 22306 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 22307 } 22308 22309 /** 22310 * Returns the minimum height of the view. 22311 * 22312 * @return the minimum height the view will try to be, in pixels 22313 * 22314 * @see #setMinimumHeight(int) 22315 * 22316 * @attr ref android.R.styleable#View_minHeight 22317 */ 22318 public int getMinimumHeight() { 22319 return mMinHeight; 22320 } 22321 22322 /** 22323 * Sets the minimum height of the view. It is not guaranteed the view will 22324 * be able to achieve this minimum height (for example, if its parent layout 22325 * constrains it with less available height). 22326 * 22327 * @param minHeight The minimum height the view will try to be, in pixels 22328 * 22329 * @see #getMinimumHeight() 22330 * 22331 * @attr ref android.R.styleable#View_minHeight 22332 */ 22333 @RemotableViewMethod 22334 public void setMinimumHeight(int minHeight) { 22335 mMinHeight = minHeight; 22336 requestLayout(); 22337 } 22338 22339 /** 22340 * Returns the minimum width of the view. 22341 * 22342 * @return the minimum width the view will try to be, in pixels 22343 * 22344 * @see #setMinimumWidth(int) 22345 * 22346 * @attr ref android.R.styleable#View_minWidth 22347 */ 22348 public int getMinimumWidth() { 22349 return mMinWidth; 22350 } 22351 22352 /** 22353 * Sets the minimum width of the view. It is not guaranteed the view will 22354 * be able to achieve this minimum width (for example, if its parent layout 22355 * constrains it with less available width). 22356 * 22357 * @param minWidth The minimum width the view will try to be, in pixels 22358 * 22359 * @see #getMinimumWidth() 22360 * 22361 * @attr ref android.R.styleable#View_minWidth 22362 */ 22363 public void setMinimumWidth(int minWidth) { 22364 mMinWidth = minWidth; 22365 requestLayout(); 22366 22367 } 22368 22369 /** 22370 * Get the animation currently associated with this view. 22371 * 22372 * @return The animation that is currently playing or 22373 * scheduled to play for this view. 22374 */ 22375 public Animation getAnimation() { 22376 return mCurrentAnimation; 22377 } 22378 22379 /** 22380 * Start the specified animation now. 22381 * 22382 * @param animation the animation to start now 22383 */ 22384 public void startAnimation(Animation animation) { 22385 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 22386 setAnimation(animation); 22387 invalidateParentCaches(); 22388 invalidate(true); 22389 } 22390 22391 /** 22392 * Cancels any animations for this view. 22393 */ 22394 public void clearAnimation() { 22395 if (mCurrentAnimation != null) { 22396 mCurrentAnimation.detach(); 22397 } 22398 mCurrentAnimation = null; 22399 invalidateParentIfNeeded(); 22400 } 22401 22402 /** 22403 * Sets the next animation to play for this view. 22404 * If you want the animation to play immediately, use 22405 * {@link #startAnimation(android.view.animation.Animation)} instead. 22406 * This method provides allows fine-grained 22407 * control over the start time and invalidation, but you 22408 * must make sure that 1) the animation has a start time set, and 22409 * 2) the view's parent (which controls animations on its children) 22410 * will be invalidated when the animation is supposed to 22411 * start. 22412 * 22413 * @param animation The next animation, or null. 22414 */ 22415 public void setAnimation(Animation animation) { 22416 mCurrentAnimation = animation; 22417 22418 if (animation != null) { 22419 // If the screen is off assume the animation start time is now instead of 22420 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 22421 // would cause the animation to start when the screen turns back on 22422 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 22423 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 22424 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 22425 } 22426 animation.reset(); 22427 } 22428 } 22429 22430 /** 22431 * Invoked by a parent ViewGroup to notify the start of the animation 22432 * currently associated with this view. If you override this method, 22433 * always call super.onAnimationStart(); 22434 * 22435 * @see #setAnimation(android.view.animation.Animation) 22436 * @see #getAnimation() 22437 */ 22438 @CallSuper 22439 protected void onAnimationStart() { 22440 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 22441 } 22442 22443 /** 22444 * Invoked by a parent ViewGroup to notify the end of the animation 22445 * currently associated with this view. If you override this method, 22446 * always call super.onAnimationEnd(); 22447 * 22448 * @see #setAnimation(android.view.animation.Animation) 22449 * @see #getAnimation() 22450 */ 22451 @CallSuper 22452 protected void onAnimationEnd() { 22453 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 22454 } 22455 22456 /** 22457 * Invoked if there is a Transform that involves alpha. Subclass that can 22458 * draw themselves with the specified alpha should return true, and then 22459 * respect that alpha when their onDraw() is called. If this returns false 22460 * then the view may be redirected to draw into an offscreen buffer to 22461 * fulfill the request, which will look fine, but may be slower than if the 22462 * subclass handles it internally. The default implementation returns false. 22463 * 22464 * @param alpha The alpha (0..255) to apply to the view's drawing 22465 * @return true if the view can draw with the specified alpha. 22466 */ 22467 protected boolean onSetAlpha(int alpha) { 22468 return false; 22469 } 22470 22471 /** 22472 * This is used by the RootView to perform an optimization when 22473 * the view hierarchy contains one or several SurfaceView. 22474 * SurfaceView is always considered transparent, but its children are not, 22475 * therefore all View objects remove themselves from the global transparent 22476 * region (passed as a parameter to this function). 22477 * 22478 * @param region The transparent region for this ViewAncestor (window). 22479 * 22480 * @return Returns true if the effective visibility of the view at this 22481 * point is opaque, regardless of the transparent region; returns false 22482 * if it is possible for underlying windows to be seen behind the view. 22483 * 22484 * {@hide} 22485 */ 22486 public boolean gatherTransparentRegion(Region region) { 22487 final AttachInfo attachInfo = mAttachInfo; 22488 if (region != null && attachInfo != null) { 22489 final int pflags = mPrivateFlags; 22490 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 22491 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 22492 // remove it from the transparent region. 22493 final int[] location = attachInfo.mTransparentLocation; 22494 getLocationInWindow(location); 22495 // When a view has Z value, then it will be better to leave some area below the view 22496 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 22497 // the bottom part needs more offset than the left, top and right parts due to the 22498 // spot light effects. 22499 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 22500 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 22501 location[0] + mRight - mLeft + shadowOffset, 22502 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 22503 } else { 22504 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 22505 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 22506 // the background drawable's non-transparent parts from this transparent region. 22507 applyDrawableToTransparentRegion(mBackground, region); 22508 } 22509 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 22510 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 22511 // Similarly, we remove the foreground drawable's non-transparent parts. 22512 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 22513 } 22514 if (mDefaultFocusHighlight != null 22515 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 22516 // Similarly, we remove the default focus highlight's non-transparent parts. 22517 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 22518 } 22519 } 22520 } 22521 return true; 22522 } 22523 22524 /** 22525 * Play a sound effect for this view. 22526 * 22527 * <p>The framework will play sound effects for some built in actions, such as 22528 * clicking, but you may wish to play these effects in your widget, 22529 * for instance, for internal navigation. 22530 * 22531 * <p>The sound effect will only be played if sound effects are enabled by the user, and 22532 * {@link #isSoundEffectsEnabled()} is true. 22533 * 22534 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 22535 */ 22536 public void playSoundEffect(int soundConstant) { 22537 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 22538 return; 22539 } 22540 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 22541 } 22542 22543 /** 22544 * BZZZTT!!1! 22545 * 22546 * <p>Provide haptic feedback to the user for this view. 22547 * 22548 * <p>The framework will provide haptic feedback for some built in actions, 22549 * such as long presses, but you may wish to provide feedback for your 22550 * own widget. 22551 * 22552 * <p>The feedback will only be performed if 22553 * {@link #isHapticFeedbackEnabled()} is true. 22554 * 22555 * @param feedbackConstant One of the constants defined in 22556 * {@link HapticFeedbackConstants} 22557 */ 22558 public boolean performHapticFeedback(int feedbackConstant) { 22559 return performHapticFeedback(feedbackConstant, 0); 22560 } 22561 22562 /** 22563 * BZZZTT!!1! 22564 * 22565 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 22566 * 22567 * @param feedbackConstant One of the constants defined in 22568 * {@link HapticFeedbackConstants} 22569 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 22570 */ 22571 public boolean performHapticFeedback(int feedbackConstant, int flags) { 22572 if (mAttachInfo == null) { 22573 return false; 22574 } 22575 //noinspection SimplifiableIfStatement 22576 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 22577 && !isHapticFeedbackEnabled()) { 22578 return false; 22579 } 22580 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 22581 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 22582 } 22583 22584 /** 22585 * Request that the visibility of the status bar or other screen/window 22586 * decorations be changed. 22587 * 22588 * <p>This method is used to put the over device UI into temporary modes 22589 * where the user's attention is focused more on the application content, 22590 * by dimming or hiding surrounding system affordances. This is typically 22591 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 22592 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 22593 * to be placed behind the action bar (and with these flags other system 22594 * affordances) so that smooth transitions between hiding and showing them 22595 * can be done. 22596 * 22597 * <p>Two representative examples of the use of system UI visibility is 22598 * implementing a content browsing application (like a magazine reader) 22599 * and a video playing application. 22600 * 22601 * <p>The first code shows a typical implementation of a View in a content 22602 * browsing application. In this implementation, the application goes 22603 * into a content-oriented mode by hiding the status bar and action bar, 22604 * and putting the navigation elements into lights out mode. The user can 22605 * then interact with content while in this mode. Such an application should 22606 * provide an easy way for the user to toggle out of the mode (such as to 22607 * check information in the status bar or access notifications). In the 22608 * implementation here, this is done simply by tapping on the content. 22609 * 22610 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 22611 * content} 22612 * 22613 * <p>This second code sample shows a typical implementation of a View 22614 * in a video playing application. In this situation, while the video is 22615 * playing the application would like to go into a complete full-screen mode, 22616 * to use as much of the display as possible for the video. When in this state 22617 * the user can not interact with the application; the system intercepts 22618 * touching on the screen to pop the UI out of full screen mode. See 22619 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 22620 * 22621 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 22622 * content} 22623 * 22624 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22625 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22626 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22627 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22628 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22629 */ 22630 public void setSystemUiVisibility(int visibility) { 22631 if (visibility != mSystemUiVisibility) { 22632 mSystemUiVisibility = visibility; 22633 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22634 mParent.recomputeViewAttributes(this); 22635 } 22636 } 22637 } 22638 22639 /** 22640 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 22641 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22642 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 22643 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 22644 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 22645 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 22646 */ 22647 public int getSystemUiVisibility() { 22648 return mSystemUiVisibility; 22649 } 22650 22651 /** 22652 * Returns the current system UI visibility that is currently set for 22653 * the entire window. This is the combination of the 22654 * {@link #setSystemUiVisibility(int)} values supplied by all of the 22655 * views in the window. 22656 */ 22657 public int getWindowSystemUiVisibility() { 22658 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 22659 } 22660 22661 /** 22662 * Override to find out when the window's requested system UI visibility 22663 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 22664 * This is different from the callbacks received through 22665 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 22666 * in that this is only telling you about the local request of the window, 22667 * not the actual values applied by the system. 22668 */ 22669 public void onWindowSystemUiVisibilityChanged(int visible) { 22670 } 22671 22672 /** 22673 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 22674 * the view hierarchy. 22675 */ 22676 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 22677 onWindowSystemUiVisibilityChanged(visible); 22678 } 22679 22680 /** 22681 * Set a listener to receive callbacks when the visibility of the system bar changes. 22682 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 22683 */ 22684 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 22685 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 22686 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 22687 mParent.recomputeViewAttributes(this); 22688 } 22689 } 22690 22691 /** 22692 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 22693 * the view hierarchy. 22694 */ 22695 public void dispatchSystemUiVisibilityChanged(int visibility) { 22696 ListenerInfo li = mListenerInfo; 22697 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 22698 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 22699 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 22700 } 22701 } 22702 22703 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 22704 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 22705 if (val != mSystemUiVisibility) { 22706 setSystemUiVisibility(val); 22707 return true; 22708 } 22709 return false; 22710 } 22711 22712 /** @hide */ 22713 public void setDisabledSystemUiVisibility(int flags) { 22714 if (mAttachInfo != null) { 22715 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 22716 mAttachInfo.mDisabledSystemUiVisibility = flags; 22717 if (mParent != null) { 22718 mParent.recomputeViewAttributes(this); 22719 } 22720 } 22721 } 22722 } 22723 22724 /** 22725 * Creates an image that the system displays during the drag and drop 22726 * operation. This is called a "drag shadow". The default implementation 22727 * for a DragShadowBuilder based on a View returns an image that has exactly the same 22728 * appearance as the given View. The default also positions the center of the drag shadow 22729 * directly under the touch point. If no View is provided (the constructor with no parameters 22730 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 22731 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 22732 * default is an invisible drag shadow. 22733 * <p> 22734 * You are not required to use the View you provide to the constructor as the basis of the 22735 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 22736 * anything you want as the drag shadow. 22737 * </p> 22738 * <p> 22739 * You pass a DragShadowBuilder object to the system when you start the drag. The system 22740 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 22741 * size and position of the drag shadow. It uses this data to construct a 22742 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 22743 * so that your application can draw the shadow image in the Canvas. 22744 * </p> 22745 * 22746 * <div class="special reference"> 22747 * <h3>Developer Guides</h3> 22748 * <p>For a guide to implementing drag and drop features, read the 22749 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 22750 * </div> 22751 */ 22752 public static class DragShadowBuilder { 22753 private final WeakReference<View> mView; 22754 22755 /** 22756 * Constructs a shadow image builder based on a View. By default, the resulting drag 22757 * shadow will have the same appearance and dimensions as the View, with the touch point 22758 * over the center of the View. 22759 * @param view A View. Any View in scope can be used. 22760 */ 22761 public DragShadowBuilder(View view) { 22762 mView = new WeakReference<View>(view); 22763 } 22764 22765 /** 22766 * Construct a shadow builder object with no associated View. This 22767 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 22768 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 22769 * to supply the drag shadow's dimensions and appearance without 22770 * reference to any View object. If they are not overridden, then the result is an 22771 * invisible drag shadow. 22772 */ 22773 public DragShadowBuilder() { 22774 mView = new WeakReference<View>(null); 22775 } 22776 22777 /** 22778 * Returns the View object that had been passed to the 22779 * {@link #View.DragShadowBuilder(View)} 22780 * constructor. If that View parameter was {@code null} or if the 22781 * {@link #View.DragShadowBuilder()} 22782 * constructor was used to instantiate the builder object, this method will return 22783 * null. 22784 * 22785 * @return The View object associate with this builder object. 22786 */ 22787 @SuppressWarnings({"JavadocReference"}) 22788 final public View getView() { 22789 return mView.get(); 22790 } 22791 22792 /** 22793 * Provides the metrics for the shadow image. These include the dimensions of 22794 * the shadow image, and the point within that shadow that should 22795 * be centered under the touch location while dragging. 22796 * <p> 22797 * The default implementation sets the dimensions of the shadow to be the 22798 * same as the dimensions of the View itself and centers the shadow under 22799 * the touch point. 22800 * </p> 22801 * 22802 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 22803 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 22804 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 22805 * image. 22806 * 22807 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 22808 * shadow image that should be underneath the touch point during the drag and drop 22809 * operation. Your application must set {@link android.graphics.Point#x} to the 22810 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 22811 */ 22812 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 22813 final View view = mView.get(); 22814 if (view != null) { 22815 outShadowSize.set(view.getWidth(), view.getHeight()); 22816 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 22817 } else { 22818 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 22819 } 22820 } 22821 22822 /** 22823 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 22824 * based on the dimensions it received from the 22825 * {@link #onProvideShadowMetrics(Point, Point)} callback. 22826 * 22827 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 22828 */ 22829 public void onDrawShadow(Canvas canvas) { 22830 final View view = mView.get(); 22831 if (view != null) { 22832 view.draw(canvas); 22833 } else { 22834 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 22835 } 22836 } 22837 } 22838 22839 /** 22840 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 22841 * startDragAndDrop()} for newer platform versions. 22842 */ 22843 @Deprecated 22844 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 22845 Object myLocalState, int flags) { 22846 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 22847 } 22848 22849 /** 22850 * Starts a drag and drop operation. When your application calls this method, it passes a 22851 * {@link android.view.View.DragShadowBuilder} object to the system. The 22852 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 22853 * to get metrics for the drag shadow, and then calls the object's 22854 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 22855 * <p> 22856 * Once the system has the drag shadow, it begins the drag and drop operation by sending 22857 * drag events to all the View objects in your application that are currently visible. It does 22858 * this either by calling the View object's drag listener (an implementation of 22859 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 22860 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 22861 * Both are passed a {@link android.view.DragEvent} object that has a 22862 * {@link android.view.DragEvent#getAction()} value of 22863 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 22864 * </p> 22865 * <p> 22866 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 22867 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 22868 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 22869 * to the View the user selected for dragging. 22870 * </p> 22871 * @param data A {@link android.content.ClipData} object pointing to the data to be 22872 * transferred by the drag and drop operation. 22873 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 22874 * drag shadow. 22875 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 22876 * drop operation. When dispatching drag events to views in the same activity this object 22877 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 22878 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 22879 * will return null). 22880 * <p> 22881 * myLocalState is a lightweight mechanism for the sending information from the dragged View 22882 * to the target Views. For example, it can contain flags that differentiate between a 22883 * a copy operation and a move operation. 22884 * </p> 22885 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 22886 * flags, or any combination of the following: 22887 * <ul> 22888 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 22889 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 22890 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 22891 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 22892 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 22893 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 22894 * </ul> 22895 * @return {@code true} if the method completes successfully, or 22896 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 22897 * do a drag, and so no drag operation is in progress. 22898 */ 22899 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 22900 Object myLocalState, int flags) { 22901 if (ViewDebug.DEBUG_DRAG) { 22902 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 22903 } 22904 if (mAttachInfo == null) { 22905 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 22906 return false; 22907 } 22908 22909 if (data != null) { 22910 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 22911 } 22912 22913 boolean okay = false; 22914 22915 Point shadowSize = new Point(); 22916 Point shadowTouchPoint = new Point(); 22917 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 22918 22919 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 22920 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 22921 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 22922 } 22923 22924 if (ViewDebug.DEBUG_DRAG) { 22925 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 22926 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 22927 } 22928 if (mAttachInfo.mDragSurface != null) { 22929 mAttachInfo.mDragSurface.release(); 22930 } 22931 mAttachInfo.mDragSurface = new Surface(); 22932 try { 22933 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 22934 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 22935 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 22936 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 22937 if (mAttachInfo.mDragToken != null) { 22938 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 22939 try { 22940 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 22941 shadowBuilder.onDrawShadow(canvas); 22942 } finally { 22943 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 22944 } 22945 22946 final ViewRootImpl root = getViewRootImpl(); 22947 22948 // Cache the local state object for delivery with DragEvents 22949 root.setLocalDragState(myLocalState); 22950 22951 // repurpose 'shadowSize' for the last touch point 22952 root.getLastTouchPoint(shadowSize); 22953 22954 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 22955 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 22956 shadowTouchPoint.x, shadowTouchPoint.y, data); 22957 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 22958 } 22959 } catch (Exception e) { 22960 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 22961 mAttachInfo.mDragSurface.destroy(); 22962 mAttachInfo.mDragSurface = null; 22963 } 22964 22965 return okay; 22966 } 22967 22968 /** 22969 * Cancels an ongoing drag and drop operation. 22970 * <p> 22971 * A {@link android.view.DragEvent} object with 22972 * {@link android.view.DragEvent#getAction()} value of 22973 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 22974 * {@link android.view.DragEvent#getResult()} value of {@code false} 22975 * will be sent to every 22976 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 22977 * even if they are not currently visible. 22978 * </p> 22979 * <p> 22980 * This method can be called on any View in the same window as the View on which 22981 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 22982 * was called. 22983 * </p> 22984 */ 22985 public final void cancelDragAndDrop() { 22986 if (ViewDebug.DEBUG_DRAG) { 22987 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 22988 } 22989 if (mAttachInfo == null) { 22990 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 22991 return; 22992 } 22993 if (mAttachInfo.mDragToken != null) { 22994 try { 22995 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 22996 } catch (Exception e) { 22997 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 22998 } 22999 mAttachInfo.mDragToken = null; 23000 } else { 23001 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 23002 } 23003 } 23004 23005 /** 23006 * Updates the drag shadow for the ongoing drag and drop operation. 23007 * 23008 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 23009 * new drag shadow. 23010 */ 23011 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 23012 if (ViewDebug.DEBUG_DRAG) { 23013 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 23014 } 23015 if (mAttachInfo == null) { 23016 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 23017 return; 23018 } 23019 if (mAttachInfo.mDragToken != null) { 23020 try { 23021 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 23022 try { 23023 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 23024 shadowBuilder.onDrawShadow(canvas); 23025 } finally { 23026 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 23027 } 23028 } catch (Exception e) { 23029 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 23030 } 23031 } else { 23032 Log.e(VIEW_LOG_TAG, "No active drag"); 23033 } 23034 } 23035 23036 /** 23037 * Starts a move from {startX, startY}, the amount of the movement will be the offset 23038 * between {startX, startY} and the new cursor positon. 23039 * @param startX horizontal coordinate where the move started. 23040 * @param startY vertical coordinate where the move started. 23041 * @return whether moving was started successfully. 23042 * @hide 23043 */ 23044 public final boolean startMovingTask(float startX, float startY) { 23045 if (ViewDebug.DEBUG_POSITIONING) { 23046 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 23047 } 23048 try { 23049 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 23050 } catch (RemoteException e) { 23051 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 23052 } 23053 return false; 23054 } 23055 23056 /** 23057 * Handles drag events sent by the system following a call to 23058 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 23059 * startDragAndDrop()}. 23060 *<p> 23061 * When the system calls this method, it passes a 23062 * {@link android.view.DragEvent} object. A call to 23063 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 23064 * in DragEvent. The method uses these to determine what is happening in the drag and drop 23065 * operation. 23066 * @param event The {@link android.view.DragEvent} sent by the system. 23067 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 23068 * in DragEvent, indicating the type of drag event represented by this object. 23069 * @return {@code true} if the method was successful, otherwise {@code false}. 23070 * <p> 23071 * The method should return {@code true} in response to an action type of 23072 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 23073 * operation. 23074 * </p> 23075 * <p> 23076 * The method should also return {@code true} in response to an action type of 23077 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 23078 * {@code false} if it didn't. 23079 * </p> 23080 * <p> 23081 * For all other events, the return value is ignored. 23082 * </p> 23083 */ 23084 public boolean onDragEvent(DragEvent event) { 23085 return false; 23086 } 23087 23088 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. 23089 boolean dispatchDragEnterExitInPreN(DragEvent event) { 23090 return callDragEventHandler(event); 23091 } 23092 23093 /** 23094 * Detects if this View is enabled and has a drag event listener. 23095 * If both are true, then it calls the drag event listener with the 23096 * {@link android.view.DragEvent} it received. If the drag event listener returns 23097 * {@code true}, then dispatchDragEvent() returns {@code true}. 23098 * <p> 23099 * For all other cases, the method calls the 23100 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 23101 * method and returns its result. 23102 * </p> 23103 * <p> 23104 * This ensures that a drag event is always consumed, even if the View does not have a drag 23105 * event listener. However, if the View has a listener and the listener returns true, then 23106 * onDragEvent() is not called. 23107 * </p> 23108 */ 23109 public boolean dispatchDragEvent(DragEvent event) { 23110 event.mEventHandlerWasCalled = true; 23111 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 23112 event.mAction == DragEvent.ACTION_DROP) { 23113 // About to deliver an event with coordinates to this view. Notify that now this view 23114 // has drag focus. This will send exit/enter events as needed. 23115 getViewRootImpl().setDragFocus(this, event); 23116 } 23117 return callDragEventHandler(event); 23118 } 23119 23120 final boolean callDragEventHandler(DragEvent event) { 23121 final boolean result; 23122 23123 ListenerInfo li = mListenerInfo; 23124 //noinspection SimplifiableIfStatement 23125 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 23126 && li.mOnDragListener.onDrag(this, event)) { 23127 result = true; 23128 } else { 23129 result = onDragEvent(event); 23130 } 23131 23132 switch (event.mAction) { 23133 case DragEvent.ACTION_DRAG_ENTERED: { 23134 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 23135 refreshDrawableState(); 23136 } break; 23137 case DragEvent.ACTION_DRAG_EXITED: { 23138 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 23139 refreshDrawableState(); 23140 } break; 23141 case DragEvent.ACTION_DRAG_ENDED: { 23142 mPrivateFlags2 &= ~View.DRAG_MASK; 23143 refreshDrawableState(); 23144 } break; 23145 } 23146 23147 return result; 23148 } 23149 23150 boolean canAcceptDrag() { 23151 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 23152 } 23153 23154 /** 23155 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 23156 * it is ever exposed at all. 23157 * @hide 23158 */ 23159 public void onCloseSystemDialogs(String reason) { 23160 } 23161 23162 /** 23163 * Given a Drawable whose bounds have been set to draw into this view, 23164 * update a Region being computed for 23165 * {@link #gatherTransparentRegion(android.graphics.Region)} so 23166 * that any non-transparent parts of the Drawable are removed from the 23167 * given transparent region. 23168 * 23169 * @param dr The Drawable whose transparency is to be applied to the region. 23170 * @param region A Region holding the current transparency information, 23171 * where any parts of the region that are set are considered to be 23172 * transparent. On return, this region will be modified to have the 23173 * transparency information reduced by the corresponding parts of the 23174 * Drawable that are not transparent. 23175 * {@hide} 23176 */ 23177 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 23178 if (DBG) { 23179 Log.i("View", "Getting transparent region for: " + this); 23180 } 23181 final Region r = dr.getTransparentRegion(); 23182 final Rect db = dr.getBounds(); 23183 final AttachInfo attachInfo = mAttachInfo; 23184 if (r != null && attachInfo != null) { 23185 final int w = getRight()-getLeft(); 23186 final int h = getBottom()-getTop(); 23187 if (db.left > 0) { 23188 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 23189 r.op(0, 0, db.left, h, Region.Op.UNION); 23190 } 23191 if (db.right < w) { 23192 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 23193 r.op(db.right, 0, w, h, Region.Op.UNION); 23194 } 23195 if (db.top > 0) { 23196 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 23197 r.op(0, 0, w, db.top, Region.Op.UNION); 23198 } 23199 if (db.bottom < h) { 23200 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 23201 r.op(0, db.bottom, w, h, Region.Op.UNION); 23202 } 23203 final int[] location = attachInfo.mTransparentLocation; 23204 getLocationInWindow(location); 23205 r.translate(location[0], location[1]); 23206 region.op(r, Region.Op.INTERSECT); 23207 } else { 23208 region.op(db, Region.Op.DIFFERENCE); 23209 } 23210 } 23211 23212 private void checkForLongClick(int delayOffset, float x, float y) { 23213 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 23214 mHasPerformedLongPress = false; 23215 23216 if (mPendingCheckForLongPress == null) { 23217 mPendingCheckForLongPress = new CheckForLongPress(); 23218 } 23219 mPendingCheckForLongPress.setAnchor(x, y); 23220 mPendingCheckForLongPress.rememberWindowAttachCount(); 23221 mPendingCheckForLongPress.rememberPressedState(); 23222 postDelayed(mPendingCheckForLongPress, 23223 ViewConfiguration.getLongPressTimeout() - delayOffset); 23224 } 23225 } 23226 23227 /** 23228 * Inflate a view from an XML resource. This convenience method wraps the {@link 23229 * LayoutInflater} class, which provides a full range of options for view inflation. 23230 * 23231 * @param context The Context object for your activity or application. 23232 * @param resource The resource ID to inflate 23233 * @param root A view group that will be the parent. Used to properly inflate the 23234 * layout_* parameters. 23235 * @see LayoutInflater 23236 */ 23237 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 23238 LayoutInflater factory = LayoutInflater.from(context); 23239 return factory.inflate(resource, root); 23240 } 23241 23242 /** 23243 * Scroll the view with standard behavior for scrolling beyond the normal 23244 * content boundaries. Views that call this method should override 23245 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 23246 * results of an over-scroll operation. 23247 * 23248 * Views can use this method to handle any touch or fling-based scrolling. 23249 * 23250 * @param deltaX Change in X in pixels 23251 * @param deltaY Change in Y in pixels 23252 * @param scrollX Current X scroll value in pixels before applying deltaX 23253 * @param scrollY Current Y scroll value in pixels before applying deltaY 23254 * @param scrollRangeX Maximum content scroll range along the X axis 23255 * @param scrollRangeY Maximum content scroll range along the Y axis 23256 * @param maxOverScrollX Number of pixels to overscroll by in either direction 23257 * along the X axis. 23258 * @param maxOverScrollY Number of pixels to overscroll by in either direction 23259 * along the Y axis. 23260 * @param isTouchEvent true if this scroll operation is the result of a touch event. 23261 * @return true if scrolling was clamped to an over-scroll boundary along either 23262 * axis, false otherwise. 23263 */ 23264 @SuppressWarnings({"UnusedParameters"}) 23265 protected boolean overScrollBy(int deltaX, int deltaY, 23266 int scrollX, int scrollY, 23267 int scrollRangeX, int scrollRangeY, 23268 int maxOverScrollX, int maxOverScrollY, 23269 boolean isTouchEvent) { 23270 final int overScrollMode = mOverScrollMode; 23271 final boolean canScrollHorizontal = 23272 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 23273 final boolean canScrollVertical = 23274 computeVerticalScrollRange() > computeVerticalScrollExtent(); 23275 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 23276 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 23277 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 23278 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 23279 23280 int newScrollX = scrollX + deltaX; 23281 if (!overScrollHorizontal) { 23282 maxOverScrollX = 0; 23283 } 23284 23285 int newScrollY = scrollY + deltaY; 23286 if (!overScrollVertical) { 23287 maxOverScrollY = 0; 23288 } 23289 23290 // Clamp values if at the limits and record 23291 final int left = -maxOverScrollX; 23292 final int right = maxOverScrollX + scrollRangeX; 23293 final int top = -maxOverScrollY; 23294 final int bottom = maxOverScrollY + scrollRangeY; 23295 23296 boolean clampedX = false; 23297 if (newScrollX > right) { 23298 newScrollX = right; 23299 clampedX = true; 23300 } else if (newScrollX < left) { 23301 newScrollX = left; 23302 clampedX = true; 23303 } 23304 23305 boolean clampedY = false; 23306 if (newScrollY > bottom) { 23307 newScrollY = bottom; 23308 clampedY = true; 23309 } else if (newScrollY < top) { 23310 newScrollY = top; 23311 clampedY = true; 23312 } 23313 23314 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 23315 23316 return clampedX || clampedY; 23317 } 23318 23319 /** 23320 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 23321 * respond to the results of an over-scroll operation. 23322 * 23323 * @param scrollX New X scroll value in pixels 23324 * @param scrollY New Y scroll value in pixels 23325 * @param clampedX True if scrollX was clamped to an over-scroll boundary 23326 * @param clampedY True if scrollY was clamped to an over-scroll boundary 23327 */ 23328 protected void onOverScrolled(int scrollX, int scrollY, 23329 boolean clampedX, boolean clampedY) { 23330 // Intentionally empty. 23331 } 23332 23333 /** 23334 * Returns the over-scroll mode for this view. The result will be 23335 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23336 * (allow over-scrolling only if the view content is larger than the container), 23337 * or {@link #OVER_SCROLL_NEVER}. 23338 * 23339 * @return This view's over-scroll mode. 23340 */ 23341 public int getOverScrollMode() { 23342 return mOverScrollMode; 23343 } 23344 23345 /** 23346 * Set the over-scroll mode for this view. Valid over-scroll modes are 23347 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 23348 * (allow over-scrolling only if the view content is larger than the container), 23349 * or {@link #OVER_SCROLL_NEVER}. 23350 * 23351 * Setting the over-scroll mode of a view will have an effect only if the 23352 * view is capable of scrolling. 23353 * 23354 * @param overScrollMode The new over-scroll mode for this view. 23355 */ 23356 public void setOverScrollMode(int overScrollMode) { 23357 if (overScrollMode != OVER_SCROLL_ALWAYS && 23358 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 23359 overScrollMode != OVER_SCROLL_NEVER) { 23360 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 23361 } 23362 mOverScrollMode = overScrollMode; 23363 } 23364 23365 /** 23366 * Enable or disable nested scrolling for this view. 23367 * 23368 * <p>If this property is set to true the view will be permitted to initiate nested 23369 * scrolling operations with a compatible parent view in the current hierarchy. If this 23370 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 23371 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 23372 * the nested scroll.</p> 23373 * 23374 * @param enabled true to enable nested scrolling, false to disable 23375 * 23376 * @see #isNestedScrollingEnabled() 23377 */ 23378 public void setNestedScrollingEnabled(boolean enabled) { 23379 if (enabled) { 23380 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 23381 } else { 23382 stopNestedScroll(); 23383 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 23384 } 23385 } 23386 23387 /** 23388 * Returns true if nested scrolling is enabled for this view. 23389 * 23390 * <p>If nested scrolling is enabled and this View class implementation supports it, 23391 * this view will act as a nested scrolling child view when applicable, forwarding data 23392 * about the scroll operation in progress to a compatible and cooperating nested scrolling 23393 * parent.</p> 23394 * 23395 * @return true if nested scrolling is enabled 23396 * 23397 * @see #setNestedScrollingEnabled(boolean) 23398 */ 23399 public boolean isNestedScrollingEnabled() { 23400 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 23401 PFLAG3_NESTED_SCROLLING_ENABLED; 23402 } 23403 23404 /** 23405 * Begin a nestable scroll operation along the given axes. 23406 * 23407 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 23408 * 23409 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 23410 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 23411 * In the case of touch scrolling the nested scroll will be terminated automatically in 23412 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 23413 * In the event of programmatic scrolling the caller must explicitly call 23414 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 23415 * 23416 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 23417 * If it returns false the caller may ignore the rest of this contract until the next scroll. 23418 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 23419 * 23420 * <p>At each incremental step of the scroll the caller should invoke 23421 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 23422 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 23423 * parent at least partially consumed the scroll and the caller should adjust the amount it 23424 * scrolls by.</p> 23425 * 23426 * <p>After applying the remainder of the scroll delta the caller should invoke 23427 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 23428 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 23429 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 23430 * </p> 23431 * 23432 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 23433 * {@link #SCROLL_AXIS_VERTICAL}. 23434 * @return true if a cooperative parent was found and nested scrolling has been enabled for 23435 * the current gesture. 23436 * 23437 * @see #stopNestedScroll() 23438 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23439 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23440 */ 23441 public boolean startNestedScroll(int axes) { 23442 if (hasNestedScrollingParent()) { 23443 // Already in progress 23444 return true; 23445 } 23446 if (isNestedScrollingEnabled()) { 23447 ViewParent p = getParent(); 23448 View child = this; 23449 while (p != null) { 23450 try { 23451 if (p.onStartNestedScroll(child, this, axes)) { 23452 mNestedScrollingParent = p; 23453 p.onNestedScrollAccepted(child, this, axes); 23454 return true; 23455 } 23456 } catch (AbstractMethodError e) { 23457 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 23458 "method onStartNestedScroll", e); 23459 // Allow the search upward to continue 23460 } 23461 if (p instanceof View) { 23462 child = (View) p; 23463 } 23464 p = p.getParent(); 23465 } 23466 } 23467 return false; 23468 } 23469 23470 /** 23471 * Stop a nested scroll in progress. 23472 * 23473 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 23474 * 23475 * @see #startNestedScroll(int) 23476 */ 23477 public void stopNestedScroll() { 23478 if (mNestedScrollingParent != null) { 23479 mNestedScrollingParent.onStopNestedScroll(this); 23480 mNestedScrollingParent = null; 23481 } 23482 } 23483 23484 /** 23485 * Returns true if this view has a nested scrolling parent. 23486 * 23487 * <p>The presence of a nested scrolling parent indicates that this view has initiated 23488 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 23489 * 23490 * @return whether this view has a nested scrolling parent 23491 */ 23492 public boolean hasNestedScrollingParent() { 23493 return mNestedScrollingParent != null; 23494 } 23495 23496 /** 23497 * Dispatch one step of a nested scroll in progress. 23498 * 23499 * <p>Implementations of views that support nested scrolling should call this to report 23500 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 23501 * is not currently in progress or nested scrolling is not 23502 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 23503 * 23504 * <p>Compatible View implementations should also call 23505 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 23506 * consuming a component of the scroll event themselves.</p> 23507 * 23508 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 23509 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 23510 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 23511 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 23512 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23513 * in local view coordinates of this view from before this operation 23514 * to after it completes. View implementations may use this to adjust 23515 * expected input coordinate tracking. 23516 * @return true if the event was dispatched, false if it could not be dispatched. 23517 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 23518 */ 23519 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 23520 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 23521 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23522 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 23523 int startX = 0; 23524 int startY = 0; 23525 if (offsetInWindow != null) { 23526 getLocationInWindow(offsetInWindow); 23527 startX = offsetInWindow[0]; 23528 startY = offsetInWindow[1]; 23529 } 23530 23531 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 23532 dxUnconsumed, dyUnconsumed); 23533 23534 if (offsetInWindow != null) { 23535 getLocationInWindow(offsetInWindow); 23536 offsetInWindow[0] -= startX; 23537 offsetInWindow[1] -= startY; 23538 } 23539 return true; 23540 } else if (offsetInWindow != null) { 23541 // No motion, no dispatch. Keep offsetInWindow up to date. 23542 offsetInWindow[0] = 0; 23543 offsetInWindow[1] = 0; 23544 } 23545 } 23546 return false; 23547 } 23548 23549 /** 23550 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 23551 * 23552 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 23553 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 23554 * scrolling operation to consume some or all of the scroll operation before the child view 23555 * consumes it.</p> 23556 * 23557 * @param dx Horizontal scroll distance in pixels 23558 * @param dy Vertical scroll distance in pixels 23559 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 23560 * and consumed[1] the consumed dy. 23561 * @param offsetInWindow Optional. If not null, on return this will contain the offset 23562 * in local view coordinates of this view from before this operation 23563 * to after it completes. View implementations may use this to adjust 23564 * expected input coordinate tracking. 23565 * @return true if the parent consumed some or all of the scroll delta 23566 * @see #dispatchNestedScroll(int, int, int, int, int[]) 23567 */ 23568 public boolean dispatchNestedPreScroll(int dx, int dy, 23569 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 23570 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23571 if (dx != 0 || dy != 0) { 23572 int startX = 0; 23573 int startY = 0; 23574 if (offsetInWindow != null) { 23575 getLocationInWindow(offsetInWindow); 23576 startX = offsetInWindow[0]; 23577 startY = offsetInWindow[1]; 23578 } 23579 23580 if (consumed == null) { 23581 if (mTempNestedScrollConsumed == null) { 23582 mTempNestedScrollConsumed = new int[2]; 23583 } 23584 consumed = mTempNestedScrollConsumed; 23585 } 23586 consumed[0] = 0; 23587 consumed[1] = 0; 23588 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 23589 23590 if (offsetInWindow != null) { 23591 getLocationInWindow(offsetInWindow); 23592 offsetInWindow[0] -= startX; 23593 offsetInWindow[1] -= startY; 23594 } 23595 return consumed[0] != 0 || consumed[1] != 0; 23596 } else if (offsetInWindow != null) { 23597 offsetInWindow[0] = 0; 23598 offsetInWindow[1] = 0; 23599 } 23600 } 23601 return false; 23602 } 23603 23604 /** 23605 * Dispatch a fling to a nested scrolling parent. 23606 * 23607 * <p>This method should be used to indicate that a nested scrolling child has detected 23608 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 23609 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 23610 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 23611 * along a scrollable axis.</p> 23612 * 23613 * <p>If a nested scrolling child view would normally fling but it is at the edge of 23614 * its own content, it can use this method to delegate the fling to its nested scrolling 23615 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 23616 * 23617 * @param velocityX Horizontal fling velocity in pixels per second 23618 * @param velocityY Vertical fling velocity in pixels per second 23619 * @param consumed true if the child consumed the fling, false otherwise 23620 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 23621 */ 23622 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 23623 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23624 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 23625 } 23626 return false; 23627 } 23628 23629 /** 23630 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 23631 * 23632 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 23633 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 23634 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 23635 * before the child view consumes it. If this method returns <code>true</code>, a nested 23636 * parent view consumed the fling and this view should not scroll as a result.</p> 23637 * 23638 * <p>For a better user experience, only one view in a nested scrolling chain should consume 23639 * the fling at a time. If a parent view consumed the fling this method will return false. 23640 * Custom view implementations should account for this in two ways:</p> 23641 * 23642 * <ul> 23643 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 23644 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 23645 * position regardless.</li> 23646 * <li>If a nested parent does consume the fling, this view should not scroll at all, 23647 * even to settle back to a valid idle position.</li> 23648 * </ul> 23649 * 23650 * <p>Views should also not offer fling velocities to nested parent views along an axis 23651 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 23652 * should not offer a horizontal fling velocity to its parents since scrolling along that 23653 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 23654 * 23655 * @param velocityX Horizontal fling velocity in pixels per second 23656 * @param velocityY Vertical fling velocity in pixels per second 23657 * @return true if a nested scrolling parent consumed the fling 23658 */ 23659 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 23660 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 23661 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 23662 } 23663 return false; 23664 } 23665 23666 /** 23667 * Gets a scale factor that determines the distance the view should scroll 23668 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 23669 * @return The vertical scroll scale factor. 23670 * @hide 23671 */ 23672 protected float getVerticalScrollFactor() { 23673 if (mVerticalScrollFactor == 0) { 23674 TypedValue outValue = new TypedValue(); 23675 if (!mContext.getTheme().resolveAttribute( 23676 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 23677 throw new IllegalStateException( 23678 "Expected theme to define listPreferredItemHeight."); 23679 } 23680 mVerticalScrollFactor = outValue.getDimension( 23681 mContext.getResources().getDisplayMetrics()); 23682 } 23683 return mVerticalScrollFactor; 23684 } 23685 23686 /** 23687 * Gets a scale factor that determines the distance the view should scroll 23688 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 23689 * @return The horizontal scroll scale factor. 23690 * @hide 23691 */ 23692 protected float getHorizontalScrollFactor() { 23693 // TODO: Should use something else. 23694 return getVerticalScrollFactor(); 23695 } 23696 23697 /** 23698 * Return the value specifying the text direction or policy that was set with 23699 * {@link #setTextDirection(int)}. 23700 * 23701 * @return the defined text direction. It can be one of: 23702 * 23703 * {@link #TEXT_DIRECTION_INHERIT}, 23704 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23705 * {@link #TEXT_DIRECTION_ANY_RTL}, 23706 * {@link #TEXT_DIRECTION_LTR}, 23707 * {@link #TEXT_DIRECTION_RTL}, 23708 * {@link #TEXT_DIRECTION_LOCALE}, 23709 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23710 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23711 * 23712 * @attr ref android.R.styleable#View_textDirection 23713 * 23714 * @hide 23715 */ 23716 @ViewDebug.ExportedProperty(category = "text", mapping = { 23717 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23718 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23719 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23720 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23721 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23722 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23723 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23724 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23725 }) 23726 public int getRawTextDirection() { 23727 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 23728 } 23729 23730 /** 23731 * Set the text direction. 23732 * 23733 * @param textDirection the direction to set. Should be one of: 23734 * 23735 * {@link #TEXT_DIRECTION_INHERIT}, 23736 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23737 * {@link #TEXT_DIRECTION_ANY_RTL}, 23738 * {@link #TEXT_DIRECTION_LTR}, 23739 * {@link #TEXT_DIRECTION_RTL}, 23740 * {@link #TEXT_DIRECTION_LOCALE} 23741 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23742 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 23743 * 23744 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 23745 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 23746 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 23747 * 23748 * @attr ref android.R.styleable#View_textDirection 23749 */ 23750 public void setTextDirection(int textDirection) { 23751 if (getRawTextDirection() != textDirection) { 23752 // Reset the current text direction and the resolved one 23753 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 23754 resetResolvedTextDirection(); 23755 // Set the new text direction 23756 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 23757 // Do resolution 23758 resolveTextDirection(); 23759 // Notify change 23760 onRtlPropertiesChanged(getLayoutDirection()); 23761 // Refresh 23762 requestLayout(); 23763 invalidate(true); 23764 } 23765 } 23766 23767 /** 23768 * Return the resolved text direction. 23769 * 23770 * @return the resolved text direction. Returns one of: 23771 * 23772 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 23773 * {@link #TEXT_DIRECTION_ANY_RTL}, 23774 * {@link #TEXT_DIRECTION_LTR}, 23775 * {@link #TEXT_DIRECTION_RTL}, 23776 * {@link #TEXT_DIRECTION_LOCALE}, 23777 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 23778 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 23779 * 23780 * @attr ref android.R.styleable#View_textDirection 23781 */ 23782 @ViewDebug.ExportedProperty(category = "text", mapping = { 23783 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 23784 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 23785 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 23786 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 23787 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 23788 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 23789 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 23790 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 23791 }) 23792 public int getTextDirection() { 23793 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 23794 } 23795 23796 /** 23797 * Resolve the text direction. 23798 * 23799 * @return true if resolution has been done, false otherwise. 23800 * 23801 * @hide 23802 */ 23803 public boolean resolveTextDirection() { 23804 // Reset any previous text direction resolution 23805 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23806 23807 if (hasRtlSupport()) { 23808 // Set resolved text direction flag depending on text direction flag 23809 final int textDirection = getRawTextDirection(); 23810 switch(textDirection) { 23811 case TEXT_DIRECTION_INHERIT: 23812 if (!canResolveTextDirection()) { 23813 // We cannot do the resolution if there is no parent, so use the default one 23814 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23815 // Resolution will need to happen again later 23816 return false; 23817 } 23818 23819 // Parent has not yet resolved, so we still return the default 23820 try { 23821 if (!mParent.isTextDirectionResolved()) { 23822 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23823 // Resolution will need to happen again later 23824 return false; 23825 } 23826 } catch (AbstractMethodError e) { 23827 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23828 " does not fully implement ViewParent", e); 23829 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 23830 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23831 return true; 23832 } 23833 23834 // Set current resolved direction to the same value as the parent's one 23835 int parentResolvedDirection; 23836 try { 23837 parentResolvedDirection = mParent.getTextDirection(); 23838 } catch (AbstractMethodError e) { 23839 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23840 " does not fully implement ViewParent", e); 23841 parentResolvedDirection = TEXT_DIRECTION_LTR; 23842 } 23843 switch (parentResolvedDirection) { 23844 case TEXT_DIRECTION_FIRST_STRONG: 23845 case TEXT_DIRECTION_ANY_RTL: 23846 case TEXT_DIRECTION_LTR: 23847 case TEXT_DIRECTION_RTL: 23848 case TEXT_DIRECTION_LOCALE: 23849 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23850 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23851 mPrivateFlags2 |= 23852 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23853 break; 23854 default: 23855 // Default resolved direction is "first strong" heuristic 23856 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23857 } 23858 break; 23859 case TEXT_DIRECTION_FIRST_STRONG: 23860 case TEXT_DIRECTION_ANY_RTL: 23861 case TEXT_DIRECTION_LTR: 23862 case TEXT_DIRECTION_RTL: 23863 case TEXT_DIRECTION_LOCALE: 23864 case TEXT_DIRECTION_FIRST_STRONG_LTR: 23865 case TEXT_DIRECTION_FIRST_STRONG_RTL: 23866 // Resolved direction is the same as text direction 23867 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 23868 break; 23869 default: 23870 // Default resolved direction is "first strong" heuristic 23871 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23872 } 23873 } else { 23874 // Default resolved direction is "first strong" heuristic 23875 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23876 } 23877 23878 // Set to resolved 23879 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 23880 return true; 23881 } 23882 23883 /** 23884 * Check if text direction resolution can be done. 23885 * 23886 * @return true if text direction resolution can be done otherwise return false. 23887 */ 23888 public boolean canResolveTextDirection() { 23889 switch (getRawTextDirection()) { 23890 case TEXT_DIRECTION_INHERIT: 23891 if (mParent != null) { 23892 try { 23893 return mParent.canResolveTextDirection(); 23894 } catch (AbstractMethodError e) { 23895 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 23896 " does not fully implement ViewParent", e); 23897 } 23898 } 23899 return false; 23900 23901 default: 23902 return true; 23903 } 23904 } 23905 23906 /** 23907 * Reset resolved text direction. Text direction will be resolved during a call to 23908 * {@link #onMeasure(int, int)}. 23909 * 23910 * @hide 23911 */ 23912 public void resetResolvedTextDirection() { 23913 // Reset any previous text direction resolution 23914 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 23915 // Set to default value 23916 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 23917 } 23918 23919 /** 23920 * @return true if text direction is inherited. 23921 * 23922 * @hide 23923 */ 23924 public boolean isTextDirectionInherited() { 23925 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 23926 } 23927 23928 /** 23929 * @return true if text direction is resolved. 23930 */ 23931 public boolean isTextDirectionResolved() { 23932 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 23933 } 23934 23935 /** 23936 * Return the value specifying the text alignment or policy that was set with 23937 * {@link #setTextAlignment(int)}. 23938 * 23939 * @return the defined text alignment. It can be one of: 23940 * 23941 * {@link #TEXT_ALIGNMENT_INHERIT}, 23942 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23943 * {@link #TEXT_ALIGNMENT_CENTER}, 23944 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23945 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23946 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23947 * {@link #TEXT_ALIGNMENT_VIEW_END} 23948 * 23949 * @attr ref android.R.styleable#View_textAlignment 23950 * 23951 * @hide 23952 */ 23953 @ViewDebug.ExportedProperty(category = "text", mapping = { 23954 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 23955 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 23956 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 23957 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 23958 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 23959 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 23960 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 23961 }) 23962 @TextAlignment 23963 public int getRawTextAlignment() { 23964 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 23965 } 23966 23967 /** 23968 * Set the text alignment. 23969 * 23970 * @param textAlignment The text alignment to set. Should be one of 23971 * 23972 * {@link #TEXT_ALIGNMENT_INHERIT}, 23973 * {@link #TEXT_ALIGNMENT_GRAVITY}, 23974 * {@link #TEXT_ALIGNMENT_CENTER}, 23975 * {@link #TEXT_ALIGNMENT_TEXT_START}, 23976 * {@link #TEXT_ALIGNMENT_TEXT_END}, 23977 * {@link #TEXT_ALIGNMENT_VIEW_START}, 23978 * {@link #TEXT_ALIGNMENT_VIEW_END} 23979 * 23980 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 23981 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 23982 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 23983 * 23984 * @attr ref android.R.styleable#View_textAlignment 23985 */ 23986 public void setTextAlignment(@TextAlignment int textAlignment) { 23987 if (textAlignment != getRawTextAlignment()) { 23988 // Reset the current and resolved text alignment 23989 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 23990 resetResolvedTextAlignment(); 23991 // Set the new text alignment 23992 mPrivateFlags2 |= 23993 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 23994 // Do resolution 23995 resolveTextAlignment(); 23996 // Notify change 23997 onRtlPropertiesChanged(getLayoutDirection()); 23998 // Refresh 23999 requestLayout(); 24000 invalidate(true); 24001 } 24002 } 24003 24004 /** 24005 * Return the resolved text alignment. 24006 * 24007 * @return the resolved text alignment. Returns one of: 24008 * 24009 * {@link #TEXT_ALIGNMENT_GRAVITY}, 24010 * {@link #TEXT_ALIGNMENT_CENTER}, 24011 * {@link #TEXT_ALIGNMENT_TEXT_START}, 24012 * {@link #TEXT_ALIGNMENT_TEXT_END}, 24013 * {@link #TEXT_ALIGNMENT_VIEW_START}, 24014 * {@link #TEXT_ALIGNMENT_VIEW_END} 24015 * 24016 * @attr ref android.R.styleable#View_textAlignment 24017 */ 24018 @ViewDebug.ExportedProperty(category = "text", mapping = { 24019 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 24020 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 24021 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 24022 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 24023 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 24024 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 24025 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 24026 }) 24027 @TextAlignment 24028 public int getTextAlignment() { 24029 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 24030 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 24031 } 24032 24033 /** 24034 * Resolve the text alignment. 24035 * 24036 * @return true if resolution has been done, false otherwise. 24037 * 24038 * @hide 24039 */ 24040 public boolean resolveTextAlignment() { 24041 // Reset any previous text alignment resolution 24042 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 24043 24044 if (hasRtlSupport()) { 24045 // Set resolved text alignment flag depending on text alignment flag 24046 final int textAlignment = getRawTextAlignment(); 24047 switch (textAlignment) { 24048 case TEXT_ALIGNMENT_INHERIT: 24049 // Check if we can resolve the text alignment 24050 if (!canResolveTextAlignment()) { 24051 // We cannot do the resolution if there is no parent so use the default 24052 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24053 // Resolution will need to happen again later 24054 return false; 24055 } 24056 24057 // Parent has not yet resolved, so we still return the default 24058 try { 24059 if (!mParent.isTextAlignmentResolved()) { 24060 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24061 // Resolution will need to happen again later 24062 return false; 24063 } 24064 } catch (AbstractMethodError e) { 24065 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24066 " does not fully implement ViewParent", e); 24067 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 24068 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24069 return true; 24070 } 24071 24072 int parentResolvedTextAlignment; 24073 try { 24074 parentResolvedTextAlignment = mParent.getTextAlignment(); 24075 } catch (AbstractMethodError e) { 24076 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24077 " does not fully implement ViewParent", e); 24078 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 24079 } 24080 switch (parentResolvedTextAlignment) { 24081 case TEXT_ALIGNMENT_GRAVITY: 24082 case TEXT_ALIGNMENT_TEXT_START: 24083 case TEXT_ALIGNMENT_TEXT_END: 24084 case TEXT_ALIGNMENT_CENTER: 24085 case TEXT_ALIGNMENT_VIEW_START: 24086 case TEXT_ALIGNMENT_VIEW_END: 24087 // Resolved text alignment is the same as the parent resolved 24088 // text alignment 24089 mPrivateFlags2 |= 24090 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 24091 break; 24092 default: 24093 // Use default resolved text alignment 24094 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24095 } 24096 break; 24097 case TEXT_ALIGNMENT_GRAVITY: 24098 case TEXT_ALIGNMENT_TEXT_START: 24099 case TEXT_ALIGNMENT_TEXT_END: 24100 case TEXT_ALIGNMENT_CENTER: 24101 case TEXT_ALIGNMENT_VIEW_START: 24102 case TEXT_ALIGNMENT_VIEW_END: 24103 // Resolved text alignment is the same as text alignment 24104 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 24105 break; 24106 default: 24107 // Use default resolved text alignment 24108 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24109 } 24110 } else { 24111 // Use default resolved text alignment 24112 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24113 } 24114 24115 // Set the resolved 24116 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24117 return true; 24118 } 24119 24120 /** 24121 * Check if text alignment resolution can be done. 24122 * 24123 * @return true if text alignment resolution can be done otherwise return false. 24124 */ 24125 public boolean canResolveTextAlignment() { 24126 switch (getRawTextAlignment()) { 24127 case TEXT_DIRECTION_INHERIT: 24128 if (mParent != null) { 24129 try { 24130 return mParent.canResolveTextAlignment(); 24131 } catch (AbstractMethodError e) { 24132 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 24133 " does not fully implement ViewParent", e); 24134 } 24135 } 24136 return false; 24137 24138 default: 24139 return true; 24140 } 24141 } 24142 24143 /** 24144 * Reset resolved text alignment. Text alignment will be resolved during a call to 24145 * {@link #onMeasure(int, int)}. 24146 * 24147 * @hide 24148 */ 24149 public void resetResolvedTextAlignment() { 24150 // Reset any previous text alignment resolution 24151 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 24152 // Set to default 24153 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 24154 } 24155 24156 /** 24157 * @return true if text alignment is inherited. 24158 * 24159 * @hide 24160 */ 24161 public boolean isTextAlignmentInherited() { 24162 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 24163 } 24164 24165 /** 24166 * @return true if text alignment is resolved. 24167 */ 24168 public boolean isTextAlignmentResolved() { 24169 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 24170 } 24171 24172 /** 24173 * Generate a value suitable for use in {@link #setId(int)}. 24174 * This value will not collide with ID values generated at build time by aapt for R.id. 24175 * 24176 * @return a generated ID value 24177 */ 24178 public static int generateViewId() { 24179 for (;;) { 24180 final int result = sNextGeneratedId.get(); 24181 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 24182 int newValue = result + 1; 24183 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 24184 if (sNextGeneratedId.compareAndSet(result, newValue)) { 24185 return result; 24186 } 24187 } 24188 } 24189 24190 private static boolean isViewIdGenerated(int id) { 24191 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 24192 } 24193 24194 /** 24195 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 24196 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 24197 * a normal View or a ViewGroup with 24198 * {@link android.view.ViewGroup#isTransitionGroup()} true. 24199 * @hide 24200 */ 24201 public void captureTransitioningViews(List<View> transitioningViews) { 24202 if (getVisibility() == View.VISIBLE) { 24203 transitioningViews.add(this); 24204 } 24205 } 24206 24207 /** 24208 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 24209 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 24210 * @hide 24211 */ 24212 public void findNamedViews(Map<String, View> namedElements) { 24213 if (getVisibility() == VISIBLE || mGhostView != null) { 24214 String transitionName = getTransitionName(); 24215 if (transitionName != null) { 24216 namedElements.put(transitionName, this); 24217 } 24218 } 24219 } 24220 24221 /** 24222 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 24223 * The default implementation does not care the location or event types, but some subclasses 24224 * may use it (such as WebViews). 24225 * @param event The MotionEvent from a mouse 24226 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 24227 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 24228 * @see PointerIcon 24229 */ 24230 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 24231 final float x = event.getX(pointerIndex); 24232 final float y = event.getY(pointerIndex); 24233 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 24234 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 24235 } 24236 return mPointerIcon; 24237 } 24238 24239 /** 24240 * Set the pointer icon for the current view. 24241 * Passing {@code null} will restore the pointer icon to its default value. 24242 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 24243 */ 24244 public void setPointerIcon(PointerIcon pointerIcon) { 24245 mPointerIcon = pointerIcon; 24246 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 24247 return; 24248 } 24249 try { 24250 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 24251 } catch (RemoteException e) { 24252 } 24253 } 24254 24255 /** 24256 * Gets the pointer icon for the current view. 24257 */ 24258 public PointerIcon getPointerIcon() { 24259 return mPointerIcon; 24260 } 24261 24262 /** 24263 * Checks pointer capture status. 24264 * 24265 * @return true if the view has pointer capture. 24266 * @see #requestPointerCapture() 24267 * @see #hasPointerCapture() 24268 */ 24269 public boolean hasPointerCapture() { 24270 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24271 if (viewRootImpl == null) { 24272 return false; 24273 } 24274 return viewRootImpl.hasPointerCapture(); 24275 } 24276 24277 /** 24278 * Requests pointer capture mode. 24279 * <p> 24280 * When the window has pointer capture, the mouse pointer icon will disappear and will not 24281 * change its position. Further mouse will be dispatched with the source 24282 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 24283 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 24284 * (touchscreens, or stylus) will not be affected. 24285 * <p> 24286 * If the window already has pointer capture, this call does nothing. 24287 * <p> 24288 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 24289 * automatically when the window loses focus. 24290 * 24291 * @see #releasePointerCapture() 24292 * @see #hasPointerCapture() 24293 */ 24294 public void requestPointerCapture() { 24295 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24296 if (viewRootImpl != null) { 24297 viewRootImpl.requestPointerCapture(true); 24298 } 24299 } 24300 24301 24302 /** 24303 * Releases the pointer capture. 24304 * <p> 24305 * If the window does not have pointer capture, this call will do nothing. 24306 * @see #requestPointerCapture() 24307 * @see #hasPointerCapture() 24308 */ 24309 public void releasePointerCapture() { 24310 final ViewRootImpl viewRootImpl = getViewRootImpl(); 24311 if (viewRootImpl != null) { 24312 viewRootImpl.requestPointerCapture(false); 24313 } 24314 } 24315 24316 /** 24317 * Called when the window has just acquired or lost pointer capture. 24318 * 24319 * @param hasCapture True if the view now has pointerCapture, false otherwise. 24320 */ 24321 @CallSuper 24322 public void onPointerCaptureChange(boolean hasCapture) { 24323 } 24324 24325 /** 24326 * @see #onPointerCaptureChange 24327 */ 24328 public void dispatchPointerCaptureChanged(boolean hasCapture) { 24329 onPointerCaptureChange(hasCapture); 24330 } 24331 24332 /** 24333 * Implement this method to handle captured pointer events 24334 * 24335 * @param event The captured pointer event. 24336 * @return True if the event was handled, false otherwise. 24337 * @see #requestPointerCapture() 24338 */ 24339 public boolean onCapturedPointerEvent(MotionEvent event) { 24340 return false; 24341 } 24342 24343 /** 24344 * Interface definition for a callback to be invoked when a captured pointer event 24345 * is being dispatched this view. The callback will be invoked before the event is 24346 * given to the view. 24347 */ 24348 public interface OnCapturedPointerListener { 24349 /** 24350 * Called when a captured pointer event is dispatched to a view. 24351 * @param view The view this event has been dispatched to. 24352 * @param event The captured event. 24353 * @return True if the listener has consumed the event, false otherwise. 24354 */ 24355 boolean onCapturedPointer(View view, MotionEvent event); 24356 } 24357 24358 /** 24359 * Set a listener to receive callbacks when the pointer capture state of a view changes. 24360 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 24361 */ 24362 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 24363 getListenerInfo().mOnCapturedPointerListener = l; 24364 } 24365 24366 // Properties 24367 // 24368 /** 24369 * A Property wrapper around the <code>alpha</code> functionality handled by the 24370 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 24371 */ 24372 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 24373 @Override 24374 public void setValue(View object, float value) { 24375 object.setAlpha(value); 24376 } 24377 24378 @Override 24379 public Float get(View object) { 24380 return object.getAlpha(); 24381 } 24382 }; 24383 24384 /** 24385 * A Property wrapper around the <code>translationX</code> functionality handled by the 24386 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 24387 */ 24388 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 24389 @Override 24390 public void setValue(View object, float value) { 24391 object.setTranslationX(value); 24392 } 24393 24394 @Override 24395 public Float get(View object) { 24396 return object.getTranslationX(); 24397 } 24398 }; 24399 24400 /** 24401 * A Property wrapper around the <code>translationY</code> functionality handled by the 24402 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 24403 */ 24404 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 24405 @Override 24406 public void setValue(View object, float value) { 24407 object.setTranslationY(value); 24408 } 24409 24410 @Override 24411 public Float get(View object) { 24412 return object.getTranslationY(); 24413 } 24414 }; 24415 24416 /** 24417 * A Property wrapper around the <code>translationZ</code> functionality handled by the 24418 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 24419 */ 24420 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 24421 @Override 24422 public void setValue(View object, float value) { 24423 object.setTranslationZ(value); 24424 } 24425 24426 @Override 24427 public Float get(View object) { 24428 return object.getTranslationZ(); 24429 } 24430 }; 24431 24432 /** 24433 * A Property wrapper around the <code>x</code> functionality handled by the 24434 * {@link View#setX(float)} and {@link View#getX()} methods. 24435 */ 24436 public static final Property<View, Float> X = new FloatProperty<View>("x") { 24437 @Override 24438 public void setValue(View object, float value) { 24439 object.setX(value); 24440 } 24441 24442 @Override 24443 public Float get(View object) { 24444 return object.getX(); 24445 } 24446 }; 24447 24448 /** 24449 * A Property wrapper around the <code>y</code> functionality handled by the 24450 * {@link View#setY(float)} and {@link View#getY()} methods. 24451 */ 24452 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 24453 @Override 24454 public void setValue(View object, float value) { 24455 object.setY(value); 24456 } 24457 24458 @Override 24459 public Float get(View object) { 24460 return object.getY(); 24461 } 24462 }; 24463 24464 /** 24465 * A Property wrapper around the <code>z</code> functionality handled by the 24466 * {@link View#setZ(float)} and {@link View#getZ()} methods. 24467 */ 24468 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 24469 @Override 24470 public void setValue(View object, float value) { 24471 object.setZ(value); 24472 } 24473 24474 @Override 24475 public Float get(View object) { 24476 return object.getZ(); 24477 } 24478 }; 24479 24480 /** 24481 * A Property wrapper around the <code>rotation</code> functionality handled by the 24482 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 24483 */ 24484 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 24485 @Override 24486 public void setValue(View object, float value) { 24487 object.setRotation(value); 24488 } 24489 24490 @Override 24491 public Float get(View object) { 24492 return object.getRotation(); 24493 } 24494 }; 24495 24496 /** 24497 * A Property wrapper around the <code>rotationX</code> functionality handled by the 24498 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 24499 */ 24500 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 24501 @Override 24502 public void setValue(View object, float value) { 24503 object.setRotationX(value); 24504 } 24505 24506 @Override 24507 public Float get(View object) { 24508 return object.getRotationX(); 24509 } 24510 }; 24511 24512 /** 24513 * A Property wrapper around the <code>rotationY</code> functionality handled by the 24514 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 24515 */ 24516 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 24517 @Override 24518 public void setValue(View object, float value) { 24519 object.setRotationY(value); 24520 } 24521 24522 @Override 24523 public Float get(View object) { 24524 return object.getRotationY(); 24525 } 24526 }; 24527 24528 /** 24529 * A Property wrapper around the <code>scaleX</code> functionality handled by the 24530 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 24531 */ 24532 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 24533 @Override 24534 public void setValue(View object, float value) { 24535 object.setScaleX(value); 24536 } 24537 24538 @Override 24539 public Float get(View object) { 24540 return object.getScaleX(); 24541 } 24542 }; 24543 24544 /** 24545 * A Property wrapper around the <code>scaleY</code> functionality handled by the 24546 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 24547 */ 24548 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 24549 @Override 24550 public void setValue(View object, float value) { 24551 object.setScaleY(value); 24552 } 24553 24554 @Override 24555 public Float get(View object) { 24556 return object.getScaleY(); 24557 } 24558 }; 24559 24560 /** 24561 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 24562 * Each MeasureSpec represents a requirement for either the width or the height. 24563 * A MeasureSpec is comprised of a size and a mode. There are three possible 24564 * modes: 24565 * <dl> 24566 * <dt>UNSPECIFIED</dt> 24567 * <dd> 24568 * The parent has not imposed any constraint on the child. It can be whatever size 24569 * it wants. 24570 * </dd> 24571 * 24572 * <dt>EXACTLY</dt> 24573 * <dd> 24574 * The parent has determined an exact size for the child. The child is going to be 24575 * given those bounds regardless of how big it wants to be. 24576 * </dd> 24577 * 24578 * <dt>AT_MOST</dt> 24579 * <dd> 24580 * The child can be as large as it wants up to the specified size. 24581 * </dd> 24582 * </dl> 24583 * 24584 * MeasureSpecs are implemented as ints to reduce object allocation. This class 24585 * is provided to pack and unpack the <size, mode> tuple into the int. 24586 */ 24587 public static class MeasureSpec { 24588 private static final int MODE_SHIFT = 30; 24589 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 24590 24591 /** @hide */ 24592 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 24593 @Retention(RetentionPolicy.SOURCE) 24594 public @interface MeasureSpecMode {} 24595 24596 /** 24597 * Measure specification mode: The parent has not imposed any constraint 24598 * on the child. It can be whatever size it wants. 24599 */ 24600 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 24601 24602 /** 24603 * Measure specification mode: The parent has determined an exact size 24604 * for the child. The child is going to be given those bounds regardless 24605 * of how big it wants to be. 24606 */ 24607 public static final int EXACTLY = 1 << MODE_SHIFT; 24608 24609 /** 24610 * Measure specification mode: The child can be as large as it wants up 24611 * to the specified size. 24612 */ 24613 public static final int AT_MOST = 2 << MODE_SHIFT; 24614 24615 /** 24616 * Creates a measure specification based on the supplied size and mode. 24617 * 24618 * The mode must always be one of the following: 24619 * <ul> 24620 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 24621 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 24622 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 24623 * </ul> 24624 * 24625 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 24626 * implementation was such that the order of arguments did not matter 24627 * and overflow in either value could impact the resulting MeasureSpec. 24628 * {@link android.widget.RelativeLayout} was affected by this bug. 24629 * Apps targeting API levels greater than 17 will get the fixed, more strict 24630 * behavior.</p> 24631 * 24632 * @param size the size of the measure specification 24633 * @param mode the mode of the measure specification 24634 * @return the measure specification based on size and mode 24635 */ 24636 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 24637 @MeasureSpecMode int mode) { 24638 if (sUseBrokenMakeMeasureSpec) { 24639 return size + mode; 24640 } else { 24641 return (size & ~MODE_MASK) | (mode & MODE_MASK); 24642 } 24643 } 24644 24645 /** 24646 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 24647 * will automatically get a size of 0. Older apps expect this. 24648 * 24649 * @hide internal use only for compatibility with system widgets and older apps 24650 */ 24651 public static int makeSafeMeasureSpec(int size, int mode) { 24652 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 24653 return 0; 24654 } 24655 return makeMeasureSpec(size, mode); 24656 } 24657 24658 /** 24659 * Extracts the mode from the supplied measure specification. 24660 * 24661 * @param measureSpec the measure specification to extract the mode from 24662 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 24663 * {@link android.view.View.MeasureSpec#AT_MOST} or 24664 * {@link android.view.View.MeasureSpec#EXACTLY} 24665 */ 24666 @MeasureSpecMode 24667 public static int getMode(int measureSpec) { 24668 //noinspection ResourceType 24669 return (measureSpec & MODE_MASK); 24670 } 24671 24672 /** 24673 * Extracts the size from the supplied measure specification. 24674 * 24675 * @param measureSpec the measure specification to extract the size from 24676 * @return the size in pixels defined in the supplied measure specification 24677 */ 24678 public static int getSize(int measureSpec) { 24679 return (measureSpec & ~MODE_MASK); 24680 } 24681 24682 static int adjust(int measureSpec, int delta) { 24683 final int mode = getMode(measureSpec); 24684 int size = getSize(measureSpec); 24685 if (mode == UNSPECIFIED) { 24686 // No need to adjust size for UNSPECIFIED mode. 24687 return makeMeasureSpec(size, UNSPECIFIED); 24688 } 24689 size += delta; 24690 if (size < 0) { 24691 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 24692 ") spec: " + toString(measureSpec) + " delta: " + delta); 24693 size = 0; 24694 } 24695 return makeMeasureSpec(size, mode); 24696 } 24697 24698 /** 24699 * Returns a String representation of the specified measure 24700 * specification. 24701 * 24702 * @param measureSpec the measure specification to convert to a String 24703 * @return a String with the following format: "MeasureSpec: MODE SIZE" 24704 */ 24705 public static String toString(int measureSpec) { 24706 int mode = getMode(measureSpec); 24707 int size = getSize(measureSpec); 24708 24709 StringBuilder sb = new StringBuilder("MeasureSpec: "); 24710 24711 if (mode == UNSPECIFIED) 24712 sb.append("UNSPECIFIED "); 24713 else if (mode == EXACTLY) 24714 sb.append("EXACTLY "); 24715 else if (mode == AT_MOST) 24716 sb.append("AT_MOST "); 24717 else 24718 sb.append(mode).append(" "); 24719 24720 sb.append(size); 24721 return sb.toString(); 24722 } 24723 } 24724 24725 private final class CheckForLongPress implements Runnable { 24726 private int mOriginalWindowAttachCount; 24727 private float mX; 24728 private float mY; 24729 private boolean mOriginalPressedState; 24730 24731 @Override 24732 public void run() { 24733 if ((mOriginalPressedState == isPressed()) && (mParent != null) 24734 && mOriginalWindowAttachCount == mWindowAttachCount) { 24735 if (performLongClick(mX, mY)) { 24736 mHasPerformedLongPress = true; 24737 } 24738 } 24739 } 24740 24741 public void setAnchor(float x, float y) { 24742 mX = x; 24743 mY = y; 24744 } 24745 24746 public void rememberWindowAttachCount() { 24747 mOriginalWindowAttachCount = mWindowAttachCount; 24748 } 24749 24750 public void rememberPressedState() { 24751 mOriginalPressedState = isPressed(); 24752 } 24753 } 24754 24755 private final class CheckForTap implements Runnable { 24756 public float x; 24757 public float y; 24758 24759 @Override 24760 public void run() { 24761 mPrivateFlags &= ~PFLAG_PREPRESSED; 24762 setPressed(true, x, y); 24763 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 24764 } 24765 } 24766 24767 private final class PerformClick implements Runnable { 24768 @Override 24769 public void run() { 24770 performClick(); 24771 } 24772 } 24773 24774 /** 24775 * This method returns a ViewPropertyAnimator object, which can be used to animate 24776 * specific properties on this View. 24777 * 24778 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 24779 */ 24780 public ViewPropertyAnimator animate() { 24781 if (mAnimator == null) { 24782 mAnimator = new ViewPropertyAnimator(this); 24783 } 24784 return mAnimator; 24785 } 24786 24787 /** 24788 * Sets the name of the View to be used to identify Views in Transitions. 24789 * Names should be unique in the View hierarchy. 24790 * 24791 * @param transitionName The name of the View to uniquely identify it for Transitions. 24792 */ 24793 public final void setTransitionName(String transitionName) { 24794 mTransitionName = transitionName; 24795 } 24796 24797 /** 24798 * Returns the name of the View to be used to identify Views in Transitions. 24799 * Names should be unique in the View hierarchy. 24800 * 24801 * <p>This returns null if the View has not been given a name.</p> 24802 * 24803 * @return The name used of the View to be used to identify Views in Transitions or null 24804 * if no name has been given. 24805 */ 24806 @ViewDebug.ExportedProperty 24807 public String getTransitionName() { 24808 return mTransitionName; 24809 } 24810 24811 /** 24812 * @hide 24813 */ 24814 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 24815 // Do nothing. 24816 } 24817 24818 /** 24819 * Interface definition for a callback to be invoked when a hardware key event is 24820 * dispatched to this view. The callback will be invoked before the key event is 24821 * given to the view. This is only useful for hardware keyboards; a software input 24822 * method has no obligation to trigger this listener. 24823 */ 24824 public interface OnKeyListener { 24825 /** 24826 * Called when a hardware key is dispatched to a view. This allows listeners to 24827 * get a chance to respond before the target view. 24828 * <p>Key presses in software keyboards will generally NOT trigger this method, 24829 * although some may elect to do so in some situations. Do not assume a 24830 * software input method has to be key-based; even if it is, it may use key presses 24831 * in a different way than you expect, so there is no way to reliably catch soft 24832 * input key presses. 24833 * 24834 * @param v The view the key has been dispatched to. 24835 * @param keyCode The code for the physical key that was pressed 24836 * @param event The KeyEvent object containing full information about 24837 * the event. 24838 * @return True if the listener has consumed the event, false otherwise. 24839 */ 24840 boolean onKey(View v, int keyCode, KeyEvent event); 24841 } 24842 24843 /** 24844 * Interface definition for a callback to be invoked when a touch event is 24845 * dispatched to this view. The callback will be invoked before the touch 24846 * event is given to the view. 24847 */ 24848 public interface OnTouchListener { 24849 /** 24850 * Called when a touch event is dispatched to a view. This allows listeners to 24851 * get a chance to respond before the target view. 24852 * 24853 * @param v The view the touch event has been dispatched to. 24854 * @param event The MotionEvent object containing full information about 24855 * the event. 24856 * @return True if the listener has consumed the event, false otherwise. 24857 */ 24858 boolean onTouch(View v, MotionEvent event); 24859 } 24860 24861 /** 24862 * Interface definition for a callback to be invoked when a hover event is 24863 * dispatched to this view. The callback will be invoked before the hover 24864 * event is given to the view. 24865 */ 24866 public interface OnHoverListener { 24867 /** 24868 * Called when a hover event is dispatched to a view. This allows listeners to 24869 * get a chance to respond before the target view. 24870 * 24871 * @param v The view the hover event has been dispatched to. 24872 * @param event The MotionEvent object containing full information about 24873 * the event. 24874 * @return True if the listener has consumed the event, false otherwise. 24875 */ 24876 boolean onHover(View v, MotionEvent event); 24877 } 24878 24879 /** 24880 * Interface definition for a callback to be invoked when a generic motion event is 24881 * dispatched to this view. The callback will be invoked before the generic motion 24882 * event is given to the view. 24883 */ 24884 public interface OnGenericMotionListener { 24885 /** 24886 * Called when a generic motion event is dispatched to a view. This allows listeners to 24887 * get a chance to respond before the target view. 24888 * 24889 * @param v The view the generic motion event has been dispatched to. 24890 * @param event The MotionEvent object containing full information about 24891 * the event. 24892 * @return True if the listener has consumed the event, false otherwise. 24893 */ 24894 boolean onGenericMotion(View v, MotionEvent event); 24895 } 24896 24897 /** 24898 * Interface definition for a callback to be invoked when a view has been clicked and held. 24899 */ 24900 public interface OnLongClickListener { 24901 /** 24902 * Called when a view has been clicked and held. 24903 * 24904 * @param v The view that was clicked and held. 24905 * 24906 * @return true if the callback consumed the long click, false otherwise. 24907 */ 24908 boolean onLongClick(View v); 24909 } 24910 24911 /** 24912 * Interface definition for a callback to be invoked when a drag is being dispatched 24913 * to this view. The callback will be invoked before the hosting view's own 24914 * onDrag(event) method. If the listener wants to fall back to the hosting view's 24915 * onDrag(event) behavior, it should return 'false' from this callback. 24916 * 24917 * <div class="special reference"> 24918 * <h3>Developer Guides</h3> 24919 * <p>For a guide to implementing drag and drop features, read the 24920 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 24921 * </div> 24922 */ 24923 public interface OnDragListener { 24924 /** 24925 * Called when a drag event is dispatched to a view. This allows listeners 24926 * to get a chance to override base View behavior. 24927 * 24928 * @param v The View that received the drag event. 24929 * @param event The {@link android.view.DragEvent} object for the drag event. 24930 * @return {@code true} if the drag event was handled successfully, or {@code false} 24931 * if the drag event was not handled. Note that {@code false} will trigger the View 24932 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 24933 */ 24934 boolean onDrag(View v, DragEvent event); 24935 } 24936 24937 /** 24938 * Interface definition for a callback to be invoked when the focus state of 24939 * a view changed. 24940 */ 24941 public interface OnFocusChangeListener { 24942 /** 24943 * Called when the focus state of a view has changed. 24944 * 24945 * @param v The view whose state has changed. 24946 * @param hasFocus The new focus state of v. 24947 */ 24948 void onFocusChange(View v, boolean hasFocus); 24949 } 24950 24951 /** 24952 * Interface definition for a callback to be invoked when a view is clicked. 24953 */ 24954 public interface OnClickListener { 24955 /** 24956 * Called when a view has been clicked. 24957 * 24958 * @param v The view that was clicked. 24959 */ 24960 void onClick(View v); 24961 } 24962 24963 /** 24964 * Interface definition for a callback to be invoked when a view is context clicked. 24965 */ 24966 public interface OnContextClickListener { 24967 /** 24968 * Called when a view is context clicked. 24969 * 24970 * @param v The view that has been context clicked. 24971 * @return true if the callback consumed the context click, false otherwise. 24972 */ 24973 boolean onContextClick(View v); 24974 } 24975 24976 /** 24977 * Interface definition for a callback to be invoked when the context menu 24978 * for this view is being built. 24979 */ 24980 public interface OnCreateContextMenuListener { 24981 /** 24982 * Called when the context menu for this view is being built. It is not 24983 * safe to hold onto the menu after this method returns. 24984 * 24985 * @param menu The context menu that is being built 24986 * @param v The view for which the context menu is being built 24987 * @param menuInfo Extra information about the item for which the 24988 * context menu should be shown. This information will vary 24989 * depending on the class of v. 24990 */ 24991 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 24992 } 24993 24994 /** 24995 * Interface definition for a callback to be invoked when the status bar changes 24996 * visibility. This reports <strong>global</strong> changes to the system UI 24997 * state, not what the application is requesting. 24998 * 24999 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 25000 */ 25001 public interface OnSystemUiVisibilityChangeListener { 25002 /** 25003 * Called when the status bar changes visibility because of a call to 25004 * {@link View#setSystemUiVisibility(int)}. 25005 * 25006 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 25007 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 25008 * This tells you the <strong>global</strong> state of these UI visibility 25009 * flags, not what your app is currently applying. 25010 */ 25011 public void onSystemUiVisibilityChange(int visibility); 25012 } 25013 25014 /** 25015 * Interface definition for a callback to be invoked when this view is attached 25016 * or detached from its window. 25017 */ 25018 public interface OnAttachStateChangeListener { 25019 /** 25020 * Called when the view is attached to a window. 25021 * @param v The view that was attached 25022 */ 25023 public void onViewAttachedToWindow(View v); 25024 /** 25025 * Called when the view is detached from a window. 25026 * @param v The view that was detached 25027 */ 25028 public void onViewDetachedFromWindow(View v); 25029 } 25030 25031 /** 25032 * Listener for applying window insets on a view in a custom way. 25033 * 25034 * <p>Apps may choose to implement this interface if they want to apply custom policy 25035 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 25036 * is set, its 25037 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 25038 * method will be called instead of the View's own 25039 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 25040 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 25041 * the View's normal behavior as part of its own.</p> 25042 */ 25043 public interface OnApplyWindowInsetsListener { 25044 /** 25045 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 25046 * on a View, this listener method will be called instead of the view's own 25047 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 25048 * 25049 * @param v The view applying window insets 25050 * @param insets The insets to apply 25051 * @return The insets supplied, minus any insets that were consumed 25052 */ 25053 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 25054 } 25055 25056 private final class UnsetPressedState implements Runnable { 25057 @Override 25058 public void run() { 25059 setPressed(false); 25060 } 25061 } 25062 25063 /** 25064 * When a view becomes invisible checks if autofill considers the view invisible too. This 25065 * happens after the regular removal operation to make sure the operation is finished by the 25066 * time this is called. 25067 */ 25068 private static class VisibilityChangeForAutofillHandler extends Handler { 25069 private final AutofillManager mAfm; 25070 private final View mView; 25071 25072 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 25073 @NonNull View view) { 25074 mAfm = afm; 25075 mView = view; 25076 } 25077 25078 @Override 25079 public void handleMessage(Message msg) { 25080 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 25081 } 25082 } 25083 25084 /** 25085 * Base class for derived classes that want to save and restore their own 25086 * state in {@link android.view.View#onSaveInstanceState()}. 25087 */ 25088 public static class BaseSavedState extends AbsSavedState { 25089 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 25090 static final int IS_AUTOFILLED = 0b10; 25091 static final int AUTOFILL_ID = 0b100; 25092 25093 // Flags that describe what data in this state is valid 25094 int mSavedData; 25095 String mStartActivityRequestWhoSaved; 25096 boolean mIsAutofilled; 25097 int mAutofillViewId; 25098 25099 /** 25100 * Constructor used when reading from a parcel. Reads the state of the superclass. 25101 * 25102 * @param source parcel to read from 25103 */ 25104 public BaseSavedState(Parcel source) { 25105 this(source, null); 25106 } 25107 25108 /** 25109 * Constructor used when reading from a parcel using a given class loader. 25110 * Reads the state of the superclass. 25111 * 25112 * @param source parcel to read from 25113 * @param loader ClassLoader to use for reading 25114 */ 25115 public BaseSavedState(Parcel source, ClassLoader loader) { 25116 super(source, loader); 25117 mSavedData = source.readInt(); 25118 mStartActivityRequestWhoSaved = source.readString(); 25119 mIsAutofilled = source.readBoolean(); 25120 mAutofillViewId = source.readInt(); 25121 } 25122 25123 /** 25124 * Constructor called by derived classes when creating their SavedState objects 25125 * 25126 * @param superState The state of the superclass of this view 25127 */ 25128 public BaseSavedState(Parcelable superState) { 25129 super(superState); 25130 } 25131 25132 @Override 25133 public void writeToParcel(Parcel out, int flags) { 25134 super.writeToParcel(out, flags); 25135 25136 out.writeInt(mSavedData); 25137 out.writeString(mStartActivityRequestWhoSaved); 25138 out.writeBoolean(mIsAutofilled); 25139 out.writeInt(mAutofillViewId); 25140 } 25141 25142 public static final Parcelable.Creator<BaseSavedState> CREATOR 25143 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 25144 @Override 25145 public BaseSavedState createFromParcel(Parcel in) { 25146 return new BaseSavedState(in); 25147 } 25148 25149 @Override 25150 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 25151 return new BaseSavedState(in, loader); 25152 } 25153 25154 @Override 25155 public BaseSavedState[] newArray(int size) { 25156 return new BaseSavedState[size]; 25157 } 25158 }; 25159 } 25160 25161 /** 25162 * A set of information given to a view when it is attached to its parent 25163 * window. 25164 */ 25165 final static class AttachInfo { 25166 interface Callbacks { 25167 void playSoundEffect(int effectId); 25168 boolean performHapticFeedback(int effectId, boolean always); 25169 } 25170 25171 /** 25172 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 25173 * to a Handler. This class contains the target (View) to invalidate and 25174 * the coordinates of the dirty rectangle. 25175 * 25176 * For performance purposes, this class also implements a pool of up to 25177 * POOL_LIMIT objects that get reused. This reduces memory allocations 25178 * whenever possible. 25179 */ 25180 static class InvalidateInfo { 25181 private static final int POOL_LIMIT = 10; 25182 25183 private static final SynchronizedPool<InvalidateInfo> sPool = 25184 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 25185 25186 View target; 25187 25188 int left; 25189 int top; 25190 int right; 25191 int bottom; 25192 25193 public static InvalidateInfo obtain() { 25194 InvalidateInfo instance = sPool.acquire(); 25195 return (instance != null) ? instance : new InvalidateInfo(); 25196 } 25197 25198 public void recycle() { 25199 target = null; 25200 sPool.release(this); 25201 } 25202 } 25203 25204 final IWindowSession mSession; 25205 25206 final IWindow mWindow; 25207 25208 final IBinder mWindowToken; 25209 25210 Display mDisplay; 25211 25212 final Callbacks mRootCallbacks; 25213 25214 IWindowId mIWindowId; 25215 WindowId mWindowId; 25216 25217 /** 25218 * The top view of the hierarchy. 25219 */ 25220 View mRootView; 25221 25222 IBinder mPanelParentWindowToken; 25223 25224 boolean mHardwareAccelerated; 25225 boolean mHardwareAccelerationRequested; 25226 ThreadedRenderer mThreadedRenderer; 25227 List<RenderNode> mPendingAnimatingRenderNodes; 25228 25229 /** 25230 * The state of the display to which the window is attached, as reported 25231 * by {@link Display#getState()}. Note that the display state constants 25232 * declared by {@link Display} do not exactly line up with the screen state 25233 * constants declared by {@link View} (there are more display states than 25234 * screen states). 25235 */ 25236 int mDisplayState = Display.STATE_UNKNOWN; 25237 25238 /** 25239 * Scale factor used by the compatibility mode 25240 */ 25241 float mApplicationScale; 25242 25243 /** 25244 * Indicates whether the application is in compatibility mode 25245 */ 25246 boolean mScalingRequired; 25247 25248 /** 25249 * Left position of this view's window 25250 */ 25251 int mWindowLeft; 25252 25253 /** 25254 * Top position of this view's window 25255 */ 25256 int mWindowTop; 25257 25258 /** 25259 * Indicates whether views need to use 32-bit drawing caches 25260 */ 25261 boolean mUse32BitDrawingCache; 25262 25263 /** 25264 * For windows that are full-screen but using insets to layout inside 25265 * of the screen areas, these are the current insets to appear inside 25266 * the overscan area of the display. 25267 */ 25268 final Rect mOverscanInsets = new Rect(); 25269 25270 /** 25271 * For windows that are full-screen but using insets to layout inside 25272 * of the screen decorations, these are the current insets for the 25273 * content of the window. 25274 */ 25275 final Rect mContentInsets = new Rect(); 25276 25277 /** 25278 * For windows that are full-screen but using insets to layout inside 25279 * of the screen decorations, these are the current insets for the 25280 * actual visible parts of the window. 25281 */ 25282 final Rect mVisibleInsets = new Rect(); 25283 25284 /** 25285 * For windows that are full-screen but using insets to layout inside 25286 * of the screen decorations, these are the current insets for the 25287 * stable system windows. 25288 */ 25289 final Rect mStableInsets = new Rect(); 25290 25291 /** 25292 * For windows that include areas that are not covered by real surface these are the outsets 25293 * for real surface. 25294 */ 25295 final Rect mOutsets = new Rect(); 25296 25297 /** 25298 * In multi-window we force show the navigation bar. Because we don't want that the surface 25299 * size changes in this mode, we instead have a flag whether the navigation bar size should 25300 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 25301 */ 25302 boolean mAlwaysConsumeNavBar; 25303 25304 /** 25305 * The internal insets given by this window. This value is 25306 * supplied by the client (through 25307 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 25308 * be given to the window manager when changed to be used in laying 25309 * out windows behind it. 25310 */ 25311 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 25312 = new ViewTreeObserver.InternalInsetsInfo(); 25313 25314 /** 25315 * Set to true when mGivenInternalInsets is non-empty. 25316 */ 25317 boolean mHasNonEmptyGivenInternalInsets; 25318 25319 /** 25320 * All views in the window's hierarchy that serve as scroll containers, 25321 * used to determine if the window can be resized or must be panned 25322 * to adjust for a soft input area. 25323 */ 25324 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 25325 25326 final KeyEvent.DispatcherState mKeyDispatchState 25327 = new KeyEvent.DispatcherState(); 25328 25329 /** 25330 * Indicates whether the view's window currently has the focus. 25331 */ 25332 boolean mHasWindowFocus; 25333 25334 /** 25335 * The current visibility of the window. 25336 */ 25337 int mWindowVisibility; 25338 25339 /** 25340 * Indicates the time at which drawing started to occur. 25341 */ 25342 long mDrawingTime; 25343 25344 /** 25345 * Indicates whether or not ignoring the DIRTY_MASK flags. 25346 */ 25347 boolean mIgnoreDirtyState; 25348 25349 /** 25350 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 25351 * to avoid clearing that flag prematurely. 25352 */ 25353 boolean mSetIgnoreDirtyState = false; 25354 25355 /** 25356 * Indicates whether the view's window is currently in touch mode. 25357 */ 25358 boolean mInTouchMode; 25359 25360 /** 25361 * Indicates whether the view has requested unbuffered input dispatching for the current 25362 * event stream. 25363 */ 25364 boolean mUnbufferedDispatchRequested; 25365 25366 /** 25367 * Indicates that ViewAncestor should trigger a global layout change 25368 * the next time it performs a traversal 25369 */ 25370 boolean mRecomputeGlobalAttributes; 25371 25372 /** 25373 * Always report new attributes at next traversal. 25374 */ 25375 boolean mForceReportNewAttributes; 25376 25377 /** 25378 * Set during a traveral if any views want to keep the screen on. 25379 */ 25380 boolean mKeepScreenOn; 25381 25382 /** 25383 * Set during a traveral if the light center needs to be updated. 25384 */ 25385 boolean mNeedsUpdateLightCenter; 25386 25387 /** 25388 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 25389 */ 25390 int mSystemUiVisibility; 25391 25392 /** 25393 * Hack to force certain system UI visibility flags to be cleared. 25394 */ 25395 int mDisabledSystemUiVisibility; 25396 25397 /** 25398 * Last global system UI visibility reported by the window manager. 25399 */ 25400 int mGlobalSystemUiVisibility = -1; 25401 25402 /** 25403 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 25404 * attached. 25405 */ 25406 boolean mHasSystemUiListeners; 25407 25408 /** 25409 * Set if the window has requested to extend into the overscan region 25410 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 25411 */ 25412 boolean mOverscanRequested; 25413 25414 /** 25415 * Set if the visibility of any views has changed. 25416 */ 25417 boolean mViewVisibilityChanged; 25418 25419 /** 25420 * Set to true if a view has been scrolled. 25421 */ 25422 boolean mViewScrollChanged; 25423 25424 /** 25425 * Set to true if high contrast mode enabled 25426 */ 25427 boolean mHighContrastText; 25428 25429 /** 25430 * Set to true if a pointer event is currently being handled. 25431 */ 25432 boolean mHandlingPointerEvent; 25433 25434 /** 25435 * Global to the view hierarchy used as a temporary for dealing with 25436 * x/y points in the transparent region computations. 25437 */ 25438 final int[] mTransparentLocation = new int[2]; 25439 25440 /** 25441 * Global to the view hierarchy used as a temporary for dealing with 25442 * x/y points in the ViewGroup.invalidateChild implementation. 25443 */ 25444 final int[] mInvalidateChildLocation = new int[2]; 25445 25446 /** 25447 * Global to the view hierarchy used as a temporary for dealing with 25448 * computing absolute on-screen location. 25449 */ 25450 final int[] mTmpLocation = new int[2]; 25451 25452 /** 25453 * Global to the view hierarchy used as a temporary for dealing with 25454 * x/y location when view is transformed. 25455 */ 25456 final float[] mTmpTransformLocation = new float[2]; 25457 25458 /** 25459 * The view tree observer used to dispatch global events like 25460 * layout, pre-draw, touch mode change, etc. 25461 */ 25462 final ViewTreeObserver mTreeObserver; 25463 25464 /** 25465 * A Canvas used by the view hierarchy to perform bitmap caching. 25466 */ 25467 Canvas mCanvas; 25468 25469 /** 25470 * The view root impl. 25471 */ 25472 final ViewRootImpl mViewRootImpl; 25473 25474 /** 25475 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 25476 * handler can be used to pump events in the UI events queue. 25477 */ 25478 final Handler mHandler; 25479 25480 /** 25481 * Temporary for use in computing invalidate rectangles while 25482 * calling up the hierarchy. 25483 */ 25484 final Rect mTmpInvalRect = new Rect(); 25485 25486 /** 25487 * Temporary for use in computing hit areas with transformed views 25488 */ 25489 final RectF mTmpTransformRect = new RectF(); 25490 25491 /** 25492 * Temporary for use in computing hit areas with transformed views 25493 */ 25494 final RectF mTmpTransformRect1 = new RectF(); 25495 25496 /** 25497 * Temporary list of rectanges. 25498 */ 25499 final List<RectF> mTmpRectList = new ArrayList<>(); 25500 25501 /** 25502 * Temporary for use in transforming invalidation rect 25503 */ 25504 final Matrix mTmpMatrix = new Matrix(); 25505 25506 /** 25507 * Temporary for use in transforming invalidation rect 25508 */ 25509 final Transformation mTmpTransformation = new Transformation(); 25510 25511 /** 25512 * Temporary for use in querying outlines from OutlineProviders 25513 */ 25514 final Outline mTmpOutline = new Outline(); 25515 25516 /** 25517 * Temporary list for use in collecting focusable descendents of a view. 25518 */ 25519 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 25520 25521 /** 25522 * The id of the window for accessibility purposes. 25523 */ 25524 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 25525 25526 /** 25527 * Flags related to accessibility processing. 25528 * 25529 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 25530 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 25531 */ 25532 int mAccessibilityFetchFlags; 25533 25534 /** 25535 * The drawable for highlighting accessibility focus. 25536 */ 25537 Drawable mAccessibilityFocusDrawable; 25538 25539 /** 25540 * The drawable for highlighting autofilled views. 25541 * 25542 * @see #isAutofilled() 25543 */ 25544 Drawable mAutofilledDrawable; 25545 25546 /** 25547 * Show where the margins, bounds and layout bounds are for each view. 25548 */ 25549 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 25550 25551 /** 25552 * Point used to compute visible regions. 25553 */ 25554 final Point mPoint = new Point(); 25555 25556 /** 25557 * Used to track which View originated a requestLayout() call, used when 25558 * requestLayout() is called during layout. 25559 */ 25560 View mViewRequestingLayout; 25561 25562 /** 25563 * Used to track views that need (at least) a partial relayout at their current size 25564 * during the next traversal. 25565 */ 25566 List<View> mPartialLayoutViews = new ArrayList<>(); 25567 25568 /** 25569 * Swapped with mPartialLayoutViews during layout to avoid concurrent 25570 * modification. Lazily assigned during ViewRootImpl layout. 25571 */ 25572 List<View> mEmptyPartialLayoutViews; 25573 25574 /** 25575 * Used to track the identity of the current drag operation. 25576 */ 25577 IBinder mDragToken; 25578 25579 /** 25580 * The drag shadow surface for the current drag operation. 25581 */ 25582 public Surface mDragSurface; 25583 25584 25585 /** 25586 * The view that currently has a tooltip displayed. 25587 */ 25588 View mTooltipHost; 25589 25590 /** 25591 * Creates a new set of attachment information with the specified 25592 * events handler and thread. 25593 * 25594 * @param handler the events handler the view must use 25595 */ 25596 AttachInfo(IWindowSession session, IWindow window, Display display, 25597 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 25598 Context context) { 25599 mSession = session; 25600 mWindow = window; 25601 mWindowToken = window.asBinder(); 25602 mDisplay = display; 25603 mViewRootImpl = viewRootImpl; 25604 mHandler = handler; 25605 mRootCallbacks = effectPlayer; 25606 mTreeObserver = new ViewTreeObserver(context); 25607 } 25608 } 25609 25610 /** 25611 * <p>ScrollabilityCache holds various fields used by a View when scrolling 25612 * is supported. This avoids keeping too many unused fields in most 25613 * instances of View.</p> 25614 */ 25615 private static class ScrollabilityCache implements Runnable { 25616 25617 /** 25618 * Scrollbars are not visible 25619 */ 25620 public static final int OFF = 0; 25621 25622 /** 25623 * Scrollbars are visible 25624 */ 25625 public static final int ON = 1; 25626 25627 /** 25628 * Scrollbars are fading away 25629 */ 25630 public static final int FADING = 2; 25631 25632 public boolean fadeScrollBars; 25633 25634 public int fadingEdgeLength; 25635 public int scrollBarDefaultDelayBeforeFade; 25636 public int scrollBarFadeDuration; 25637 25638 public int scrollBarSize; 25639 public int scrollBarMinTouchTarget; 25640 public ScrollBarDrawable scrollBar; 25641 public float[] interpolatorValues; 25642 public View host; 25643 25644 public final Paint paint; 25645 public final Matrix matrix; 25646 public Shader shader; 25647 25648 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 25649 25650 private static final float[] OPAQUE = { 255 }; 25651 private static final float[] TRANSPARENT = { 0.0f }; 25652 25653 /** 25654 * When fading should start. This time moves into the future every time 25655 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 25656 */ 25657 public long fadeStartTime; 25658 25659 25660 /** 25661 * The current state of the scrollbars: ON, OFF, or FADING 25662 */ 25663 public int state = OFF; 25664 25665 private int mLastColor; 25666 25667 public final Rect mScrollBarBounds = new Rect(); 25668 public final Rect mScrollBarTouchBounds = new Rect(); 25669 25670 public static final int NOT_DRAGGING = 0; 25671 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 25672 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 25673 public int mScrollBarDraggingState = NOT_DRAGGING; 25674 25675 public float mScrollBarDraggingPos = 0; 25676 25677 public ScrollabilityCache(ViewConfiguration configuration, View host) { 25678 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 25679 scrollBarSize = configuration.getScaledScrollBarSize(); 25680 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 25681 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 25682 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 25683 25684 paint = new Paint(); 25685 matrix = new Matrix(); 25686 // use use a height of 1, and then wack the matrix each time we 25687 // actually use it. 25688 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25689 paint.setShader(shader); 25690 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25691 25692 this.host = host; 25693 } 25694 25695 public void setFadeColor(int color) { 25696 if (color != mLastColor) { 25697 mLastColor = color; 25698 25699 if (color != 0) { 25700 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 25701 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 25702 paint.setShader(shader); 25703 // Restore the default transfer mode (src_over) 25704 paint.setXfermode(null); 25705 } else { 25706 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 25707 paint.setShader(shader); 25708 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 25709 } 25710 } 25711 } 25712 25713 public void run() { 25714 long now = AnimationUtils.currentAnimationTimeMillis(); 25715 if (now >= fadeStartTime) { 25716 25717 // the animation fades the scrollbars out by changing 25718 // the opacity (alpha) from fully opaque to fully 25719 // transparent 25720 int nextFrame = (int) now; 25721 int framesCount = 0; 25722 25723 Interpolator interpolator = scrollBarInterpolator; 25724 25725 // Start opaque 25726 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 25727 25728 // End transparent 25729 nextFrame += scrollBarFadeDuration; 25730 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 25731 25732 state = FADING; 25733 25734 // Kick off the fade animation 25735 host.invalidate(true); 25736 } 25737 } 25738 } 25739 25740 /** 25741 * Resuable callback for sending 25742 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 25743 */ 25744 private class SendViewScrolledAccessibilityEvent implements Runnable { 25745 public volatile boolean mIsPending; 25746 25747 public void run() { 25748 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 25749 mIsPending = false; 25750 } 25751 } 25752 25753 /** 25754 * <p> 25755 * This class represents a delegate that can be registered in a {@link View} 25756 * to enhance accessibility support via composition rather via inheritance. 25757 * It is specifically targeted to widget developers that extend basic View 25758 * classes i.e. classes in package android.view, that would like their 25759 * applications to be backwards compatible. 25760 * </p> 25761 * <div class="special reference"> 25762 * <h3>Developer Guides</h3> 25763 * <p>For more information about making applications accessible, read the 25764 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 25765 * developer guide.</p> 25766 * </div> 25767 * <p> 25768 * A scenario in which a developer would like to use an accessibility delegate 25769 * is overriding a method introduced in a later API version than the minimal API 25770 * version supported by the application. For example, the method 25771 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 25772 * in API version 4 when the accessibility APIs were first introduced. If a 25773 * developer would like his application to run on API version 4 devices (assuming 25774 * all other APIs used by the application are version 4 or lower) and take advantage 25775 * of this method, instead of overriding the method which would break the application's 25776 * backwards compatibility, he can override the corresponding method in this 25777 * delegate and register the delegate in the target View if the API version of 25778 * the system is high enough, i.e. the API version is the same as or higher than the API 25779 * version that introduced 25780 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 25781 * </p> 25782 * <p> 25783 * Here is an example implementation: 25784 * </p> 25785 * <code><pre><p> 25786 * if (Build.VERSION.SDK_INT >= 14) { 25787 * // If the API version is equal of higher than the version in 25788 * // which onInitializeAccessibilityNodeInfo was introduced we 25789 * // register a delegate with a customized implementation. 25790 * View view = findViewById(R.id.view_id); 25791 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 25792 * public void onInitializeAccessibilityNodeInfo(View host, 25793 * AccessibilityNodeInfo info) { 25794 * // Let the default implementation populate the info. 25795 * super.onInitializeAccessibilityNodeInfo(host, info); 25796 * // Set some other information. 25797 * info.setEnabled(host.isEnabled()); 25798 * } 25799 * }); 25800 * } 25801 * </code></pre></p> 25802 * <p> 25803 * This delegate contains methods that correspond to the accessibility methods 25804 * in View. If a delegate has been specified the implementation in View hands 25805 * off handling to the corresponding method in this delegate. The default 25806 * implementation the delegate methods behaves exactly as the corresponding 25807 * method in View for the case of no accessibility delegate been set. Hence, 25808 * to customize the behavior of a View method, clients can override only the 25809 * corresponding delegate method without altering the behavior of the rest 25810 * accessibility related methods of the host view. 25811 * </p> 25812 * <p> 25813 * <strong>Note:</strong> On platform versions prior to 25814 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 25815 * views in the {@code android.widget.*} package are called <i>before</i> 25816 * host methods. This prevents certain properties such as class name from 25817 * being modified by overriding 25818 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 25819 * as any changes will be overwritten by the host class. 25820 * <p> 25821 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 25822 * methods are called <i>after</i> host methods, which all properties to be 25823 * modified without being overwritten by the host class. 25824 */ 25825 public static class AccessibilityDelegate { 25826 25827 /** 25828 * Sends an accessibility event of the given type. If accessibility is not 25829 * enabled this method has no effect. 25830 * <p> 25831 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 25832 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 25833 * been set. 25834 * </p> 25835 * 25836 * @param host The View hosting the delegate. 25837 * @param eventType The type of the event to send. 25838 * 25839 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 25840 */ 25841 public void sendAccessibilityEvent(View host, int eventType) { 25842 host.sendAccessibilityEventInternal(eventType); 25843 } 25844 25845 /** 25846 * Performs the specified accessibility action on the view. For 25847 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 25848 * <p> 25849 * The default implementation behaves as 25850 * {@link View#performAccessibilityAction(int, Bundle) 25851 * View#performAccessibilityAction(int, Bundle)} for the case of 25852 * no accessibility delegate been set. 25853 * </p> 25854 * 25855 * @param action The action to perform. 25856 * @return Whether the action was performed. 25857 * 25858 * @see View#performAccessibilityAction(int, Bundle) 25859 * View#performAccessibilityAction(int, Bundle) 25860 */ 25861 public boolean performAccessibilityAction(View host, int action, Bundle args) { 25862 return host.performAccessibilityActionInternal(action, args); 25863 } 25864 25865 /** 25866 * Sends an accessibility event. This method behaves exactly as 25867 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 25868 * empty {@link AccessibilityEvent} and does not perform a check whether 25869 * accessibility is enabled. 25870 * <p> 25871 * The default implementation behaves as 25872 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25873 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 25874 * the case of no accessibility delegate been set. 25875 * </p> 25876 * 25877 * @param host The View hosting the delegate. 25878 * @param event The event to send. 25879 * 25880 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25881 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 25882 */ 25883 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 25884 host.sendAccessibilityEventUncheckedInternal(event); 25885 } 25886 25887 /** 25888 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 25889 * to its children for adding their text content to the event. 25890 * <p> 25891 * The default implementation behaves as 25892 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25893 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 25894 * the case of no accessibility delegate been set. 25895 * </p> 25896 * 25897 * @param host The View hosting the delegate. 25898 * @param event The event. 25899 * @return True if the event population was completed. 25900 * 25901 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25902 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 25903 */ 25904 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25905 return host.dispatchPopulateAccessibilityEventInternal(event); 25906 } 25907 25908 /** 25909 * Gives a chance to the host View to populate the accessibility event with its 25910 * text content. 25911 * <p> 25912 * The default implementation behaves as 25913 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 25914 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 25915 * the case of no accessibility delegate been set. 25916 * </p> 25917 * 25918 * @param host The View hosting the delegate. 25919 * @param event The accessibility event which to populate. 25920 * 25921 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 25922 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 25923 */ 25924 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 25925 host.onPopulateAccessibilityEventInternal(event); 25926 } 25927 25928 /** 25929 * Initializes an {@link AccessibilityEvent} with information about the 25930 * the host View which is the event source. 25931 * <p> 25932 * The default implementation behaves as 25933 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 25934 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 25935 * the case of no accessibility delegate been set. 25936 * </p> 25937 * 25938 * @param host The View hosting the delegate. 25939 * @param event The event to initialize. 25940 * 25941 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 25942 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 25943 */ 25944 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 25945 host.onInitializeAccessibilityEventInternal(event); 25946 } 25947 25948 /** 25949 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 25950 * <p> 25951 * The default implementation behaves as 25952 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25953 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 25954 * the case of no accessibility delegate been set. 25955 * </p> 25956 * 25957 * @param host The View hosting the delegate. 25958 * @param info The instance to initialize. 25959 * 25960 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25961 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 25962 */ 25963 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 25964 host.onInitializeAccessibilityNodeInfoInternal(info); 25965 } 25966 25967 /** 25968 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 25969 * additional data. 25970 * <p> 25971 * This method only needs to be implemented if the View offers to provide additional data. 25972 * </p> 25973 * <p> 25974 * The default implementation behaves as 25975 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 25976 * for the case where no accessibility delegate is set. 25977 * </p> 25978 * 25979 * @param host The View hosting the delegate. Never {@code null}. 25980 * @param info The info to which to add the extra data. Never {@code null}. 25981 * @param extraDataKey A key specifying the type of extra data to add to the info. The 25982 * extra data should be added to the {@link Bundle} returned by 25983 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 25984 * {@code null}. 25985 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 25986 * May be {@code null} if the if the service provided no arguments. 25987 * 25988 * @see AccessibilityNodeInfo#setExtraAvailableData 25989 */ 25990 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 25991 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 25992 @Nullable Bundle arguments) { 25993 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 25994 } 25995 25996 /** 25997 * Called when a child of the host View has requested sending an 25998 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 25999 * to augment the event. 26000 * <p> 26001 * The default implementation behaves as 26002 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 26003 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 26004 * the case of no accessibility delegate been set. 26005 * </p> 26006 * 26007 * @param host The View hosting the delegate. 26008 * @param child The child which requests sending the event. 26009 * @param event The event to be sent. 26010 * @return True if the event should be sent 26011 * 26012 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 26013 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 26014 */ 26015 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 26016 AccessibilityEvent event) { 26017 return host.onRequestSendAccessibilityEventInternal(child, event); 26018 } 26019 26020 /** 26021 * Gets the provider for managing a virtual view hierarchy rooted at this View 26022 * and reported to {@link android.accessibilityservice.AccessibilityService}s 26023 * that explore the window content. 26024 * <p> 26025 * The default implementation behaves as 26026 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 26027 * the case of no accessibility delegate been set. 26028 * </p> 26029 * 26030 * @return The provider. 26031 * 26032 * @see AccessibilityNodeProvider 26033 */ 26034 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 26035 return null; 26036 } 26037 26038 /** 26039 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 26040 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 26041 * This method is responsible for obtaining an accessibility node info from a 26042 * pool of reusable instances and calling 26043 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 26044 * view to initialize the former. 26045 * <p> 26046 * <strong>Note:</strong> The client is responsible for recycling the obtained 26047 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 26048 * creation. 26049 * </p> 26050 * <p> 26051 * The default implementation behaves as 26052 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 26053 * the case of no accessibility delegate been set. 26054 * </p> 26055 * @return A populated {@link AccessibilityNodeInfo}. 26056 * 26057 * @see AccessibilityNodeInfo 26058 * 26059 * @hide 26060 */ 26061 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 26062 return host.createAccessibilityNodeInfoInternal(); 26063 } 26064 } 26065 26066 private static class MatchIdPredicate implements Predicate<View> { 26067 public int mId; 26068 26069 @Override 26070 public boolean test(View view) { 26071 return (view.mID == mId); 26072 } 26073 } 26074 26075 private static class MatchLabelForPredicate implements Predicate<View> { 26076 private int mLabeledId; 26077 26078 @Override 26079 public boolean test(View view) { 26080 return (view.mLabelForId == mLabeledId); 26081 } 26082 } 26083 26084 /** 26085 * Dump all private flags in readable format, useful for documentation and 26086 * sanity checking. 26087 */ 26088 private static void dumpFlags() { 26089 final HashMap<String, String> found = Maps.newHashMap(); 26090 try { 26091 for (Field field : View.class.getDeclaredFields()) { 26092 final int modifiers = field.getModifiers(); 26093 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 26094 if (field.getType().equals(int.class)) { 26095 final int value = field.getInt(null); 26096 dumpFlag(found, field.getName(), value); 26097 } else if (field.getType().equals(int[].class)) { 26098 final int[] values = (int[]) field.get(null); 26099 for (int i = 0; i < values.length; i++) { 26100 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 26101 } 26102 } 26103 } 26104 } 26105 } catch (IllegalAccessException e) { 26106 throw new RuntimeException(e); 26107 } 26108 26109 final ArrayList<String> keys = Lists.newArrayList(); 26110 keys.addAll(found.keySet()); 26111 Collections.sort(keys); 26112 for (String key : keys) { 26113 Log.d(VIEW_LOG_TAG, found.get(key)); 26114 } 26115 } 26116 26117 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 26118 // Sort flags by prefix, then by bits, always keeping unique keys 26119 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 26120 final int prefix = name.indexOf('_'); 26121 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 26122 final String output = bits + " " + name; 26123 found.put(key, output); 26124 } 26125 26126 /** {@hide} */ 26127 public void encode(@NonNull ViewHierarchyEncoder stream) { 26128 stream.beginObject(this); 26129 encodeProperties(stream); 26130 stream.endObject(); 26131 } 26132 26133 /** {@hide} */ 26134 @CallSuper 26135 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 26136 Object resolveId = ViewDebug.resolveId(getContext(), mID); 26137 if (resolveId instanceof String) { 26138 stream.addProperty("id", (String) resolveId); 26139 } else { 26140 stream.addProperty("id", mID); 26141 } 26142 26143 stream.addProperty("misc:transformation.alpha", 26144 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 26145 stream.addProperty("misc:transitionName", getTransitionName()); 26146 26147 // layout 26148 stream.addProperty("layout:left", mLeft); 26149 stream.addProperty("layout:right", mRight); 26150 stream.addProperty("layout:top", mTop); 26151 stream.addProperty("layout:bottom", mBottom); 26152 stream.addProperty("layout:width", getWidth()); 26153 stream.addProperty("layout:height", getHeight()); 26154 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 26155 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 26156 stream.addProperty("layout:hasTransientState", hasTransientState()); 26157 stream.addProperty("layout:baseline", getBaseline()); 26158 26159 // layout params 26160 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 26161 if (layoutParams != null) { 26162 stream.addPropertyKey("layoutParams"); 26163 layoutParams.encode(stream); 26164 } 26165 26166 // scrolling 26167 stream.addProperty("scrolling:scrollX", mScrollX); 26168 stream.addProperty("scrolling:scrollY", mScrollY); 26169 26170 // padding 26171 stream.addProperty("padding:paddingLeft", mPaddingLeft); 26172 stream.addProperty("padding:paddingRight", mPaddingRight); 26173 stream.addProperty("padding:paddingTop", mPaddingTop); 26174 stream.addProperty("padding:paddingBottom", mPaddingBottom); 26175 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 26176 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 26177 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 26178 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 26179 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 26180 26181 // measurement 26182 stream.addProperty("measurement:minHeight", mMinHeight); 26183 stream.addProperty("measurement:minWidth", mMinWidth); 26184 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 26185 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 26186 26187 // drawing 26188 stream.addProperty("drawing:elevation", getElevation()); 26189 stream.addProperty("drawing:translationX", getTranslationX()); 26190 stream.addProperty("drawing:translationY", getTranslationY()); 26191 stream.addProperty("drawing:translationZ", getTranslationZ()); 26192 stream.addProperty("drawing:rotation", getRotation()); 26193 stream.addProperty("drawing:rotationX", getRotationX()); 26194 stream.addProperty("drawing:rotationY", getRotationY()); 26195 stream.addProperty("drawing:scaleX", getScaleX()); 26196 stream.addProperty("drawing:scaleY", getScaleY()); 26197 stream.addProperty("drawing:pivotX", getPivotX()); 26198 stream.addProperty("drawing:pivotY", getPivotY()); 26199 stream.addProperty("drawing:opaque", isOpaque()); 26200 stream.addProperty("drawing:alpha", getAlpha()); 26201 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 26202 stream.addProperty("drawing:shadow", hasShadow()); 26203 stream.addProperty("drawing:solidColor", getSolidColor()); 26204 stream.addProperty("drawing:layerType", mLayerType); 26205 stream.addProperty("drawing:willNotDraw", willNotDraw()); 26206 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 26207 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 26208 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 26209 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 26210 26211 // focus 26212 stream.addProperty("focus:hasFocus", hasFocus()); 26213 stream.addProperty("focus:isFocused", isFocused()); 26214 stream.addProperty("focus:focusable", getFocusable()); 26215 stream.addProperty("focus:isFocusable", isFocusable()); 26216 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 26217 26218 stream.addProperty("misc:clickable", isClickable()); 26219 stream.addProperty("misc:pressed", isPressed()); 26220 stream.addProperty("misc:selected", isSelected()); 26221 stream.addProperty("misc:touchMode", isInTouchMode()); 26222 stream.addProperty("misc:hovered", isHovered()); 26223 stream.addProperty("misc:activated", isActivated()); 26224 26225 stream.addProperty("misc:visibility", getVisibility()); 26226 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 26227 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 26228 26229 stream.addProperty("misc:enabled", isEnabled()); 26230 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 26231 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 26232 26233 // theme attributes 26234 Resources.Theme theme = getContext().getTheme(); 26235 if (theme != null) { 26236 stream.addPropertyKey("theme"); 26237 theme.encode(stream); 26238 } 26239 26240 // view attribute information 26241 int n = mAttributes != null ? mAttributes.length : 0; 26242 stream.addProperty("meta:__attrCount__", n/2); 26243 for (int i = 0; i < n; i += 2) { 26244 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 26245 } 26246 26247 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 26248 26249 // text 26250 stream.addProperty("text:textDirection", getTextDirection()); 26251 stream.addProperty("text:textAlignment", getTextAlignment()); 26252 26253 // accessibility 26254 CharSequence contentDescription = getContentDescription(); 26255 stream.addProperty("accessibility:contentDescription", 26256 contentDescription == null ? "" : contentDescription.toString()); 26257 stream.addProperty("accessibility:labelFor", getLabelFor()); 26258 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 26259 } 26260 26261 /** 26262 * Determine if this view is rendered on a round wearable device and is the main view 26263 * on the screen. 26264 */ 26265 boolean shouldDrawRoundScrollbar() { 26266 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 26267 return false; 26268 } 26269 26270 final View rootView = getRootView(); 26271 final WindowInsets insets = getRootWindowInsets(); 26272 26273 int height = getHeight(); 26274 int width = getWidth(); 26275 int displayHeight = rootView.getHeight(); 26276 int displayWidth = rootView.getWidth(); 26277 26278 if (height != displayHeight || width != displayWidth) { 26279 return false; 26280 } 26281 26282 getLocationInWindow(mAttachInfo.mTmpLocation); 26283 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 26284 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 26285 } 26286 26287 /** 26288 * Sets the tooltip text which will be displayed in a small popup next to the view. 26289 * <p> 26290 * The tooltip will be displayed: 26291 * <ul> 26292 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 26293 * menu). </li> 26294 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 26295 * </ul> 26296 * <p> 26297 * <strong>Note:</strong> Do not override this method, as it will have no 26298 * effect on the text displayed in the tooltip. 26299 * 26300 * @param tooltipText the tooltip text, or null if no tooltip is required 26301 * @see #getTooltipText() 26302 * @attr ref android.R.styleable#View_tooltipText 26303 */ 26304 public void setTooltipText(@Nullable CharSequence tooltipText) { 26305 if (TextUtils.isEmpty(tooltipText)) { 26306 setFlags(0, TOOLTIP); 26307 hideTooltip(); 26308 mTooltipInfo = null; 26309 } else { 26310 setFlags(TOOLTIP, TOOLTIP); 26311 if (mTooltipInfo == null) { 26312 mTooltipInfo = new TooltipInfo(); 26313 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 26314 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 26315 } 26316 mTooltipInfo.mTooltipText = tooltipText; 26317 } 26318 } 26319 26320 /** 26321 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26322 */ 26323 public void setTooltip(@Nullable CharSequence tooltipText) { 26324 setTooltipText(tooltipText); 26325 } 26326 26327 /** 26328 * Returns the view's tooltip text. 26329 * 26330 * <strong>Note:</strong> Do not override this method, as it will have no 26331 * effect on the text displayed in the tooltip. You must call 26332 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 26333 * 26334 * @return the tooltip text 26335 * @see #setTooltipText(CharSequence) 26336 * @attr ref android.R.styleable#View_tooltipText 26337 */ 26338 @Nullable 26339 public CharSequence getTooltipText() { 26340 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 26341 } 26342 26343 /** 26344 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 26345 */ 26346 @Nullable 26347 public CharSequence getTooltip() { 26348 return getTooltipText(); 26349 } 26350 26351 private boolean showTooltip(int x, int y, boolean fromLongClick) { 26352 if (mAttachInfo == null || mTooltipInfo == null) { 26353 return false; 26354 } 26355 if ((mViewFlags & ENABLED_MASK) != ENABLED) { 26356 return false; 26357 } 26358 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 26359 return false; 26360 } 26361 hideTooltip(); 26362 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 26363 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 26364 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 26365 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 26366 mAttachInfo.mTooltipHost = this; 26367 return true; 26368 } 26369 26370 void hideTooltip() { 26371 if (mTooltipInfo == null) { 26372 return; 26373 } 26374 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26375 if (mTooltipInfo.mTooltipPopup == null) { 26376 return; 26377 } 26378 mTooltipInfo.mTooltipPopup.hide(); 26379 mTooltipInfo.mTooltipPopup = null; 26380 mTooltipInfo.mTooltipFromLongClick = false; 26381 if (mAttachInfo != null) { 26382 mAttachInfo.mTooltipHost = null; 26383 } 26384 } 26385 26386 private boolean showLongClickTooltip(int x, int y) { 26387 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26388 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26389 return showTooltip(x, y, true); 26390 } 26391 26392 private void showHoverTooltip() { 26393 showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 26394 } 26395 26396 boolean dispatchTooltipHoverEvent(MotionEvent event) { 26397 if (mTooltipInfo == null) { 26398 return false; 26399 } 26400 switch(event.getAction()) { 26401 case MotionEvent.ACTION_HOVER_MOVE: 26402 if ((mViewFlags & TOOLTIP) != TOOLTIP || (mViewFlags & ENABLED_MASK) != ENABLED) { 26403 break; 26404 } 26405 if (!mTooltipInfo.mTooltipFromLongClick) { 26406 if (mTooltipInfo.mTooltipPopup == null) { 26407 // Schedule showing the tooltip after a timeout. 26408 mTooltipInfo.mAnchorX = (int) event.getX(); 26409 mTooltipInfo.mAnchorY = (int) event.getY(); 26410 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 26411 postDelayed(mTooltipInfo.mShowTooltipRunnable, 26412 ViewConfiguration.getHoverTooltipShowTimeout()); 26413 } 26414 26415 // Hide hover-triggered tooltip after a period of inactivity. 26416 // Match the timeout used by NativeInputManager to hide the mouse pointer 26417 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 26418 final int timeout; 26419 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 26420 == SYSTEM_UI_FLAG_LOW_PROFILE) { 26421 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 26422 } else { 26423 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 26424 } 26425 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26426 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 26427 } 26428 return true; 26429 26430 case MotionEvent.ACTION_HOVER_EXIT: 26431 if (!mTooltipInfo.mTooltipFromLongClick) { 26432 hideTooltip(); 26433 } 26434 break; 26435 } 26436 return false; 26437 } 26438 26439 void handleTooltipKey(KeyEvent event) { 26440 switch (event.getAction()) { 26441 case KeyEvent.ACTION_DOWN: 26442 if (event.getRepeatCount() == 0) { 26443 hideTooltip(); 26444 } 26445 break; 26446 26447 case KeyEvent.ACTION_UP: 26448 handleTooltipUp(); 26449 break; 26450 } 26451 } 26452 26453 private void handleTooltipUp() { 26454 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26455 return; 26456 } 26457 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 26458 postDelayed(mTooltipInfo.mHideTooltipRunnable, 26459 ViewConfiguration.getLongPressTooltipHideTimeout()); 26460 } 26461 26462 private int getFocusableAttribute(TypedArray attributes) { 26463 TypedValue val = new TypedValue(); 26464 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 26465 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 26466 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 26467 } else { 26468 return val.data; 26469 } 26470 } else { 26471 return FOCUSABLE_AUTO; 26472 } 26473 } 26474 26475 /** 26476 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 26477 * is not showing. 26478 * @hide 26479 */ 26480 @TestApi 26481 public View getTooltipView() { 26482 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 26483 return null; 26484 } 26485 return mTooltipInfo.mTooltipPopup.getContentView(); 26486 } 26487 } 26488