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 android.animation.AnimatorInflater; 20 import android.animation.StateListAnimator; 21 import android.annotation.CallSuper; 22 import android.annotation.ColorInt; 23 import android.annotation.DrawableRes; 24 import android.annotation.FloatRange; 25 import android.annotation.IdRes; 26 import android.annotation.IntDef; 27 import android.annotation.IntRange; 28 import android.annotation.LayoutRes; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.annotation.Size; 32 import android.annotation.UiThread; 33 import android.content.ClipData; 34 import android.content.Context; 35 import android.content.ContextWrapper; 36 import android.content.Intent; 37 import android.content.res.ColorStateList; 38 import android.content.res.Configuration; 39 import android.content.res.Resources; 40 import android.content.res.TypedArray; 41 import android.graphics.Bitmap; 42 import android.graphics.Canvas; 43 import android.graphics.Insets; 44 import android.graphics.Interpolator; 45 import android.graphics.LinearGradient; 46 import android.graphics.Matrix; 47 import android.graphics.Outline; 48 import android.graphics.Paint; 49 import android.graphics.PixelFormat; 50 import android.graphics.Point; 51 import android.graphics.PorterDuff; 52 import android.graphics.PorterDuffXfermode; 53 import android.graphics.Rect; 54 import android.graphics.RectF; 55 import android.graphics.Region; 56 import android.graphics.Shader; 57 import android.graphics.drawable.ColorDrawable; 58 import android.graphics.drawable.Drawable; 59 import android.hardware.display.DisplayManagerGlobal; 60 import android.os.Build.VERSION_CODES; 61 import android.os.Bundle; 62 import android.os.Handler; 63 import android.os.IBinder; 64 import android.os.Parcel; 65 import android.os.Parcelable; 66 import android.os.RemoteException; 67 import android.os.SystemClock; 68 import android.os.SystemProperties; 69 import android.os.Trace; 70 import android.text.TextUtils; 71 import android.util.AttributeSet; 72 import android.util.FloatProperty; 73 import android.util.LayoutDirection; 74 import android.util.Log; 75 import android.util.LongSparseLongArray; 76 import android.util.Pools.SynchronizedPool; 77 import android.util.Property; 78 import android.util.SparseArray; 79 import android.util.StateSet; 80 import android.util.SuperNotCalledException; 81 import android.util.TypedValue; 82 import android.view.ContextMenu.ContextMenuInfo; 83 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 84 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 85 import android.view.AccessibilityIterators.TextSegmentIterator; 86 import android.view.AccessibilityIterators.WordTextSegmentIterator; 87 import android.view.accessibility.AccessibilityEvent; 88 import android.view.accessibility.AccessibilityEventSource; 89 import android.view.accessibility.AccessibilityManager; 90 import android.view.accessibility.AccessibilityNodeInfo; 91 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 92 import android.view.accessibility.AccessibilityNodeProvider; 93 import android.view.animation.Animation; 94 import android.view.animation.AnimationUtils; 95 import android.view.animation.Transformation; 96 import android.view.inputmethod.EditorInfo; 97 import android.view.inputmethod.InputConnection; 98 import android.view.inputmethod.InputMethodManager; 99 import android.widget.Checkable; 100 import android.widget.FrameLayout; 101 import android.widget.ScrollBarDrawable; 102 import static android.os.Build.VERSION_CODES.*; 103 import static java.lang.Math.max; 104 105 import com.android.internal.R; 106 import com.android.internal.util.Predicate; 107 import com.android.internal.view.menu.MenuBuilder; 108 import com.android.internal.widget.ScrollBarUtils; 109 import com.google.android.collect.Lists; 110 import com.google.android.collect.Maps; 111 112 import java.lang.NullPointerException; 113 import java.lang.annotation.Retention; 114 import java.lang.annotation.RetentionPolicy; 115 import java.lang.ref.WeakReference; 116 import java.lang.reflect.Field; 117 import java.lang.reflect.InvocationTargetException; 118 import java.lang.reflect.Method; 119 import java.lang.reflect.Modifier; 120 import java.util.ArrayList; 121 import java.util.Arrays; 122 import java.util.Collections; 123 import java.util.HashMap; 124 import java.util.List; 125 import java.util.Locale; 126 import java.util.Map; 127 import java.util.concurrent.CopyOnWriteArrayList; 128 import java.util.concurrent.atomic.AtomicInteger; 129 130 /** 131 * <p> 132 * This class represents the basic building block for user interface components. A View 133 * occupies a rectangular area on the screen and is responsible for drawing and 134 * event handling. View is the base class for <em>widgets</em>, which are 135 * used to create interactive UI components (buttons, text fields, etc.). The 136 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 137 * are invisible containers that hold other Views (or other ViewGroups) and define 138 * their layout properties. 139 * </p> 140 * 141 * <div class="special reference"> 142 * <h3>Developer Guides</h3> 143 * <p>For information about using this class to develop your application's user interface, 144 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 145 * </div> 146 * 147 * <a name="Using"></a> 148 * <h3>Using Views</h3> 149 * <p> 150 * All of the views in a window are arranged in a single tree. You can add views 151 * either from code or by specifying a tree of views in one or more XML layout 152 * files. There are many specialized subclasses of views that act as controls or 153 * are capable of displaying text, images, or other content. 154 * </p> 155 * <p> 156 * Once you have created a tree of views, there are typically a few types of 157 * common operations you may wish to perform: 158 * <ul> 159 * <li><strong>Set properties:</strong> for example setting the text of a 160 * {@link android.widget.TextView}. The available properties and the methods 161 * that set them will vary among the different subclasses of views. Note that 162 * properties that are known at build time can be set in the XML layout 163 * files.</li> 164 * <li><strong>Set focus:</strong> The framework will handle moving focus in 165 * response to user input. To force focus to a specific view, call 166 * {@link #requestFocus}.</li> 167 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 168 * that will be notified when something interesting happens to the view. For 169 * example, all views will let you set a listener to be notified when the view 170 * gains or loses focus. You can register such a listener using 171 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 172 * Other view subclasses offer more specialized listeners. For example, a Button 173 * exposes a listener to notify clients when the button is clicked.</li> 174 * <li><strong>Set visibility:</strong> You can hide or show views using 175 * {@link #setVisibility(int)}.</li> 176 * </ul> 177 * </p> 178 * <p><em> 179 * Note: The Android framework is responsible for measuring, laying out and 180 * drawing views. You should not call methods that perform these actions on 181 * views yourself unless you are actually implementing a 182 * {@link android.view.ViewGroup}. 183 * </em></p> 184 * 185 * <a name="Lifecycle"></a> 186 * <h3>Implementing a Custom View</h3> 187 * 188 * <p> 189 * To implement a custom view, you will usually begin by providing overrides for 190 * some of the standard methods that the framework calls on all views. You do 191 * not need to override all of these methods. In fact, you can start by just 192 * overriding {@link #onDraw(android.graphics.Canvas)}. 193 * <table border="2" width="85%" align="center" cellpadding="5"> 194 * <thead> 195 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 196 * </thead> 197 * 198 * <tbody> 199 * <tr> 200 * <td rowspan="2">Creation</td> 201 * <td>Constructors</td> 202 * <td>There is a form of the constructor that are called when the view 203 * is created from code and a form that is called when the view is 204 * inflated from a layout file. The second form should parse and apply 205 * any attributes defined in the layout file. 206 * </td> 207 * </tr> 208 * <tr> 209 * <td><code>{@link #onFinishInflate()}</code></td> 210 * <td>Called after a view and all of its children has been inflated 211 * from XML.</td> 212 * </tr> 213 * 214 * <tr> 215 * <td rowspan="3">Layout</td> 216 * <td><code>{@link #onMeasure(int, int)}</code></td> 217 * <td>Called to determine the size requirements for this view and all 218 * of its children. 219 * </td> 220 * </tr> 221 * <tr> 222 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 223 * <td>Called when this view should assign a size and position to all 224 * of its children. 225 * </td> 226 * </tr> 227 * <tr> 228 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 229 * <td>Called when the size of this view has changed. 230 * </td> 231 * </tr> 232 * 233 * <tr> 234 * <td>Drawing</td> 235 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 236 * <td>Called when the view should render its content. 237 * </td> 238 * </tr> 239 * 240 * <tr> 241 * <td rowspan="4">Event processing</td> 242 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 243 * <td>Called when a new hardware key event occurs. 244 * </td> 245 * </tr> 246 * <tr> 247 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 248 * <td>Called when a hardware key up event occurs. 249 * </td> 250 * </tr> 251 * <tr> 252 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 253 * <td>Called when a trackball motion event occurs. 254 * </td> 255 * </tr> 256 * <tr> 257 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 258 * <td>Called when a touch screen motion event occurs. 259 * </td> 260 * </tr> 261 * 262 * <tr> 263 * <td rowspan="2">Focus</td> 264 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 265 * <td>Called when the view gains or loses focus. 266 * </td> 267 * </tr> 268 * 269 * <tr> 270 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 271 * <td>Called when the window containing the view gains or loses focus. 272 * </td> 273 * </tr> 274 * 275 * <tr> 276 * <td rowspan="3">Attaching</td> 277 * <td><code>{@link #onAttachedToWindow()}</code></td> 278 * <td>Called when the view is attached to a window. 279 * </td> 280 * </tr> 281 * 282 * <tr> 283 * <td><code>{@link #onDetachedFromWindow}</code></td> 284 * <td>Called when the view is detached from its window. 285 * </td> 286 * </tr> 287 * 288 * <tr> 289 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 290 * <td>Called when the visibility of the window containing the view 291 * has changed. 292 * </td> 293 * </tr> 294 * </tbody> 295 * 296 * </table> 297 * </p> 298 * 299 * <a name="IDs"></a> 300 * <h3>IDs</h3> 301 * Views may have an integer id associated with them. These ids are typically 302 * assigned in the layout XML files, and are used to find specific views within 303 * the view tree. A common pattern is to: 304 * <ul> 305 * <li>Define a Button in the layout file and assign it a unique ID. 306 * <pre> 307 * <Button 308 * android:id="@+id/my_button" 309 * android:layout_width="wrap_content" 310 * android:layout_height="wrap_content" 311 * android:text="@string/my_button_text"/> 312 * </pre></li> 313 * <li>From the onCreate method of an Activity, find the Button 314 * <pre class="prettyprint"> 315 * Button myButton = (Button) findViewById(R.id.my_button); 316 * </pre></li> 317 * </ul> 318 * <p> 319 * View IDs need not be unique throughout the tree, but it is good practice to 320 * ensure that they are at least unique within the part of the tree you are 321 * searching. 322 * </p> 323 * 324 * <a name="Position"></a> 325 * <h3>Position</h3> 326 * <p> 327 * The geometry of a view is that of a rectangle. A view has a location, 328 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 329 * two dimensions, expressed as a width and a height. The unit for location 330 * and dimensions is the pixel. 331 * </p> 332 * 333 * <p> 334 * It is possible to retrieve the location of a view by invoking the methods 335 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 336 * coordinate of the rectangle representing the view. The latter returns the 337 * top, or Y, coordinate of the rectangle representing the view. These methods 338 * both return the location of the view relative to its parent. For instance, 339 * when getLeft() returns 20, that means the view is located 20 pixels to the 340 * right of the left edge of its direct parent. 341 * </p> 342 * 343 * <p> 344 * In addition, several convenience methods are offered to avoid unnecessary 345 * computations, namely {@link #getRight()} and {@link #getBottom()}. 346 * These methods return the coordinates of the right and bottom edges of the 347 * rectangle representing the view. For instance, calling {@link #getRight()} 348 * is similar to the following computation: <code>getLeft() + getWidth()</code> 349 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 350 * </p> 351 * 352 * <a name="SizePaddingMargins"></a> 353 * <h3>Size, padding and margins</h3> 354 * <p> 355 * The size of a view is expressed with a width and a height. A view actually 356 * possess two pairs of width and height values. 357 * </p> 358 * 359 * <p> 360 * The first pair is known as <em>measured width</em> and 361 * <em>measured height</em>. These dimensions define how big a view wants to be 362 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 363 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 364 * and {@link #getMeasuredHeight()}. 365 * </p> 366 * 367 * <p> 368 * The second pair is simply known as <em>width</em> and <em>height</em>, or 369 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 370 * dimensions define the actual size of the view on screen, at drawing time and 371 * after layout. These values may, but do not have to, be different from the 372 * measured width and height. The width and height can be obtained by calling 373 * {@link #getWidth()} and {@link #getHeight()}. 374 * </p> 375 * 376 * <p> 377 * To measure its dimensions, a view takes into account its padding. The padding 378 * is expressed in pixels for the left, top, right and bottom parts of the view. 379 * Padding can be used to offset the content of the view by a specific amount of 380 * pixels. For instance, a left padding of 2 will push the view's content by 381 * 2 pixels to the right of the left edge. Padding can be set using the 382 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 383 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 384 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 385 * {@link #getPaddingEnd()}. 386 * </p> 387 * 388 * <p> 389 * Even though a view can define a padding, it does not provide any support for 390 * margins. However, view groups provide such a support. Refer to 391 * {@link android.view.ViewGroup} and 392 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 393 * </p> 394 * 395 * <a name="Layout"></a> 396 * <h3>Layout</h3> 397 * <p> 398 * Layout is a two pass process: a measure pass and a layout pass. The measuring 399 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 400 * of the view tree. Each view pushes dimension specifications down the tree 401 * during the recursion. At the end of the measure pass, every view has stored 402 * its measurements. The second pass happens in 403 * {@link #layout(int,int,int,int)} and is also top-down. During 404 * this pass each parent is responsible for positioning all of its children 405 * using the sizes computed in the measure pass. 406 * </p> 407 * 408 * <p> 409 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 410 * {@link #getMeasuredHeight()} values must be set, along with those for all of 411 * that view's descendants. A view's measured width and measured height values 412 * must respect the constraints imposed by the view's parents. This guarantees 413 * that at the end of the measure pass, all parents accept all of their 414 * children's measurements. A parent view may call measure() more than once on 415 * its children. For example, the parent may measure each child once with 416 * unspecified dimensions to find out how big they want to be, then call 417 * measure() on them again with actual numbers if the sum of all the children's 418 * unconstrained sizes is too big or too small. 419 * </p> 420 * 421 * <p> 422 * The measure pass uses two classes to communicate dimensions. The 423 * {@link MeasureSpec} class is used by views to tell their parents how they 424 * want to be measured and positioned. The base LayoutParams class just 425 * describes how big the view wants to be for both width and height. For each 426 * dimension, it can specify one of: 427 * <ul> 428 * <li> an exact number 429 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 430 * (minus padding) 431 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 432 * enclose its content (plus padding). 433 * </ul> 434 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 435 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 436 * an X and Y value. 437 * </p> 438 * 439 * <p> 440 * MeasureSpecs are used to push requirements down the tree from parent to 441 * child. A MeasureSpec can be in one of three modes: 442 * <ul> 443 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 444 * of a child view. For example, a LinearLayout may call measure() on its child 445 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 446 * tall the child view wants to be given a width of 240 pixels. 447 * <li>EXACTLY: This is used by the parent to impose an exact size on the 448 * child. The child must use this size, and guarantee that all of its 449 * descendants will fit within this size. 450 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 451 * child. The child must guarantee that it and all of its descendants will fit 452 * within this size. 453 * </ul> 454 * </p> 455 * 456 * <p> 457 * To initiate a layout, call {@link #requestLayout}. This method is typically 458 * called by a view on itself when it believes that is can no longer fit within 459 * its current bounds. 460 * </p> 461 * 462 * <a name="Drawing"></a> 463 * <h3>Drawing</h3> 464 * <p> 465 * Drawing is handled by walking the tree and recording the drawing commands of 466 * any View that needs to update. After this, the drawing commands of the 467 * entire tree are issued to screen, clipped to the newly damaged area. 468 * </p> 469 * 470 * <p> 471 * The tree is largely recorded and drawn in order, with parents drawn before 472 * (i.e., behind) their children, with siblings drawn in the order they appear 473 * in the tree. If you set a background drawable for a View, then the View will 474 * draw it before calling back to its <code>onDraw()</code> method. The child 475 * drawing order can be overridden with 476 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 477 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 478 * </p> 479 * 480 * <p> 481 * To force a view to draw, call {@link #invalidate()}. 482 * </p> 483 * 484 * <a name="EventHandlingThreading"></a> 485 * <h3>Event Handling and Threading</h3> 486 * <p> 487 * The basic cycle of a view is as follows: 488 * <ol> 489 * <li>An event comes in and is dispatched to the appropriate view. The view 490 * handles the event and notifies any listeners.</li> 491 * <li>If in the course of processing the event, the view's bounds may need 492 * to be changed, the view will call {@link #requestLayout()}.</li> 493 * <li>Similarly, if in the course of processing the event the view's appearance 494 * may need to be changed, the view will call {@link #invalidate()}.</li> 495 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 496 * the framework will take care of measuring, laying out, and drawing the tree 497 * as appropriate.</li> 498 * </ol> 499 * </p> 500 * 501 * <p><em>Note: The entire view tree is single threaded. You must always be on 502 * the UI thread when calling any method on any view.</em> 503 * If you are doing work on other threads and want to update the state of a view 504 * from that thread, you should use a {@link Handler}. 505 * </p> 506 * 507 * <a name="FocusHandling"></a> 508 * <h3>Focus Handling</h3> 509 * <p> 510 * The framework will handle routine focus movement in response to user input. 511 * This includes changing the focus as views are removed or hidden, or as new 512 * views become available. Views indicate their willingness to take focus 513 * through the {@link #isFocusable} method. To change whether a view can take 514 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 515 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 516 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 517 * </p> 518 * <p> 519 * Focus movement is based on an algorithm which finds the nearest neighbor in a 520 * given direction. In rare cases, the default algorithm may not match the 521 * intended behavior of the developer. In these situations, you can provide 522 * explicit overrides by using these XML attributes in the layout file: 523 * <pre> 524 * nextFocusDown 525 * nextFocusLeft 526 * nextFocusRight 527 * nextFocusUp 528 * </pre> 529 * </p> 530 * 531 * 532 * <p> 533 * To get a particular view to take focus, call {@link #requestFocus()}. 534 * </p> 535 * 536 * <a name="TouchMode"></a> 537 * <h3>Touch Mode</h3> 538 * <p> 539 * When a user is navigating a user interface via directional keys such as a D-pad, it is 540 * necessary to give focus to actionable items such as buttons so the user can see 541 * what will take input. If the device has touch capabilities, however, and the user 542 * begins interacting with the interface by touching it, it is no longer necessary to 543 * always highlight, or give focus to, a particular view. This motivates a mode 544 * for interaction named 'touch mode'. 545 * </p> 546 * <p> 547 * For a touch capable device, once the user touches the screen, the device 548 * will enter touch mode. From this point onward, only views for which 549 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 550 * Other views that are touchable, like buttons, will not take focus when touched; they will 551 * only fire the on click listeners. 552 * </p> 553 * <p> 554 * Any time a user hits a directional key, such as a D-pad direction, the view device will 555 * exit touch mode, and find a view to take focus, so that the user may resume interacting 556 * with the user interface without touching the screen again. 557 * </p> 558 * <p> 559 * The touch mode state is maintained across {@link android.app.Activity}s. Call 560 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 561 * </p> 562 * 563 * <a name="Scrolling"></a> 564 * <h3>Scrolling</h3> 565 * <p> 566 * The framework provides basic support for views that wish to internally 567 * scroll their content. This includes keeping track of the X and Y scroll 568 * offset as well as mechanisms for drawing scrollbars. See 569 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 570 * {@link #awakenScrollBars()} for more details. 571 * </p> 572 * 573 * <a name="Tags"></a> 574 * <h3>Tags</h3> 575 * <p> 576 * Unlike IDs, tags are not used to identify views. Tags are essentially an 577 * extra piece of information that can be associated with a view. They are most 578 * often used as a convenience to store data related to views in the views 579 * themselves rather than by putting them in a separate structure. 580 * </p> 581 * <p> 582 * Tags may be specified with character sequence values in layout XML as either 583 * a single tag using the {@link android.R.styleable#View_tag android:tag} 584 * attribute or multiple tags using the {@code <tag>} child element: 585 * <pre> 586 * <View ... 587 * android:tag="@string/mytag_value" /> 588 * <View ...> 589 * <tag android:id="@+id/mytag" 590 * android:value="@string/mytag_value" /> 591 * </View> 592 * </pre> 593 * </p> 594 * <p> 595 * Tags may also be specified with arbitrary objects from code using 596 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 597 * </p> 598 * 599 * <a name="Themes"></a> 600 * <h3>Themes</h3> 601 * <p> 602 * By default, Views are created using the theme of the Context object supplied 603 * to their constructor; however, a different theme may be specified by using 604 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 605 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 606 * code. 607 * </p> 608 * <p> 609 * When the {@link android.R.styleable#View_theme android:theme} attribute is 610 * used in XML, the specified theme is applied on top of the inflation 611 * context's theme (see {@link LayoutInflater}) and used for the view itself as 612 * well as any child elements. 613 * </p> 614 * <p> 615 * In the following example, both views will be created using the Material dark 616 * color scheme; however, because an overlay theme is used which only defines a 617 * subset of attributes, the value of 618 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 619 * the inflation context's theme (e.g. the Activity theme) will be preserved. 620 * <pre> 621 * <LinearLayout 622 * ... 623 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 624 * <View ...> 625 * </LinearLayout> 626 * </pre> 627 * </p> 628 * 629 * <a name="Properties"></a> 630 * <h3>Properties</h3> 631 * <p> 632 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 633 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 634 * available both in the {@link Property} form as well as in similarly-named setter/getter 635 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 636 * be used to set persistent state associated with these rendering-related properties on the view. 637 * The properties and methods can also be used in conjunction with 638 * {@link android.animation.Animator Animator}-based animations, described more in the 639 * <a href="#Animation">Animation</a> section. 640 * </p> 641 * 642 * <a name="Animation"></a> 643 * <h3>Animation</h3> 644 * <p> 645 * Starting with Android 3.0, the preferred way of animating views is to use the 646 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 647 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 648 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 649 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 650 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 651 * makes animating these View properties particularly easy and efficient. 652 * </p> 653 * <p> 654 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 655 * You can attach an {@link Animation} object to a view using 656 * {@link #setAnimation(Animation)} or 657 * {@link #startAnimation(Animation)}. The animation can alter the scale, 658 * rotation, translation and alpha of a view over time. If the animation is 659 * attached to a view that has children, the animation will affect the entire 660 * subtree rooted by that node. When an animation is started, the framework will 661 * take care of redrawing the appropriate views until the animation completes. 662 * </p> 663 * 664 * <a name="Security"></a> 665 * <h3>Security</h3> 666 * <p> 667 * Sometimes it is essential that an application be able to verify that an action 668 * is being performed with the full knowledge and consent of the user, such as 669 * granting a permission request, making a purchase or clicking on an advertisement. 670 * Unfortunately, a malicious application could try to spoof the user into 671 * performing these actions, unaware, by concealing the intended purpose of the view. 672 * As a remedy, the framework offers a touch filtering mechanism that can be used to 673 * improve the security of views that provide access to sensitive functionality. 674 * </p><p> 675 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 676 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 677 * will discard touches that are received whenever the view's window is obscured by 678 * another visible window. As a result, the view will not receive touches whenever a 679 * toast, dialog or other window appears above the view's window. 680 * </p><p> 681 * For more fine-grained control over security, consider overriding the 682 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 683 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 684 * </p> 685 * 686 * @attr ref android.R.styleable#View_alpha 687 * @attr ref android.R.styleable#View_background 688 * @attr ref android.R.styleable#View_clickable 689 * @attr ref android.R.styleable#View_contentDescription 690 * @attr ref android.R.styleable#View_drawingCacheQuality 691 * @attr ref android.R.styleable#View_duplicateParentState 692 * @attr ref android.R.styleable#View_id 693 * @attr ref android.R.styleable#View_requiresFadingEdge 694 * @attr ref android.R.styleable#View_fadeScrollbars 695 * @attr ref android.R.styleable#View_fadingEdgeLength 696 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 697 * @attr ref android.R.styleable#View_fitsSystemWindows 698 * @attr ref android.R.styleable#View_isScrollContainer 699 * @attr ref android.R.styleable#View_focusable 700 * @attr ref android.R.styleable#View_focusableInTouchMode 701 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 702 * @attr ref android.R.styleable#View_keepScreenOn 703 * @attr ref android.R.styleable#View_layerType 704 * @attr ref android.R.styleable#View_layoutDirection 705 * @attr ref android.R.styleable#View_longClickable 706 * @attr ref android.R.styleable#View_minHeight 707 * @attr ref android.R.styleable#View_minWidth 708 * @attr ref android.R.styleable#View_nextFocusDown 709 * @attr ref android.R.styleable#View_nextFocusLeft 710 * @attr ref android.R.styleable#View_nextFocusRight 711 * @attr ref android.R.styleable#View_nextFocusUp 712 * @attr ref android.R.styleable#View_onClick 713 * @attr ref android.R.styleable#View_padding 714 * @attr ref android.R.styleable#View_paddingBottom 715 * @attr ref android.R.styleable#View_paddingLeft 716 * @attr ref android.R.styleable#View_paddingRight 717 * @attr ref android.R.styleable#View_paddingTop 718 * @attr ref android.R.styleable#View_paddingStart 719 * @attr ref android.R.styleable#View_paddingEnd 720 * @attr ref android.R.styleable#View_saveEnabled 721 * @attr ref android.R.styleable#View_rotation 722 * @attr ref android.R.styleable#View_rotationX 723 * @attr ref android.R.styleable#View_rotationY 724 * @attr ref android.R.styleable#View_scaleX 725 * @attr ref android.R.styleable#View_scaleY 726 * @attr ref android.R.styleable#View_scrollX 727 * @attr ref android.R.styleable#View_scrollY 728 * @attr ref android.R.styleable#View_scrollbarSize 729 * @attr ref android.R.styleable#View_scrollbarStyle 730 * @attr ref android.R.styleable#View_scrollbars 731 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 732 * @attr ref android.R.styleable#View_scrollbarFadeDuration 733 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 734 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 735 * @attr ref android.R.styleable#View_scrollbarThumbVertical 736 * @attr ref android.R.styleable#View_scrollbarTrackVertical 737 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 738 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 739 * @attr ref android.R.styleable#View_stateListAnimator 740 * @attr ref android.R.styleable#View_transitionName 741 * @attr ref android.R.styleable#View_soundEffectsEnabled 742 * @attr ref android.R.styleable#View_tag 743 * @attr ref android.R.styleable#View_textAlignment 744 * @attr ref android.R.styleable#View_textDirection 745 * @attr ref android.R.styleable#View_transformPivotX 746 * @attr ref android.R.styleable#View_transformPivotY 747 * @attr ref android.R.styleable#View_translationX 748 * @attr ref android.R.styleable#View_translationY 749 * @attr ref android.R.styleable#View_translationZ 750 * @attr ref android.R.styleable#View_visibility 751 * @attr ref android.R.styleable#View_theme 752 * 753 * @see android.view.ViewGroup 754 */ 755 @UiThread 756 public class View implements Drawable.Callback, KeyEvent.Callback, 757 AccessibilityEventSource { 758 private static final boolean DBG = false; 759 760 /** 761 * The logging tag used by this class with android.util.Log. 762 */ 763 protected static final String VIEW_LOG_TAG = "View"; 764 765 /** 766 * When set to true, apps will draw debugging information about their layouts. 767 * 768 * @hide 769 */ 770 public static final String DEBUG_LAYOUT_PROPERTY = "debug.layout"; 771 772 /** 773 * When set to true, this view will save its attribute data. 774 * 775 * @hide 776 */ 777 public static boolean mDebugViewAttributes = false; 778 779 /** 780 * Used to mark a View that has no ID. 781 */ 782 public static final int NO_ID = -1; 783 784 /** 785 * Signals that compatibility booleans have been initialized according to 786 * target SDK versions. 787 */ 788 private static boolean sCompatibilityDone = false; 789 790 /** 791 * Use the old (broken) way of building MeasureSpecs. 792 */ 793 private static boolean sUseBrokenMakeMeasureSpec = false; 794 795 /** 796 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 797 */ 798 static boolean sUseZeroUnspecifiedMeasureSpec = false; 799 800 /** 801 * Ignore any optimizations using the measure cache. 802 */ 803 private static boolean sIgnoreMeasureCache = false; 804 805 /** 806 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 807 */ 808 private static boolean sAlwaysRemeasureExactly = false; 809 810 /** 811 * Relax constraints around whether setLayoutParams() must be called after 812 * modifying the layout params. 813 */ 814 private static boolean sLayoutParamsAlwaysChanged = false; 815 816 /** 817 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 818 * without throwing 819 */ 820 static boolean sTextureViewIgnoresDrawableSetters = false; 821 822 /** 823 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 824 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 825 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 826 * check is implemented for backwards compatibility. 827 * 828 * {@hide} 829 */ 830 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 831 832 /** 833 * Prior to N, when drag enters into child of a view that has already received an 834 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 835 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 836 * false from its event handler for these events. 837 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 838 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 839 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 840 */ 841 static boolean sCascadedDragDrop; 842 843 /** 844 * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when 845 * calling setFlags. 846 */ 847 private static final int NOT_FOCUSABLE = 0x00000000; 848 849 /** 850 * This view wants keystrokes. Use with TAKES_FOCUS_MASK when calling 851 * setFlags. 852 */ 853 private static final int FOCUSABLE = 0x00000001; 854 855 /** 856 * Mask for use with setFlags indicating bits used for focus. 857 */ 858 private static final int FOCUSABLE_MASK = 0x00000001; 859 860 /** 861 * This view will adjust its padding to fit sytem windows (e.g. status bar) 862 */ 863 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 864 865 /** @hide */ 866 @IntDef({VISIBLE, INVISIBLE, GONE}) 867 @Retention(RetentionPolicy.SOURCE) 868 public @interface Visibility {} 869 870 /** 871 * This view is visible. 872 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 873 * android:visibility}. 874 */ 875 public static final int VISIBLE = 0x00000000; 876 877 /** 878 * This view is invisible, but it still takes up space for layout purposes. 879 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 880 * android:visibility}. 881 */ 882 public static final int INVISIBLE = 0x00000004; 883 884 /** 885 * This view is invisible, and it doesn't take any space for layout 886 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 887 * android:visibility}. 888 */ 889 public static final int GONE = 0x00000008; 890 891 /** 892 * Mask for use with setFlags indicating bits used for visibility. 893 * {@hide} 894 */ 895 static final int VISIBILITY_MASK = 0x0000000C; 896 897 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 898 899 /** 900 * This view is enabled. Interpretation varies by subclass. 901 * Use with ENABLED_MASK when calling setFlags. 902 * {@hide} 903 */ 904 static final int ENABLED = 0x00000000; 905 906 /** 907 * This view is disabled. Interpretation varies by subclass. 908 * Use with ENABLED_MASK when calling setFlags. 909 * {@hide} 910 */ 911 static final int DISABLED = 0x00000020; 912 913 /** 914 * Mask for use with setFlags indicating bits used for indicating whether 915 * this view is enabled 916 * {@hide} 917 */ 918 static final int ENABLED_MASK = 0x00000020; 919 920 /** 921 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 922 * called and further optimizations will be performed. It is okay to have 923 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 924 * {@hide} 925 */ 926 static final int WILL_NOT_DRAW = 0x00000080; 927 928 /** 929 * Mask for use with setFlags indicating bits used for indicating whether 930 * this view is will draw 931 * {@hide} 932 */ 933 static final int DRAW_MASK = 0x00000080; 934 935 /** 936 * <p>This view doesn't show scrollbars.</p> 937 * {@hide} 938 */ 939 static final int SCROLLBARS_NONE = 0x00000000; 940 941 /** 942 * <p>This view shows horizontal scrollbars.</p> 943 * {@hide} 944 */ 945 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 946 947 /** 948 * <p>This view shows vertical scrollbars.</p> 949 * {@hide} 950 */ 951 static final int SCROLLBARS_VERTICAL = 0x00000200; 952 953 /** 954 * <p>Mask for use with setFlags indicating bits used for indicating which 955 * scrollbars are enabled.</p> 956 * {@hide} 957 */ 958 static final int SCROLLBARS_MASK = 0x00000300; 959 960 /** 961 * Indicates that the view should filter touches when its window is obscured. 962 * Refer to the class comments for more information about this security feature. 963 * {@hide} 964 */ 965 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 966 967 /** 968 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 969 * that they are optional and should be skipped if the window has 970 * requested system UI flags that ignore those insets for layout. 971 */ 972 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 973 974 /** 975 * <p>This view doesn't show fading edges.</p> 976 * {@hide} 977 */ 978 static final int FADING_EDGE_NONE = 0x00000000; 979 980 /** 981 * <p>This view shows horizontal fading edges.</p> 982 * {@hide} 983 */ 984 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 985 986 /** 987 * <p>This view shows vertical fading edges.</p> 988 * {@hide} 989 */ 990 static final int FADING_EDGE_VERTICAL = 0x00002000; 991 992 /** 993 * <p>Mask for use with setFlags indicating bits used for indicating which 994 * fading edges are enabled.</p> 995 * {@hide} 996 */ 997 static final int FADING_EDGE_MASK = 0x00003000; 998 999 /** 1000 * <p>Indicates this view can be clicked. When clickable, a View reacts 1001 * to clicks by notifying the OnClickListener.<p> 1002 * {@hide} 1003 */ 1004 static final int CLICKABLE = 0x00004000; 1005 1006 /** 1007 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1008 * {@hide} 1009 */ 1010 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1011 1012 /** 1013 * <p>Indicates that no icicle should be saved for this view.<p> 1014 * {@hide} 1015 */ 1016 static final int SAVE_DISABLED = 0x000010000; 1017 1018 /** 1019 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1020 * property.</p> 1021 * {@hide} 1022 */ 1023 static final int SAVE_DISABLED_MASK = 0x000010000; 1024 1025 /** 1026 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1027 * {@hide} 1028 */ 1029 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1030 1031 /** 1032 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1033 * {@hide} 1034 */ 1035 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1036 1037 /** @hide */ 1038 @Retention(RetentionPolicy.SOURCE) 1039 @IntDef({DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH, DRAWING_CACHE_QUALITY_AUTO}) 1040 public @interface DrawingCacheQuality {} 1041 1042 /** 1043 * <p>Enables low quality mode for the drawing cache.</p> 1044 */ 1045 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1046 1047 /** 1048 * <p>Enables high quality mode for the drawing cache.</p> 1049 */ 1050 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1051 1052 /** 1053 * <p>Enables automatic quality mode for the drawing cache.</p> 1054 */ 1055 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1056 1057 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1058 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1059 }; 1060 1061 /** 1062 * <p>Mask for use with setFlags indicating bits used for the cache 1063 * quality property.</p> 1064 * {@hide} 1065 */ 1066 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1067 1068 /** 1069 * <p> 1070 * Indicates this view can be long clicked. When long clickable, a View 1071 * reacts to long clicks by notifying the OnLongClickListener or showing a 1072 * context menu. 1073 * </p> 1074 * {@hide} 1075 */ 1076 static final int LONG_CLICKABLE = 0x00200000; 1077 1078 /** 1079 * <p>Indicates that this view gets its drawable states from its direct parent 1080 * and ignores its original internal states.</p> 1081 * 1082 * @hide 1083 */ 1084 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1085 1086 /** 1087 * <p> 1088 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1089 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1090 * OnContextClickListener. 1091 * </p> 1092 * {@hide} 1093 */ 1094 static final int CONTEXT_CLICKABLE = 0x00800000; 1095 1096 1097 /** @hide */ 1098 @IntDef({ 1099 SCROLLBARS_INSIDE_OVERLAY, 1100 SCROLLBARS_INSIDE_INSET, 1101 SCROLLBARS_OUTSIDE_OVERLAY, 1102 SCROLLBARS_OUTSIDE_INSET 1103 }) 1104 @Retention(RetentionPolicy.SOURCE) 1105 public @interface ScrollBarStyle {} 1106 1107 /** 1108 * The scrollbar style to display the scrollbars inside the content area, 1109 * without increasing the padding. The scrollbars will be overlaid with 1110 * translucency on the view's content. 1111 */ 1112 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1113 1114 /** 1115 * The scrollbar style to display the scrollbars inside the padded area, 1116 * increasing the padding of the view. The scrollbars will not overlap the 1117 * content area of the view. 1118 */ 1119 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1120 1121 /** 1122 * The scrollbar style to display the scrollbars at the edge of the view, 1123 * without increasing the padding. The scrollbars will be overlaid with 1124 * translucency. 1125 */ 1126 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1127 1128 /** 1129 * The scrollbar style to display the scrollbars at the edge of the view, 1130 * increasing the padding of the view. The scrollbars will only overlap the 1131 * background, if any. 1132 */ 1133 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1134 1135 /** 1136 * Mask to check if the scrollbar style is overlay or inset. 1137 * {@hide} 1138 */ 1139 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1140 1141 /** 1142 * Mask to check if the scrollbar style is inside or outside. 1143 * {@hide} 1144 */ 1145 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1146 1147 /** 1148 * Mask for scrollbar style. 1149 * {@hide} 1150 */ 1151 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1152 1153 /** 1154 * View flag indicating that the screen should remain on while the 1155 * window containing this view is visible to the user. This effectively 1156 * takes care of automatically setting the WindowManager's 1157 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1158 */ 1159 public static final int KEEP_SCREEN_ON = 0x04000000; 1160 1161 /** 1162 * View flag indicating whether this view should have sound effects enabled 1163 * for events such as clicking and touching. 1164 */ 1165 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1166 1167 /** 1168 * View flag indicating whether this view should have haptic feedback 1169 * enabled for events such as long presses. 1170 */ 1171 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1172 1173 /** 1174 * <p>Indicates that the view hierarchy should stop saving state when 1175 * it reaches this view. If state saving is initiated immediately at 1176 * the view, it will be allowed. 1177 * {@hide} 1178 */ 1179 static final int PARENT_SAVE_DISABLED = 0x20000000; 1180 1181 /** 1182 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1183 * {@hide} 1184 */ 1185 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1186 1187 /** @hide */ 1188 @IntDef(flag = true, 1189 value = { 1190 FOCUSABLES_ALL, 1191 FOCUSABLES_TOUCH_MODE 1192 }) 1193 @Retention(RetentionPolicy.SOURCE) 1194 public @interface FocusableMode {} 1195 1196 /** 1197 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1198 * should add all focusable Views regardless if they are focusable in touch mode. 1199 */ 1200 public static final int FOCUSABLES_ALL = 0x00000000; 1201 1202 /** 1203 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1204 * should add only Views focusable in touch mode. 1205 */ 1206 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1207 1208 /** @hide */ 1209 @IntDef({ 1210 FOCUS_BACKWARD, 1211 FOCUS_FORWARD, 1212 FOCUS_LEFT, 1213 FOCUS_UP, 1214 FOCUS_RIGHT, 1215 FOCUS_DOWN 1216 }) 1217 @Retention(RetentionPolicy.SOURCE) 1218 public @interface FocusDirection {} 1219 1220 /** @hide */ 1221 @IntDef({ 1222 FOCUS_LEFT, 1223 FOCUS_UP, 1224 FOCUS_RIGHT, 1225 FOCUS_DOWN 1226 }) 1227 @Retention(RetentionPolicy.SOURCE) 1228 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1229 1230 /** 1231 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1232 * item. 1233 */ 1234 public static final int FOCUS_BACKWARD = 0x00000001; 1235 1236 /** 1237 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1238 * item. 1239 */ 1240 public static final int FOCUS_FORWARD = 0x00000002; 1241 1242 /** 1243 * Use with {@link #focusSearch(int)}. Move focus to the left. 1244 */ 1245 public static final int FOCUS_LEFT = 0x00000011; 1246 1247 /** 1248 * Use with {@link #focusSearch(int)}. Move focus up. 1249 */ 1250 public static final int FOCUS_UP = 0x00000021; 1251 1252 /** 1253 * Use with {@link #focusSearch(int)}. Move focus to the right. 1254 */ 1255 public static final int FOCUS_RIGHT = 0x00000042; 1256 1257 /** 1258 * Use with {@link #focusSearch(int)}. Move focus down. 1259 */ 1260 public static final int FOCUS_DOWN = 0x00000082; 1261 1262 /** 1263 * Bits of {@link #getMeasuredWidthAndState()} and 1264 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1265 */ 1266 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1267 1268 /** 1269 * Bits of {@link #getMeasuredWidthAndState()} and 1270 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1271 */ 1272 public static final int MEASURED_STATE_MASK = 0xff000000; 1273 1274 /** 1275 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1276 * for functions that combine both width and height into a single int, 1277 * such as {@link #getMeasuredState()} and the childState argument of 1278 * {@link #resolveSizeAndState(int, int, int)}. 1279 */ 1280 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1281 1282 /** 1283 * Bit of {@link #getMeasuredWidthAndState()} and 1284 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1285 * is smaller that the space the view would like to have. 1286 */ 1287 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1288 1289 /** 1290 * Base View state sets 1291 */ 1292 // Singles 1293 /** 1294 * Indicates the view has no states set. States are used with 1295 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1296 * view depending on its state. 1297 * 1298 * @see android.graphics.drawable.Drawable 1299 * @see #getDrawableState() 1300 */ 1301 protected static final int[] EMPTY_STATE_SET; 1302 /** 1303 * Indicates the view is enabled. States are used with 1304 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1305 * view depending on its state. 1306 * 1307 * @see android.graphics.drawable.Drawable 1308 * @see #getDrawableState() 1309 */ 1310 protected static final int[] ENABLED_STATE_SET; 1311 /** 1312 * Indicates the view is focused. States are used with 1313 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1314 * view depending on its state. 1315 * 1316 * @see android.graphics.drawable.Drawable 1317 * @see #getDrawableState() 1318 */ 1319 protected static final int[] FOCUSED_STATE_SET; 1320 /** 1321 * Indicates the view is selected. States are used with 1322 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1323 * view depending on its state. 1324 * 1325 * @see android.graphics.drawable.Drawable 1326 * @see #getDrawableState() 1327 */ 1328 protected static final int[] SELECTED_STATE_SET; 1329 /** 1330 * Indicates the view is pressed. States are used with 1331 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1332 * view depending on its state. 1333 * 1334 * @see android.graphics.drawable.Drawable 1335 * @see #getDrawableState() 1336 */ 1337 protected static final int[] PRESSED_STATE_SET; 1338 /** 1339 * Indicates the view's window has focus. States are used with 1340 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1341 * view depending on its state. 1342 * 1343 * @see android.graphics.drawable.Drawable 1344 * @see #getDrawableState() 1345 */ 1346 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1347 // Doubles 1348 /** 1349 * Indicates the view is enabled and has the focus. 1350 * 1351 * @see #ENABLED_STATE_SET 1352 * @see #FOCUSED_STATE_SET 1353 */ 1354 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1355 /** 1356 * Indicates the view is enabled and selected. 1357 * 1358 * @see #ENABLED_STATE_SET 1359 * @see #SELECTED_STATE_SET 1360 */ 1361 protected static final int[] ENABLED_SELECTED_STATE_SET; 1362 /** 1363 * Indicates the view is enabled and that its window has focus. 1364 * 1365 * @see #ENABLED_STATE_SET 1366 * @see #WINDOW_FOCUSED_STATE_SET 1367 */ 1368 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1369 /** 1370 * Indicates the view is focused and selected. 1371 * 1372 * @see #FOCUSED_STATE_SET 1373 * @see #SELECTED_STATE_SET 1374 */ 1375 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1376 /** 1377 * Indicates the view has the focus and that its window has the focus. 1378 * 1379 * @see #FOCUSED_STATE_SET 1380 * @see #WINDOW_FOCUSED_STATE_SET 1381 */ 1382 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1383 /** 1384 * Indicates the view is selected and that its window has the focus. 1385 * 1386 * @see #SELECTED_STATE_SET 1387 * @see #WINDOW_FOCUSED_STATE_SET 1388 */ 1389 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1390 // Triples 1391 /** 1392 * Indicates the view is enabled, focused and selected. 1393 * 1394 * @see #ENABLED_STATE_SET 1395 * @see #FOCUSED_STATE_SET 1396 * @see #SELECTED_STATE_SET 1397 */ 1398 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1399 /** 1400 * Indicates the view is enabled, focused and its window has the focus. 1401 * 1402 * @see #ENABLED_STATE_SET 1403 * @see #FOCUSED_STATE_SET 1404 * @see #WINDOW_FOCUSED_STATE_SET 1405 */ 1406 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1407 /** 1408 * Indicates the view is enabled, selected and its window has the focus. 1409 * 1410 * @see #ENABLED_STATE_SET 1411 * @see #SELECTED_STATE_SET 1412 * @see #WINDOW_FOCUSED_STATE_SET 1413 */ 1414 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1415 /** 1416 * Indicates the view is focused, selected and its window has the focus. 1417 * 1418 * @see #FOCUSED_STATE_SET 1419 * @see #SELECTED_STATE_SET 1420 * @see #WINDOW_FOCUSED_STATE_SET 1421 */ 1422 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1423 /** 1424 * Indicates the view is enabled, focused, selected and its window 1425 * has the focus. 1426 * 1427 * @see #ENABLED_STATE_SET 1428 * @see #FOCUSED_STATE_SET 1429 * @see #SELECTED_STATE_SET 1430 * @see #WINDOW_FOCUSED_STATE_SET 1431 */ 1432 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1433 /** 1434 * Indicates the view is pressed and its window has the focus. 1435 * 1436 * @see #PRESSED_STATE_SET 1437 * @see #WINDOW_FOCUSED_STATE_SET 1438 */ 1439 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1440 /** 1441 * Indicates the view is pressed and selected. 1442 * 1443 * @see #PRESSED_STATE_SET 1444 * @see #SELECTED_STATE_SET 1445 */ 1446 protected static final int[] PRESSED_SELECTED_STATE_SET; 1447 /** 1448 * Indicates the view is pressed, selected and its window has the focus. 1449 * 1450 * @see #PRESSED_STATE_SET 1451 * @see #SELECTED_STATE_SET 1452 * @see #WINDOW_FOCUSED_STATE_SET 1453 */ 1454 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1455 /** 1456 * Indicates the view is pressed and focused. 1457 * 1458 * @see #PRESSED_STATE_SET 1459 * @see #FOCUSED_STATE_SET 1460 */ 1461 protected static final int[] PRESSED_FOCUSED_STATE_SET; 1462 /** 1463 * Indicates the view is pressed, focused and its window has the focus. 1464 * 1465 * @see #PRESSED_STATE_SET 1466 * @see #FOCUSED_STATE_SET 1467 * @see #WINDOW_FOCUSED_STATE_SET 1468 */ 1469 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1470 /** 1471 * Indicates the view is pressed, focused and selected. 1472 * 1473 * @see #PRESSED_STATE_SET 1474 * @see #SELECTED_STATE_SET 1475 * @see #FOCUSED_STATE_SET 1476 */ 1477 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 1478 /** 1479 * Indicates the view is pressed, focused, selected and its window has the focus. 1480 * 1481 * @see #PRESSED_STATE_SET 1482 * @see #FOCUSED_STATE_SET 1483 * @see #SELECTED_STATE_SET 1484 * @see #WINDOW_FOCUSED_STATE_SET 1485 */ 1486 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1487 /** 1488 * Indicates the view is pressed and enabled. 1489 * 1490 * @see #PRESSED_STATE_SET 1491 * @see #ENABLED_STATE_SET 1492 */ 1493 protected static final int[] PRESSED_ENABLED_STATE_SET; 1494 /** 1495 * Indicates the view is pressed, enabled and its window has the focus. 1496 * 1497 * @see #PRESSED_STATE_SET 1498 * @see #ENABLED_STATE_SET 1499 * @see #WINDOW_FOCUSED_STATE_SET 1500 */ 1501 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 1502 /** 1503 * Indicates the view is pressed, enabled and selected. 1504 * 1505 * @see #PRESSED_STATE_SET 1506 * @see #ENABLED_STATE_SET 1507 * @see #SELECTED_STATE_SET 1508 */ 1509 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 1510 /** 1511 * Indicates the view is pressed, enabled, selected and its window has the 1512 * focus. 1513 * 1514 * @see #PRESSED_STATE_SET 1515 * @see #ENABLED_STATE_SET 1516 * @see #SELECTED_STATE_SET 1517 * @see #WINDOW_FOCUSED_STATE_SET 1518 */ 1519 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1520 /** 1521 * Indicates the view is pressed, enabled and focused. 1522 * 1523 * @see #PRESSED_STATE_SET 1524 * @see #ENABLED_STATE_SET 1525 * @see #FOCUSED_STATE_SET 1526 */ 1527 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 1528 /** 1529 * Indicates the view is pressed, enabled, focused and its window has the 1530 * focus. 1531 * 1532 * @see #PRESSED_STATE_SET 1533 * @see #ENABLED_STATE_SET 1534 * @see #FOCUSED_STATE_SET 1535 * @see #WINDOW_FOCUSED_STATE_SET 1536 */ 1537 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1538 /** 1539 * Indicates the view is pressed, enabled, focused and selected. 1540 * 1541 * @see #PRESSED_STATE_SET 1542 * @see #ENABLED_STATE_SET 1543 * @see #SELECTED_STATE_SET 1544 * @see #FOCUSED_STATE_SET 1545 */ 1546 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 1547 /** 1548 * Indicates the view is pressed, enabled, focused, selected and its window 1549 * has the focus. 1550 * 1551 * @see #PRESSED_STATE_SET 1552 * @see #ENABLED_STATE_SET 1553 * @see #SELECTED_STATE_SET 1554 * @see #FOCUSED_STATE_SET 1555 * @see #WINDOW_FOCUSED_STATE_SET 1556 */ 1557 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1558 1559 static { 1560 EMPTY_STATE_SET = StateSet.get(0); 1561 1562 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 1563 1564 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 1565 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1566 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 1567 1568 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 1569 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1570 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 1571 FOCUSED_SELECTED_STATE_SET = StateSet.get( 1572 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 1573 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1574 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1575 | StateSet.VIEW_STATE_FOCUSED); 1576 1577 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 1578 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1579 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1580 ENABLED_SELECTED_STATE_SET = StateSet.get( 1581 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 1582 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1583 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1584 | StateSet.VIEW_STATE_ENABLED); 1585 ENABLED_FOCUSED_STATE_SET = StateSet.get( 1586 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 1587 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1588 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1589 | StateSet.VIEW_STATE_ENABLED); 1590 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1591 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1592 | StateSet.VIEW_STATE_ENABLED); 1593 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1594 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1595 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 1596 1597 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 1598 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1599 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1600 PRESSED_SELECTED_STATE_SET = StateSet.get( 1601 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 1602 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1603 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1604 | StateSet.VIEW_STATE_PRESSED); 1605 PRESSED_FOCUSED_STATE_SET = StateSet.get( 1606 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1607 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1608 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1609 | StateSet.VIEW_STATE_PRESSED); 1610 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1611 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1612 | StateSet.VIEW_STATE_PRESSED); 1613 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1614 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1615 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 1616 PRESSED_ENABLED_STATE_SET = StateSet.get( 1617 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1618 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1619 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 1620 | StateSet.VIEW_STATE_PRESSED); 1621 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 1622 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 1623 | StateSet.VIEW_STATE_PRESSED); 1624 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1625 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1626 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1627 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 1628 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 1629 | StateSet.VIEW_STATE_PRESSED); 1630 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1631 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 1632 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1633 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 1634 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 1635 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 1636 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 1637 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 1638 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 1639 | StateSet.VIEW_STATE_PRESSED); 1640 } 1641 1642 /** 1643 * Accessibility event types that are dispatched for text population. 1644 */ 1645 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 1646 AccessibilityEvent.TYPE_VIEW_CLICKED 1647 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 1648 | AccessibilityEvent.TYPE_VIEW_SELECTED 1649 | AccessibilityEvent.TYPE_VIEW_FOCUSED 1650 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 1651 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1652 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1653 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1654 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1655 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 1656 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 1657 1658 /** 1659 * Temporary Rect currently for use in setBackground(). This will probably 1660 * be extended in the future to hold our own class with more than just 1661 * a Rect. :) 1662 */ 1663 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 1664 1665 /** 1666 * Map used to store views' tags. 1667 */ 1668 private SparseArray<Object> mKeyedTags; 1669 1670 /** 1671 * The next available accessibility id. 1672 */ 1673 private static int sNextAccessibilityViewId; 1674 1675 /** 1676 * The animation currently associated with this view. 1677 * @hide 1678 */ 1679 protected Animation mCurrentAnimation = null; 1680 1681 /** 1682 * Width as measured during measure pass. 1683 * {@hide} 1684 */ 1685 @ViewDebug.ExportedProperty(category = "measurement") 1686 int mMeasuredWidth; 1687 1688 /** 1689 * Height as measured during measure pass. 1690 * {@hide} 1691 */ 1692 @ViewDebug.ExportedProperty(category = "measurement") 1693 int mMeasuredHeight; 1694 1695 /** 1696 * Flag to indicate that this view was marked INVALIDATED, or had its display list 1697 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 1698 * its display list. This flag, used only when hw accelerated, allows us to clear the 1699 * flag while retaining this information until it's needed (at getDisplayList() time and 1700 * in drawChild(), when we decide to draw a view's children's display lists into our own). 1701 * 1702 * {@hide} 1703 */ 1704 boolean mRecreateDisplayList = false; 1705 1706 /** 1707 * The view's identifier. 1708 * {@hide} 1709 * 1710 * @see #setId(int) 1711 * @see #getId() 1712 */ 1713 @IdRes 1714 @ViewDebug.ExportedProperty(resolveId = true) 1715 int mID = NO_ID; 1716 1717 /** 1718 * The stable ID of this view for accessibility purposes. 1719 */ 1720 int mAccessibilityViewId = NO_ID; 1721 1722 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 1723 1724 SendViewStateChangedAccessibilityEvent mSendViewStateChangedAccessibilityEvent; 1725 1726 /** 1727 * The view's tag. 1728 * {@hide} 1729 * 1730 * @see #setTag(Object) 1731 * @see #getTag() 1732 */ 1733 protected Object mTag = null; 1734 1735 // for mPrivateFlags: 1736 /** {@hide} */ 1737 static final int PFLAG_WANTS_FOCUS = 0x00000001; 1738 /** {@hide} */ 1739 static final int PFLAG_FOCUSED = 0x00000002; 1740 /** {@hide} */ 1741 static final int PFLAG_SELECTED = 0x00000004; 1742 /** {@hide} */ 1743 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 1744 /** {@hide} */ 1745 static final int PFLAG_HAS_BOUNDS = 0x00000010; 1746 /** {@hide} */ 1747 static final int PFLAG_DRAWN = 0x00000020; 1748 /** 1749 * When this flag is set, this view is running an animation on behalf of its 1750 * children and should therefore not cancel invalidate requests, even if they 1751 * lie outside of this view's bounds. 1752 * 1753 * {@hide} 1754 */ 1755 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 1756 /** {@hide} */ 1757 static final int PFLAG_SKIP_DRAW = 0x00000080; 1758 /** {@hide} */ 1759 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 1760 /** {@hide} */ 1761 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 1762 /** {@hide} */ 1763 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 1764 /** {@hide} */ 1765 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 1766 /** {@hide} */ 1767 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 1768 1769 private static final int PFLAG_PRESSED = 0x00004000; 1770 1771 /** {@hide} */ 1772 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 1773 /** 1774 * Flag used to indicate that this view should be drawn once more (and only once 1775 * more) after its animation has completed. 1776 * {@hide} 1777 */ 1778 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 1779 1780 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 1781 1782 /** 1783 * Indicates that the View returned true when onSetAlpha() was called and that 1784 * the alpha must be restored. 1785 * {@hide} 1786 */ 1787 static final int PFLAG_ALPHA_SET = 0x00040000; 1788 1789 /** 1790 * Set by {@link #setScrollContainer(boolean)}. 1791 */ 1792 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 1793 1794 /** 1795 * Set by {@link #setScrollContainer(boolean)}. 1796 */ 1797 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 1798 1799 /** 1800 * View flag indicating whether this view was invalidated (fully or partially.) 1801 * 1802 * @hide 1803 */ 1804 static final int PFLAG_DIRTY = 0x00200000; 1805 1806 /** 1807 * View flag indicating whether this view was invalidated by an opaque 1808 * invalidate request. 1809 * 1810 * @hide 1811 */ 1812 static final int PFLAG_DIRTY_OPAQUE = 0x00400000; 1813 1814 /** 1815 * Mask for {@link #PFLAG_DIRTY} and {@link #PFLAG_DIRTY_OPAQUE}. 1816 * 1817 * @hide 1818 */ 1819 static final int PFLAG_DIRTY_MASK = 0x00600000; 1820 1821 /** 1822 * Indicates whether the background is opaque. 1823 * 1824 * @hide 1825 */ 1826 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 1827 1828 /** 1829 * Indicates whether the scrollbars are opaque. 1830 * 1831 * @hide 1832 */ 1833 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 1834 1835 /** 1836 * Indicates whether the view is opaque. 1837 * 1838 * @hide 1839 */ 1840 static final int PFLAG_OPAQUE_MASK = 0x01800000; 1841 1842 /** 1843 * Indicates a prepressed state; 1844 * the short time between ACTION_DOWN and recognizing 1845 * a 'real' press. Prepressed is used to recognize quick taps 1846 * even when they are shorter than ViewConfiguration.getTapTimeout(). 1847 * 1848 * @hide 1849 */ 1850 private static final int PFLAG_PREPRESSED = 0x02000000; 1851 1852 /** 1853 * Indicates whether the view is temporarily detached. 1854 * 1855 * @hide 1856 */ 1857 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 1858 1859 /** 1860 * Indicates that we should awaken scroll bars once attached 1861 * 1862 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 1863 * during window attachment and it is no longer needed. Feel free to repurpose it. 1864 * 1865 * @hide 1866 */ 1867 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 1868 1869 /** 1870 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 1871 * @hide 1872 */ 1873 private static final int PFLAG_HOVERED = 0x10000000; 1874 1875 /** 1876 * no longer needed, should be reused 1877 */ 1878 private static final int PFLAG_DOES_NOTHING_REUSE_PLEASE = 0x20000000; 1879 1880 /** {@hide} */ 1881 static final int PFLAG_ACTIVATED = 0x40000000; 1882 1883 /** 1884 * Indicates that this view was specifically invalidated, not just dirtied because some 1885 * child view was invalidated. The flag is used to determine when we need to recreate 1886 * a view's display list (as opposed to just returning a reference to its existing 1887 * display list). 1888 * 1889 * @hide 1890 */ 1891 static final int PFLAG_INVALIDATED = 0x80000000; 1892 1893 /** 1894 * Masks for mPrivateFlags2, as generated by dumpFlags(): 1895 * 1896 * |-------|-------|-------|-------| 1897 * 1 PFLAG2_DRAG_CAN_ACCEPT 1898 * 1 PFLAG2_DRAG_HOVERED 1899 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 1900 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 1901 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 1902 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 1903 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 1904 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 1905 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 1906 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 1907 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 1908 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 1909 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 1910 * 111 PFLAG2_TEXT_DIRECTION_MASK 1911 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 1912 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 1913 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 1914 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 1915 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 1916 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 1917 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 1918 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 1919 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 1920 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 1921 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 1922 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 1923 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 1924 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 1925 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 1926 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 1927 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 1928 * 1 PFLAG2_VIEW_QUICK_REJECTED 1929 * 1 PFLAG2_PADDING_RESOLVED 1930 * 1 PFLAG2_DRAWABLE_RESOLVED 1931 * 1 PFLAG2_HAS_TRANSIENT_STATE 1932 * |-------|-------|-------|-------| 1933 */ 1934 1935 /** 1936 * Indicates that this view has reported that it can accept the current drag's content. 1937 * Cleared when the drag operation concludes. 1938 * @hide 1939 */ 1940 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 1941 1942 /** 1943 * Indicates that this view is currently directly under the drag location in a 1944 * drag-and-drop operation involving content that it can accept. Cleared when 1945 * the drag exits the view, or when the drag operation concludes. 1946 * @hide 1947 */ 1948 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 1949 1950 /** @hide */ 1951 @IntDef({ 1952 LAYOUT_DIRECTION_LTR, 1953 LAYOUT_DIRECTION_RTL, 1954 LAYOUT_DIRECTION_INHERIT, 1955 LAYOUT_DIRECTION_LOCALE 1956 }) 1957 @Retention(RetentionPolicy.SOURCE) 1958 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 1959 public @interface LayoutDir {} 1960 1961 /** @hide */ 1962 @IntDef({ 1963 LAYOUT_DIRECTION_LTR, 1964 LAYOUT_DIRECTION_RTL 1965 }) 1966 @Retention(RetentionPolicy.SOURCE) 1967 public @interface ResolvedLayoutDir {} 1968 1969 /** 1970 * A flag to indicate that the layout direction of this view has not been defined yet. 1971 * @hide 1972 */ 1973 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 1974 1975 /** 1976 * Horizontal layout direction of this view is from Left to Right. 1977 * Use with {@link #setLayoutDirection}. 1978 */ 1979 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 1980 1981 /** 1982 * Horizontal layout direction of this view is from Right to Left. 1983 * Use with {@link #setLayoutDirection}. 1984 */ 1985 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 1986 1987 /** 1988 * Horizontal layout direction of this view is inherited from its parent. 1989 * Use with {@link #setLayoutDirection}. 1990 */ 1991 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 1992 1993 /** 1994 * Horizontal layout direction of this view is from deduced from the default language 1995 * script for the locale. Use with {@link #setLayoutDirection}. 1996 */ 1997 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 1998 1999 /** 2000 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2001 * @hide 2002 */ 2003 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2004 2005 /** 2006 * Mask for use with private flags indicating bits used for horizontal layout direction. 2007 * @hide 2008 */ 2009 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2010 2011 /** 2012 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2013 * right-to-left direction. 2014 * @hide 2015 */ 2016 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2017 2018 /** 2019 * Indicates whether the view horizontal layout direction has been resolved. 2020 * @hide 2021 */ 2022 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2023 2024 /** 2025 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2026 * @hide 2027 */ 2028 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2029 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2030 2031 /* 2032 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2033 * flag value. 2034 * @hide 2035 */ 2036 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2037 LAYOUT_DIRECTION_LTR, 2038 LAYOUT_DIRECTION_RTL, 2039 LAYOUT_DIRECTION_INHERIT, 2040 LAYOUT_DIRECTION_LOCALE 2041 }; 2042 2043 /** 2044 * Default horizontal layout direction. 2045 */ 2046 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2047 2048 /** 2049 * Default horizontal layout direction. 2050 * @hide 2051 */ 2052 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2053 2054 /** 2055 * Text direction is inherited through {@link ViewGroup} 2056 */ 2057 public static final int TEXT_DIRECTION_INHERIT = 0; 2058 2059 /** 2060 * Text direction is using "first strong algorithm". The first strong directional character 2061 * determines the paragraph direction. If there is no strong directional character, the 2062 * paragraph direction is the view's resolved layout direction. 2063 */ 2064 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2065 2066 /** 2067 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2068 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2069 * If there are neither, the paragraph direction is the view's resolved layout direction. 2070 */ 2071 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2072 2073 /** 2074 * Text direction is forced to LTR. 2075 */ 2076 public static final int TEXT_DIRECTION_LTR = 3; 2077 2078 /** 2079 * Text direction is forced to RTL. 2080 */ 2081 public static final int TEXT_DIRECTION_RTL = 4; 2082 2083 /** 2084 * Text direction is coming from the system Locale. 2085 */ 2086 public static final int TEXT_DIRECTION_LOCALE = 5; 2087 2088 /** 2089 * Text direction is using "first strong algorithm". The first strong directional character 2090 * determines the paragraph direction. If there is no strong directional character, the 2091 * paragraph direction is LTR. 2092 */ 2093 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2094 2095 /** 2096 * Text direction is using "first strong algorithm". The first strong directional character 2097 * determines the paragraph direction. If there is no strong directional character, the 2098 * paragraph direction is RTL. 2099 */ 2100 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2101 2102 /** 2103 * Default text direction is inherited 2104 */ 2105 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2106 2107 /** 2108 * Default resolved text direction 2109 * @hide 2110 */ 2111 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2112 2113 /** 2114 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2115 * @hide 2116 */ 2117 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2118 2119 /** 2120 * Mask for use with private flags indicating bits used for text direction. 2121 * @hide 2122 */ 2123 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2124 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2125 2126 /** 2127 * Array of text direction flags for mapping attribute "textDirection" to correct 2128 * flag value. 2129 * @hide 2130 */ 2131 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2132 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2133 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2134 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2135 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2136 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2137 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2138 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2139 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2140 }; 2141 2142 /** 2143 * Indicates whether the view text direction has been resolved. 2144 * @hide 2145 */ 2146 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2147 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2148 2149 /** 2150 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2151 * @hide 2152 */ 2153 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2154 2155 /** 2156 * Mask for use with private flags indicating bits used for resolved text direction. 2157 * @hide 2158 */ 2159 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2160 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2161 2162 /** 2163 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2164 * @hide 2165 */ 2166 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2167 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2168 2169 /** @hide */ 2170 @IntDef({ 2171 TEXT_ALIGNMENT_INHERIT, 2172 TEXT_ALIGNMENT_GRAVITY, 2173 TEXT_ALIGNMENT_CENTER, 2174 TEXT_ALIGNMENT_TEXT_START, 2175 TEXT_ALIGNMENT_TEXT_END, 2176 TEXT_ALIGNMENT_VIEW_START, 2177 TEXT_ALIGNMENT_VIEW_END 2178 }) 2179 @Retention(RetentionPolicy.SOURCE) 2180 public @interface TextAlignment {} 2181 2182 /** 2183 * Default text alignment. The text alignment of this View is inherited from its parent. 2184 * Use with {@link #setTextAlignment(int)} 2185 */ 2186 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2187 2188 /** 2189 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2190 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2191 * 2192 * Use with {@link #setTextAlignment(int)} 2193 */ 2194 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2195 2196 /** 2197 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2198 * 2199 * Use with {@link #setTextAlignment(int)} 2200 */ 2201 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2202 2203 /** 2204 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2205 * 2206 * Use with {@link #setTextAlignment(int)} 2207 */ 2208 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2209 2210 /** 2211 * Center the paragraph, e.g. ALIGN_CENTER. 2212 * 2213 * Use with {@link #setTextAlignment(int)} 2214 */ 2215 public static final int TEXT_ALIGNMENT_CENTER = 4; 2216 2217 /** 2218 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2219 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2220 * 2221 * Use with {@link #setTextAlignment(int)} 2222 */ 2223 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2224 2225 /** 2226 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2227 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2228 * 2229 * Use with {@link #setTextAlignment(int)} 2230 */ 2231 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2232 2233 /** 2234 * Default text alignment is inherited 2235 */ 2236 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2237 2238 /** 2239 * Default resolved text alignment 2240 * @hide 2241 */ 2242 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2243 2244 /** 2245 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2246 * @hide 2247 */ 2248 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2249 2250 /** 2251 * Mask for use with private flags indicating bits used for text alignment. 2252 * @hide 2253 */ 2254 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2255 2256 /** 2257 * Array of text direction flags for mapping attribute "textAlignment" to correct 2258 * flag value. 2259 * @hide 2260 */ 2261 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2262 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2263 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2264 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2265 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2266 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2267 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2268 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2269 }; 2270 2271 /** 2272 * Indicates whether the view text alignment has been resolved. 2273 * @hide 2274 */ 2275 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2276 2277 /** 2278 * Bit shift to get the resolved text alignment. 2279 * @hide 2280 */ 2281 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2282 2283 /** 2284 * Mask for use with private flags indicating bits used for text alignment. 2285 * @hide 2286 */ 2287 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2288 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2289 2290 /** 2291 * Indicates whether if the view text alignment has been resolved to gravity 2292 */ 2293 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2294 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2295 2296 // Accessiblity constants for mPrivateFlags2 2297 2298 /** 2299 * Shift for the bits in {@link #mPrivateFlags2} related to the 2300 * "importantForAccessibility" attribute. 2301 */ 2302 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2303 2304 /** 2305 * Automatically determine whether a view is important for accessibility. 2306 */ 2307 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2308 2309 /** 2310 * The view is important for accessibility. 2311 */ 2312 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2313 2314 /** 2315 * The view is not important for accessibility. 2316 */ 2317 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2318 2319 /** 2320 * The view is not important for accessibility, nor are any of its 2321 * descendant views. 2322 */ 2323 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2324 2325 /** 2326 * The default whether the view is important for accessibility. 2327 */ 2328 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2329 2330 /** 2331 * Mask for obtainig the bits which specify how to determine 2332 * whether a view is important for accessibility. 2333 */ 2334 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2335 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2336 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2337 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2338 2339 /** 2340 * Shift for the bits in {@link #mPrivateFlags2} related to the 2341 * "accessibilityLiveRegion" attribute. 2342 */ 2343 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2344 2345 /** 2346 * Live region mode specifying that accessibility services should not 2347 * automatically announce changes to this view. This is the default live 2348 * region mode for most views. 2349 * <p> 2350 * Use with {@link #setAccessibilityLiveRegion(int)}. 2351 */ 2352 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2353 2354 /** 2355 * Live region mode specifying that accessibility services should announce 2356 * changes to this view. 2357 * <p> 2358 * Use with {@link #setAccessibilityLiveRegion(int)}. 2359 */ 2360 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2361 2362 /** 2363 * Live region mode specifying that accessibility services should interrupt 2364 * ongoing speech to immediately announce changes to this view. 2365 * <p> 2366 * Use with {@link #setAccessibilityLiveRegion(int)}. 2367 */ 2368 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2369 2370 /** 2371 * The default whether the view is important for accessibility. 2372 */ 2373 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2374 2375 /** 2376 * Mask for obtaining the bits which specify a view's accessibility live 2377 * region mode. 2378 */ 2379 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2380 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2381 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2382 2383 /** 2384 * Flag indicating whether a view has accessibility focus. 2385 */ 2386 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2387 2388 /** 2389 * Flag whether the accessibility state of the subtree rooted at this view changed. 2390 */ 2391 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2392 2393 /** 2394 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2395 * is used to check whether later changes to the view's transform should invalidate the 2396 * view to force the quickReject test to run again. 2397 */ 2398 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2399 2400 /** 2401 * Flag indicating that start/end padding has been resolved into left/right padding 2402 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2403 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2404 * during measurement. In some special cases this is required such as when an adapter-based 2405 * view measures prospective children without attaching them to a window. 2406 */ 2407 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 2408 2409 /** 2410 * Flag indicating that the start/end drawables has been resolved into left/right ones. 2411 */ 2412 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 2413 2414 /** 2415 * Indicates that the view is tracking some sort of transient state 2416 * that the app should not need to be aware of, but that the framework 2417 * should take special care to preserve. 2418 */ 2419 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 2420 2421 /** 2422 * Group of bits indicating that RTL properties resolution is done. 2423 */ 2424 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 2425 PFLAG2_TEXT_DIRECTION_RESOLVED | 2426 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 2427 PFLAG2_PADDING_RESOLVED | 2428 PFLAG2_DRAWABLE_RESOLVED; 2429 2430 // There are a couple of flags left in mPrivateFlags2 2431 2432 /* End of masks for mPrivateFlags2 */ 2433 2434 /** 2435 * Masks for mPrivateFlags3, as generated by dumpFlags(): 2436 * 2437 * |-------|-------|-------|-------| 2438 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 2439 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 2440 * 1 PFLAG3_IS_LAID_OUT 2441 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 2442 * 1 PFLAG3_CALLED_SUPER 2443 * 1 PFLAG3_APPLYING_INSETS 2444 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 2445 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 2446 * 1 PFLAG3_SCROLL_INDICATOR_TOP 2447 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 2448 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 2449 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 2450 * 1 PFLAG3_SCROLL_INDICATOR_START 2451 * 1 PFLAG3_SCROLL_INDICATOR_END 2452 * 1 PFLAG3_ASSIST_BLOCKED 2453 * 1 PFLAG3_POINTER_ICON_NULL 2454 * 1 PFLAG3_POINTER_ICON_VALUE_START 2455 * 11111111 PFLAG3_POINTER_ICON_MASK 2456 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 2457 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 2458 * 1 PFLAG3_TEMPORARY_DETACH 2459 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 2460 * |-------|-------|-------|-------| 2461 */ 2462 2463 /** 2464 * Flag indicating that view has a transform animation set on it. This is used to track whether 2465 * an animation is cleared between successive frames, in order to tell the associated 2466 * DisplayList to clear its animation matrix. 2467 */ 2468 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 2469 2470 /** 2471 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 2472 * animation is cleared between successive frames, in order to tell the associated 2473 * DisplayList to restore its alpha value. 2474 */ 2475 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 2476 2477 /** 2478 * Flag indicating that the view has been through at least one layout since it 2479 * was last attached to a window. 2480 */ 2481 static final int PFLAG3_IS_LAID_OUT = 0x4; 2482 2483 /** 2484 * Flag indicating that a call to measure() was skipped and should be done 2485 * instead when layout() is invoked. 2486 */ 2487 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 2488 2489 /** 2490 * Flag indicating that an overridden method correctly called down to 2491 * the superclass implementation as required by the API spec. 2492 */ 2493 static final int PFLAG3_CALLED_SUPER = 0x10; 2494 2495 /** 2496 * Flag indicating that we're in the process of applying window insets. 2497 */ 2498 static final int PFLAG3_APPLYING_INSETS = 0x20; 2499 2500 /** 2501 * Flag indicating that we're in the process of fitting system windows using the old method. 2502 */ 2503 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 2504 2505 /** 2506 * Flag indicating that nested scrolling is enabled for this view. 2507 * The view will optionally cooperate with views up its parent chain to allow for 2508 * integrated nested scrolling along the same axis. 2509 */ 2510 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 2511 2512 /** 2513 * Flag indicating that the bottom scroll indicator should be displayed 2514 * when this view can scroll up. 2515 */ 2516 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 2517 2518 /** 2519 * Flag indicating that the bottom scroll indicator should be displayed 2520 * when this view can scroll down. 2521 */ 2522 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 2523 2524 /** 2525 * Flag indicating that the left scroll indicator should be displayed 2526 * when this view can scroll left. 2527 */ 2528 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 2529 2530 /** 2531 * Flag indicating that the right scroll indicator should be displayed 2532 * when this view can scroll right. 2533 */ 2534 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 2535 2536 /** 2537 * Flag indicating that the start scroll indicator should be displayed 2538 * when this view can scroll in the start direction. 2539 */ 2540 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 2541 2542 /** 2543 * Flag indicating that the end scroll indicator should be displayed 2544 * when this view can scroll in the end direction. 2545 */ 2546 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 2547 2548 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 2549 2550 static final int SCROLL_INDICATORS_NONE = 0x0000; 2551 2552 /** 2553 * Mask for use with setFlags indicating bits used for indicating which 2554 * scroll indicators are enabled. 2555 */ 2556 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 2557 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 2558 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 2559 | PFLAG3_SCROLL_INDICATOR_END; 2560 2561 /** 2562 * Left-shift required to translate between public scroll indicator flags 2563 * and internal PFLAGS3 flags. When used as a right-shift, translates 2564 * PFLAGS3 flags to public flags. 2565 */ 2566 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 2567 2568 /** @hide */ 2569 @Retention(RetentionPolicy.SOURCE) 2570 @IntDef(flag = true, 2571 value = { 2572 SCROLL_INDICATOR_TOP, 2573 SCROLL_INDICATOR_BOTTOM, 2574 SCROLL_INDICATOR_LEFT, 2575 SCROLL_INDICATOR_RIGHT, 2576 SCROLL_INDICATOR_START, 2577 SCROLL_INDICATOR_END, 2578 }) 2579 public @interface ScrollIndicators {} 2580 2581 /** 2582 * Scroll indicator direction for the top edge of the view. 2583 * 2584 * @see #setScrollIndicators(int) 2585 * @see #setScrollIndicators(int, int) 2586 * @see #getScrollIndicators() 2587 */ 2588 public static final int SCROLL_INDICATOR_TOP = 2589 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2590 2591 /** 2592 * Scroll indicator direction for the bottom edge of the view. 2593 * 2594 * @see #setScrollIndicators(int) 2595 * @see #setScrollIndicators(int, int) 2596 * @see #getScrollIndicators() 2597 */ 2598 public static final int SCROLL_INDICATOR_BOTTOM = 2599 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2600 2601 /** 2602 * Scroll indicator direction for the left edge of the view. 2603 * 2604 * @see #setScrollIndicators(int) 2605 * @see #setScrollIndicators(int, int) 2606 * @see #getScrollIndicators() 2607 */ 2608 public static final int SCROLL_INDICATOR_LEFT = 2609 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2610 2611 /** 2612 * Scroll indicator direction for the right edge of the view. 2613 * 2614 * @see #setScrollIndicators(int) 2615 * @see #setScrollIndicators(int, int) 2616 * @see #getScrollIndicators() 2617 */ 2618 public static final int SCROLL_INDICATOR_RIGHT = 2619 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2620 2621 /** 2622 * Scroll indicator direction for the starting edge of the view. 2623 * <p> 2624 * Resolved according to the view's layout direction, see 2625 * {@link #getLayoutDirection()} for more information. 2626 * 2627 * @see #setScrollIndicators(int) 2628 * @see #setScrollIndicators(int, int) 2629 * @see #getScrollIndicators() 2630 */ 2631 public static final int SCROLL_INDICATOR_START = 2632 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2633 2634 /** 2635 * Scroll indicator direction for the ending edge of the view. 2636 * <p> 2637 * Resolved according to the view's layout direction, see 2638 * {@link #getLayoutDirection()} for more information. 2639 * 2640 * @see #setScrollIndicators(int) 2641 * @see #setScrollIndicators(int, int) 2642 * @see #getScrollIndicators() 2643 */ 2644 public static final int SCROLL_INDICATOR_END = 2645 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 2646 2647 /** 2648 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 2649 * into this view.<p> 2650 */ 2651 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 2652 2653 /** 2654 * The mask for use with private flags indicating bits used for pointer icon shapes. 2655 */ 2656 static final int PFLAG3_POINTER_ICON_MASK = 0x7f8000; 2657 2658 /** 2659 * Left-shift used for pointer icon shape values in private flags. 2660 */ 2661 static final int PFLAG3_POINTER_ICON_LSHIFT = 15; 2662 2663 /** 2664 * Value indicating no specific pointer icons. 2665 */ 2666 private static final int PFLAG3_POINTER_ICON_NOT_SPECIFIED = 0 << PFLAG3_POINTER_ICON_LSHIFT; 2667 2668 /** 2669 * Value indicating {@link PointerIcon.TYPE_NULL}. 2670 */ 2671 private static final int PFLAG3_POINTER_ICON_NULL = 1 << PFLAG3_POINTER_ICON_LSHIFT; 2672 2673 /** 2674 * The base value for other pointer icon shapes. 2675 */ 2676 private static final int PFLAG3_POINTER_ICON_VALUE_START = 2 << PFLAG3_POINTER_ICON_LSHIFT; 2677 2678 /** 2679 * Whether this view has rendered elements that overlap (see {@link 2680 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 2681 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 2682 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 2683 * determined by whatever {@link #hasOverlappingRendering()} returns. 2684 */ 2685 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 2686 2687 /** 2688 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 2689 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 2690 */ 2691 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 2692 2693 /** 2694 * Flag indicating that the view is temporarily detached from the parent view. 2695 * 2696 * @see #onStartTemporaryDetach() 2697 * @see #onFinishTemporaryDetach() 2698 */ 2699 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 2700 2701 /** 2702 * Flag indicating that the view does not wish to be revealed within its parent 2703 * hierarchy when it gains focus. Expressed in the negative since the historical 2704 * default behavior is to reveal on focus; this flag suppresses that behavior. 2705 * 2706 * @see #setRevealOnFocusHint(boolean) 2707 * @see #getRevealOnFocusHint() 2708 */ 2709 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 2710 2711 /* End of masks for mPrivateFlags3 */ 2712 2713 /** 2714 * Always allow a user to over-scroll this view, provided it is a 2715 * view that can scroll. 2716 * 2717 * @see #getOverScrollMode() 2718 * @see #setOverScrollMode(int) 2719 */ 2720 public static final int OVER_SCROLL_ALWAYS = 0; 2721 2722 /** 2723 * Allow a user to over-scroll this view only if the content is large 2724 * enough to meaningfully scroll, provided it is a view that can scroll. 2725 * 2726 * @see #getOverScrollMode() 2727 * @see #setOverScrollMode(int) 2728 */ 2729 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 2730 2731 /** 2732 * Never allow a user to over-scroll this view. 2733 * 2734 * @see #getOverScrollMode() 2735 * @see #setOverScrollMode(int) 2736 */ 2737 public static final int OVER_SCROLL_NEVER = 2; 2738 2739 /** 2740 * Special constant for {@link #setSystemUiVisibility(int)}: View has 2741 * requested the system UI (status bar) to be visible (the default). 2742 * 2743 * @see #setSystemUiVisibility(int) 2744 */ 2745 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 2746 2747 /** 2748 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 2749 * system UI to enter an unobtrusive "low profile" mode. 2750 * 2751 * <p>This is for use in games, book readers, video players, or any other 2752 * "immersive" application where the usual system chrome is deemed too distracting. 2753 * 2754 * <p>In low profile mode, the status bar and/or navigation icons may dim. 2755 * 2756 * @see #setSystemUiVisibility(int) 2757 */ 2758 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 2759 2760 /** 2761 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 2762 * system navigation be temporarily hidden. 2763 * 2764 * <p>This is an even less obtrusive state than that called for by 2765 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 2766 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 2767 * those to disappear. This is useful (in conjunction with the 2768 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 2769 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 2770 * window flags) for displaying content using every last pixel on the display. 2771 * 2772 * <p>There is a limitation: because navigation controls are so important, the least user 2773 * interaction will cause them to reappear immediately. When this happens, both 2774 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 2775 * so that both elements reappear at the same time. 2776 * 2777 * @see #setSystemUiVisibility(int) 2778 */ 2779 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 2780 2781 /** 2782 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 2783 * into the normal fullscreen mode so that its content can take over the screen 2784 * while still allowing the user to interact with the application. 2785 * 2786 * <p>This has the same visual effect as 2787 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 2788 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 2789 * meaning that non-critical screen decorations (such as the status bar) will be 2790 * hidden while the user is in the View's window, focusing the experience on 2791 * that content. Unlike the window flag, if you are using ActionBar in 2792 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2793 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 2794 * hide the action bar. 2795 * 2796 * <p>This approach to going fullscreen is best used over the window flag when 2797 * it is a transient state -- that is, the application does this at certain 2798 * points in its user interaction where it wants to allow the user to focus 2799 * on content, but not as a continuous state. For situations where the application 2800 * would like to simply stay full screen the entire time (such as a game that 2801 * wants to take over the screen), the 2802 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 2803 * is usually a better approach. The state set here will be removed by the system 2804 * in various situations (such as the user moving to another application) like 2805 * the other system UI states. 2806 * 2807 * <p>When using this flag, the application should provide some easy facility 2808 * for the user to go out of it. A common example would be in an e-book 2809 * reader, where tapping on the screen brings back whatever screen and UI 2810 * decorations that had been hidden while the user was immersed in reading 2811 * the book. 2812 * 2813 * @see #setSystemUiVisibility(int) 2814 */ 2815 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 2816 2817 /** 2818 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 2819 * flags, we would like a stable view of the content insets given to 2820 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 2821 * will always represent the worst case that the application can expect 2822 * as a continuous state. In the stock Android UI this is the space for 2823 * the system bar, nav bar, and status bar, but not more transient elements 2824 * such as an input method. 2825 * 2826 * The stable layout your UI sees is based on the system UI modes you can 2827 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 2828 * then you will get a stable layout for changes of the 2829 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 2830 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 2831 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 2832 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 2833 * with a stable layout. (Note that you should avoid using 2834 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 2835 * 2836 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 2837 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 2838 * then a hidden status bar will be considered a "stable" state for purposes 2839 * here. This allows your UI to continually hide the status bar, while still 2840 * using the system UI flags to hide the action bar while still retaining 2841 * a stable layout. Note that changing the window fullscreen flag will never 2842 * provide a stable layout for a clean transition. 2843 * 2844 * <p>If you are using ActionBar in 2845 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 2846 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 2847 * insets it adds to those given to the application. 2848 */ 2849 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 2850 2851 /** 2852 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2853 * to be laid out as if it has requested 2854 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 2855 * allows it to avoid artifacts when switching in and out of that mode, at 2856 * the expense that some of its user interface may be covered by screen 2857 * decorations when they are shown. You can perform layout of your inner 2858 * UI elements to account for the navigation system UI through the 2859 * {@link #fitSystemWindows(Rect)} method. 2860 */ 2861 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 2862 2863 /** 2864 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 2865 * to be laid out as if it has requested 2866 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 2867 * allows it to avoid artifacts when switching in and out of that mode, at 2868 * the expense that some of its user interface may be covered by screen 2869 * decorations when they are shown. You can perform layout of your inner 2870 * UI elements to account for non-fullscreen system UI through the 2871 * {@link #fitSystemWindows(Rect)} method. 2872 */ 2873 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 2874 2875 /** 2876 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2877 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 2878 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 2879 * user interaction. 2880 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 2881 * has an effect when used in combination with that flag.</p> 2882 */ 2883 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 2884 2885 /** 2886 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 2887 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 2888 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 2889 * experience while also hiding the system bars. If this flag is not set, 2890 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 2891 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 2892 * if the user swipes from the top of the screen. 2893 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 2894 * system gestures, such as swiping from the top of the screen. These transient system bars 2895 * will overlay app’s content, may have some degree of transparency, and will automatically 2896 * hide after a short timeout. 2897 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 2898 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 2899 * with one or both of those flags.</p> 2900 */ 2901 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 2902 2903 /** 2904 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 2905 * is compatible with light status bar backgrounds. 2906 * 2907 * <p>For this to take effect, the window must request 2908 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 2909 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 2910 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 2911 * FLAG_TRANSLUCENT_STATUS}. 2912 * 2913 * @see android.R.attr#windowLightStatusBar 2914 */ 2915 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 2916 2917 /** 2918 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 2919 */ 2920 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 2921 2922 /** 2923 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 2924 */ 2925 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 2926 2927 /** 2928 * @hide 2929 * 2930 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2931 * out of the public fields to keep the undefined bits out of the developer's way. 2932 * 2933 * Flag to make the status bar not expandable. Unless you also 2934 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 2935 */ 2936 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 2937 2938 /** 2939 * @hide 2940 * 2941 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2942 * out of the public fields to keep the undefined bits out of the developer's way. 2943 * 2944 * Flag to hide notification icons and scrolling ticker text. 2945 */ 2946 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 2947 2948 /** 2949 * @hide 2950 * 2951 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2952 * out of the public fields to keep the undefined bits out of the developer's way. 2953 * 2954 * Flag to disable incoming notification alerts. This will not block 2955 * icons, but it will block sound, vibrating and other visual or aural notifications. 2956 */ 2957 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 2958 2959 /** 2960 * @hide 2961 * 2962 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2963 * out of the public fields to keep the undefined bits out of the developer's way. 2964 * 2965 * Flag to hide only the scrolling ticker. Note that 2966 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 2967 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 2968 */ 2969 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 2970 2971 /** 2972 * @hide 2973 * 2974 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2975 * out of the public fields to keep the undefined bits out of the developer's way. 2976 * 2977 * Flag to hide the center system info area. 2978 */ 2979 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 2980 2981 /** 2982 * @hide 2983 * 2984 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2985 * out of the public fields to keep the undefined bits out of the developer's way. 2986 * 2987 * Flag to hide only the home button. Don't use this 2988 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 2989 */ 2990 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 2991 2992 /** 2993 * @hide 2994 * 2995 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 2996 * out of the public fields to keep the undefined bits out of the developer's way. 2997 * 2998 * Flag to hide only the back button. Don't use this 2999 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3000 */ 3001 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3002 3003 /** 3004 * @hide 3005 * 3006 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3007 * out of the public fields to keep the undefined bits out of the developer's way. 3008 * 3009 * Flag to hide only the clock. You might use this if your activity has 3010 * its own clock making the status bar's clock redundant. 3011 */ 3012 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3013 3014 /** 3015 * @hide 3016 * 3017 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3018 * out of the public fields to keep the undefined bits out of the developer's way. 3019 * 3020 * Flag to hide only the recent apps button. Don't use this 3021 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3022 */ 3023 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3024 3025 /** 3026 * @hide 3027 * 3028 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3029 * out of the public fields to keep the undefined bits out of the developer's way. 3030 * 3031 * Flag to disable the global search gesture. Don't use this 3032 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3033 */ 3034 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3035 3036 /** 3037 * @hide 3038 * 3039 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3040 * out of the public fields to keep the undefined bits out of the developer's way. 3041 * 3042 * Flag to specify that the status bar is displayed in transient mode. 3043 */ 3044 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3045 3046 /** 3047 * @hide 3048 * 3049 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3050 * out of the public fields to keep the undefined bits out of the developer's way. 3051 * 3052 * Flag to specify that the navigation bar is displayed in transient mode. 3053 */ 3054 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3055 3056 /** 3057 * @hide 3058 * 3059 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3060 * out of the public fields to keep the undefined bits out of the developer's way. 3061 * 3062 * Flag to specify that the hidden status bar would like to be shown. 3063 */ 3064 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3065 3066 /** 3067 * @hide 3068 * 3069 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3070 * out of the public fields to keep the undefined bits out of the developer's way. 3071 * 3072 * Flag to specify that the hidden navigation bar would like to be shown. 3073 */ 3074 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3075 3076 /** 3077 * @hide 3078 * 3079 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3080 * out of the public fields to keep the undefined bits out of the developer's way. 3081 * 3082 * Flag to specify that the status bar is displayed in translucent mode. 3083 */ 3084 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3085 3086 /** 3087 * @hide 3088 * 3089 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3090 * out of the public fields to keep the undefined bits out of the developer's way. 3091 * 3092 * Flag to specify that the navigation bar is displayed in translucent mode. 3093 */ 3094 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3095 3096 /** 3097 * @hide 3098 * 3099 * Makes navigation bar transparent (but not the status bar). 3100 */ 3101 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3102 3103 /** 3104 * @hide 3105 * 3106 * Makes status bar transparent (but not the navigation bar). 3107 */ 3108 public static final int STATUS_BAR_TRANSPARENT = 0x0000008; 3109 3110 /** 3111 * @hide 3112 * 3113 * Makes both status bar and navigation bar transparent. 3114 */ 3115 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3116 | STATUS_BAR_TRANSPARENT; 3117 3118 /** 3119 * @hide 3120 */ 3121 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3122 3123 /** 3124 * These are the system UI flags that can be cleared by events outside 3125 * of an application. Currently this is just the ability to tap on the 3126 * screen while hiding the navigation bar to have it return. 3127 * @hide 3128 */ 3129 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3130 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3131 | SYSTEM_UI_FLAG_FULLSCREEN; 3132 3133 /** 3134 * Flags that can impact the layout in relation to system UI. 3135 */ 3136 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3137 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3138 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3139 3140 /** @hide */ 3141 @IntDef(flag = true, 3142 value = { FIND_VIEWS_WITH_TEXT, FIND_VIEWS_WITH_CONTENT_DESCRIPTION }) 3143 @Retention(RetentionPolicy.SOURCE) 3144 public @interface FindViewFlags {} 3145 3146 /** 3147 * Find views that render the specified text. 3148 * 3149 * @see #findViewsWithText(ArrayList, CharSequence, int) 3150 */ 3151 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3152 3153 /** 3154 * Find find views that contain the specified content description. 3155 * 3156 * @see #findViewsWithText(ArrayList, CharSequence, int) 3157 */ 3158 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3159 3160 /** 3161 * Find views that contain {@link AccessibilityNodeProvider}. Such 3162 * a View is a root of virtual view hierarchy and may contain the searched 3163 * text. If this flag is set Views with providers are automatically 3164 * added and it is a responsibility of the client to call the APIs of 3165 * the provider to determine whether the virtual tree rooted at this View 3166 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3167 * representing the virtual views with this text. 3168 * 3169 * @see #findViewsWithText(ArrayList, CharSequence, int) 3170 * 3171 * @hide 3172 */ 3173 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3174 3175 /** 3176 * The undefined cursor position. 3177 * 3178 * @hide 3179 */ 3180 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3181 3182 /** 3183 * Indicates that the screen has changed state and is now off. 3184 * 3185 * @see #onScreenStateChanged(int) 3186 */ 3187 public static final int SCREEN_STATE_OFF = 0x0; 3188 3189 /** 3190 * Indicates that the screen has changed state and is now on. 3191 * 3192 * @see #onScreenStateChanged(int) 3193 */ 3194 public static final int SCREEN_STATE_ON = 0x1; 3195 3196 /** 3197 * Indicates no axis of view scrolling. 3198 */ 3199 public static final int SCROLL_AXIS_NONE = 0; 3200 3201 /** 3202 * Indicates scrolling along the horizontal axis. 3203 */ 3204 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3205 3206 /** 3207 * Indicates scrolling along the vertical axis. 3208 */ 3209 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3210 3211 /** 3212 * Controls the over-scroll mode for this view. 3213 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3214 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3215 * and {@link #OVER_SCROLL_NEVER}. 3216 */ 3217 private int mOverScrollMode; 3218 3219 /** 3220 * The parent this view is attached to. 3221 * {@hide} 3222 * 3223 * @see #getParent() 3224 */ 3225 protected ViewParent mParent; 3226 3227 /** 3228 * {@hide} 3229 */ 3230 AttachInfo mAttachInfo; 3231 3232 /** 3233 * {@hide} 3234 */ 3235 @ViewDebug.ExportedProperty(flagMapping = { 3236 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3237 name = "FORCE_LAYOUT"), 3238 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3239 name = "LAYOUT_REQUIRED"), 3240 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3241 name = "DRAWING_CACHE_INVALID", outputIf = false), 3242 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3243 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3244 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY_OPAQUE, name = "DIRTY_OPAQUE"), 3245 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3246 }, formatToHexString = true) 3247 int mPrivateFlags; 3248 int mPrivateFlags2; 3249 int mPrivateFlags3; 3250 3251 /** 3252 * This view's request for the visibility of the status bar. 3253 * @hide 3254 */ 3255 @ViewDebug.ExportedProperty(flagMapping = { 3256 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3257 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3258 name = "SYSTEM_UI_FLAG_LOW_PROFILE", outputIf = true), 3259 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3260 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3261 name = "SYSTEM_UI_FLAG_HIDE_NAVIGATION", outputIf = true), 3262 @ViewDebug.FlagToString(mask = PUBLIC_STATUS_BAR_VISIBILITY_MASK, 3263 equals = SYSTEM_UI_FLAG_VISIBLE, 3264 name = "SYSTEM_UI_FLAG_VISIBLE", outputIf = true) 3265 }, formatToHexString = true) 3266 int mSystemUiVisibility; 3267 3268 /** 3269 * Reference count for transient state. 3270 * @see #setHasTransientState(boolean) 3271 */ 3272 int mTransientStateCount = 0; 3273 3274 /** 3275 * Count of how many windows this view has been attached to. 3276 */ 3277 int mWindowAttachCount; 3278 3279 /** 3280 * The layout parameters associated with this view and used by the parent 3281 * {@link android.view.ViewGroup} to determine how this view should be 3282 * laid out. 3283 * {@hide} 3284 */ 3285 protected ViewGroup.LayoutParams mLayoutParams; 3286 3287 /** 3288 * The view flags hold various views states. 3289 * {@hide} 3290 */ 3291 @ViewDebug.ExportedProperty(formatToHexString = true) 3292 int mViewFlags; 3293 3294 static class TransformationInfo { 3295 /** 3296 * The transform matrix for the View. This transform is calculated internally 3297 * based on the translation, rotation, and scale properties. 3298 * 3299 * Do *not* use this variable directly; instead call getMatrix(), which will 3300 * load the value from the View's RenderNode. 3301 */ 3302 private final Matrix mMatrix = new Matrix(); 3303 3304 /** 3305 * The inverse transform matrix for the View. This transform is calculated 3306 * internally based on the translation, rotation, and scale properties. 3307 * 3308 * Do *not* use this variable directly; instead call getInverseMatrix(), 3309 * which will load the value from the View's RenderNode. 3310 */ 3311 private Matrix mInverseMatrix; 3312 3313 /** 3314 * The opacity of the View. This is a value from 0 to 1, where 0 means 3315 * completely transparent and 1 means completely opaque. 3316 */ 3317 @ViewDebug.ExportedProperty 3318 float mAlpha = 1f; 3319 3320 /** 3321 * The opacity of the view as manipulated by the Fade transition. This is a hidden 3322 * property only used by transitions, which is composited with the other alpha 3323 * values to calculate the final visual alpha value. 3324 */ 3325 float mTransitionAlpha = 1f; 3326 } 3327 3328 TransformationInfo mTransformationInfo; 3329 3330 /** 3331 * Current clip bounds. to which all drawing of this view are constrained. 3332 */ 3333 Rect mClipBounds = null; 3334 3335 private boolean mLastIsOpaque; 3336 3337 /** 3338 * The distance in pixels from the left edge of this view's parent 3339 * to the left edge of this view. 3340 * {@hide} 3341 */ 3342 @ViewDebug.ExportedProperty(category = "layout") 3343 protected int mLeft; 3344 /** 3345 * The distance in pixels from the left edge of this view's parent 3346 * to the right edge of this view. 3347 * {@hide} 3348 */ 3349 @ViewDebug.ExportedProperty(category = "layout") 3350 protected int mRight; 3351 /** 3352 * The distance in pixels from the top edge of this view's parent 3353 * to the top edge of this view. 3354 * {@hide} 3355 */ 3356 @ViewDebug.ExportedProperty(category = "layout") 3357 protected int mTop; 3358 /** 3359 * The distance in pixels from the top edge of this view's parent 3360 * to the bottom edge of this view. 3361 * {@hide} 3362 */ 3363 @ViewDebug.ExportedProperty(category = "layout") 3364 protected int mBottom; 3365 3366 /** 3367 * The offset, in pixels, by which the content of this view is scrolled 3368 * horizontally. 3369 * {@hide} 3370 */ 3371 @ViewDebug.ExportedProperty(category = "scrolling") 3372 protected int mScrollX; 3373 /** 3374 * The offset, in pixels, by which the content of this view is scrolled 3375 * vertically. 3376 * {@hide} 3377 */ 3378 @ViewDebug.ExportedProperty(category = "scrolling") 3379 protected int mScrollY; 3380 3381 /** 3382 * The left padding in pixels, that is the distance in pixels between the 3383 * left edge of this view and the left edge of its content. 3384 * {@hide} 3385 */ 3386 @ViewDebug.ExportedProperty(category = "padding") 3387 protected int mPaddingLeft = 0; 3388 /** 3389 * The right padding in pixels, that is the distance in pixels between the 3390 * right edge of this view and the right edge of its content. 3391 * {@hide} 3392 */ 3393 @ViewDebug.ExportedProperty(category = "padding") 3394 protected int mPaddingRight = 0; 3395 /** 3396 * The top padding in pixels, that is the distance in pixels between the 3397 * top edge of this view and the top edge of its content. 3398 * {@hide} 3399 */ 3400 @ViewDebug.ExportedProperty(category = "padding") 3401 protected int mPaddingTop; 3402 /** 3403 * The bottom padding in pixels, that is the distance in pixels between the 3404 * bottom edge of this view and the bottom edge of its content. 3405 * {@hide} 3406 */ 3407 @ViewDebug.ExportedProperty(category = "padding") 3408 protected int mPaddingBottom; 3409 3410 /** 3411 * The layout insets in pixels, that is the distance in pixels between the 3412 * visible edges of this view its bounds. 3413 */ 3414 private Insets mLayoutInsets; 3415 3416 /** 3417 * Briefly describes the view and is primarily used for accessibility support. 3418 */ 3419 private CharSequence mContentDescription; 3420 3421 /** 3422 * Specifies the id of a view for which this view serves as a label for 3423 * accessibility purposes. 3424 */ 3425 private int mLabelForId = View.NO_ID; 3426 3427 /** 3428 * Predicate for matching labeled view id with its label for 3429 * accessibility purposes. 3430 */ 3431 private MatchLabelForPredicate mMatchLabelForPredicate; 3432 3433 /** 3434 * Specifies a view before which this one is visited in accessibility traversal. 3435 */ 3436 private int mAccessibilityTraversalBeforeId = NO_ID; 3437 3438 /** 3439 * Specifies a view after which this one is visited in accessibility traversal. 3440 */ 3441 private int mAccessibilityTraversalAfterId = NO_ID; 3442 3443 /** 3444 * Predicate for matching a view by its id. 3445 */ 3446 private MatchIdPredicate mMatchIdPredicate; 3447 3448 /** 3449 * Cache the paddingRight set by the user to append to the scrollbar's size. 3450 * 3451 * @hide 3452 */ 3453 @ViewDebug.ExportedProperty(category = "padding") 3454 protected int mUserPaddingRight; 3455 3456 /** 3457 * Cache the paddingBottom set by the user to append to the scrollbar's size. 3458 * 3459 * @hide 3460 */ 3461 @ViewDebug.ExportedProperty(category = "padding") 3462 protected int mUserPaddingBottom; 3463 3464 /** 3465 * Cache the paddingLeft set by the user to append to the scrollbar's size. 3466 * 3467 * @hide 3468 */ 3469 @ViewDebug.ExportedProperty(category = "padding") 3470 protected int mUserPaddingLeft; 3471 3472 /** 3473 * Cache the paddingStart set by the user to append to the scrollbar's size. 3474 * 3475 */ 3476 @ViewDebug.ExportedProperty(category = "padding") 3477 int mUserPaddingStart; 3478 3479 /** 3480 * Cache the paddingEnd set by the user to append to the scrollbar's size. 3481 * 3482 */ 3483 @ViewDebug.ExportedProperty(category = "padding") 3484 int mUserPaddingEnd; 3485 3486 /** 3487 * Cache initial left padding. 3488 * 3489 * @hide 3490 */ 3491 int mUserPaddingLeftInitial; 3492 3493 /** 3494 * Cache initial right padding. 3495 * 3496 * @hide 3497 */ 3498 int mUserPaddingRightInitial; 3499 3500 /** 3501 * Default undefined padding 3502 */ 3503 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 3504 3505 /** 3506 * Cache if a left padding has been defined 3507 */ 3508 private boolean mLeftPaddingDefined = false; 3509 3510 /** 3511 * Cache if a right padding has been defined 3512 */ 3513 private boolean mRightPaddingDefined = false; 3514 3515 /** 3516 * @hide 3517 */ 3518 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 3519 /** 3520 * @hide 3521 */ 3522 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 3523 3524 private LongSparseLongArray mMeasureCache; 3525 3526 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 3527 private Drawable mBackground; 3528 private TintInfo mBackgroundTint; 3529 3530 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 3531 private ForegroundInfo mForegroundInfo; 3532 3533 private Drawable mScrollIndicatorDrawable; 3534 3535 /** 3536 * RenderNode used for backgrounds. 3537 * <p> 3538 * When non-null and valid, this is expected to contain an up-to-date copy 3539 * of the background drawable. It is cleared on temporary detach, and reset 3540 * on cleanup. 3541 */ 3542 private RenderNode mBackgroundRenderNode; 3543 3544 private int mBackgroundResource; 3545 private boolean mBackgroundSizeChanged; 3546 3547 private String mTransitionName; 3548 3549 static class TintInfo { 3550 ColorStateList mTintList; 3551 PorterDuff.Mode mTintMode; 3552 boolean mHasTintMode; 3553 boolean mHasTintList; 3554 } 3555 3556 private static class ForegroundInfo { 3557 private Drawable mDrawable; 3558 private TintInfo mTintInfo; 3559 private int mGravity = Gravity.FILL; 3560 private boolean mInsidePadding = true; 3561 private boolean mBoundsChanged = true; 3562 private final Rect mSelfBounds = new Rect(); 3563 private final Rect mOverlayBounds = new Rect(); 3564 } 3565 3566 static class ListenerInfo { 3567 /** 3568 * Listener used to dispatch focus change events. 3569 * This field should be made private, so it is hidden from the SDK. 3570 * {@hide} 3571 */ 3572 protected OnFocusChangeListener mOnFocusChangeListener; 3573 3574 /** 3575 * Listeners for layout change events. 3576 */ 3577 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 3578 3579 protected OnScrollChangeListener mOnScrollChangeListener; 3580 3581 /** 3582 * Listeners for attach events. 3583 */ 3584 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 3585 3586 /** 3587 * Listener used to dispatch click events. 3588 * This field should be made private, so it is hidden from the SDK. 3589 * {@hide} 3590 */ 3591 public OnClickListener mOnClickListener; 3592 3593 /** 3594 * Listener used to dispatch long click events. 3595 * This field should be made private, so it is hidden from the SDK. 3596 * {@hide} 3597 */ 3598 protected OnLongClickListener mOnLongClickListener; 3599 3600 /** 3601 * Listener used to dispatch context click events. This field should be made private, so it 3602 * is hidden from the SDK. 3603 * {@hide} 3604 */ 3605 protected OnContextClickListener mOnContextClickListener; 3606 3607 /** 3608 * Listener used to build the context menu. 3609 * This field should be made private, so it is hidden from the SDK. 3610 * {@hide} 3611 */ 3612 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 3613 3614 private OnKeyListener mOnKeyListener; 3615 3616 private OnTouchListener mOnTouchListener; 3617 3618 private OnHoverListener mOnHoverListener; 3619 3620 private OnGenericMotionListener mOnGenericMotionListener; 3621 3622 private OnDragListener mOnDragListener; 3623 3624 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 3625 3626 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 3627 } 3628 3629 ListenerInfo mListenerInfo; 3630 3631 // Temporary values used to hold (x,y) coordinates when delegating from the 3632 // two-arg performLongClick() method to the legacy no-arg version. 3633 private float mLongClickX = Float.NaN; 3634 private float mLongClickY = Float.NaN; 3635 3636 /** 3637 * The application environment this view lives in. 3638 * This field should be made private, so it is hidden from the SDK. 3639 * {@hide} 3640 */ 3641 @ViewDebug.ExportedProperty(deepExport = true) 3642 protected Context mContext; 3643 3644 private final Resources mResources; 3645 3646 private ScrollabilityCache mScrollCache; 3647 3648 private int[] mDrawableState = null; 3649 3650 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 3651 3652 /** 3653 * Animator that automatically runs based on state changes. 3654 */ 3655 private StateListAnimator mStateListAnimator; 3656 3657 /** 3658 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 3659 * the user may specify which view to go to next. 3660 */ 3661 private int mNextFocusLeftId = View.NO_ID; 3662 3663 /** 3664 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 3665 * the user may specify which view to go to next. 3666 */ 3667 private int mNextFocusRightId = View.NO_ID; 3668 3669 /** 3670 * When this view has focus and the next focus is {@link #FOCUS_UP}, 3671 * the user may specify which view to go to next. 3672 */ 3673 private int mNextFocusUpId = View.NO_ID; 3674 3675 /** 3676 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 3677 * the user may specify which view to go to next. 3678 */ 3679 private int mNextFocusDownId = View.NO_ID; 3680 3681 /** 3682 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 3683 * the user may specify which view to go to next. 3684 */ 3685 int mNextFocusForwardId = View.NO_ID; 3686 3687 private CheckForLongPress mPendingCheckForLongPress; 3688 private CheckForTap mPendingCheckForTap = null; 3689 private PerformClick mPerformClick; 3690 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 3691 3692 private UnsetPressedState mUnsetPressedState; 3693 3694 /** 3695 * Whether the long press's action has been invoked. The tap's action is invoked on the 3696 * up event while a long press is invoked as soon as the long press duration is reached, so 3697 * a long press could be performed before the tap is checked, in which case the tap's action 3698 * should not be invoked. 3699 */ 3700 private boolean mHasPerformedLongPress; 3701 3702 /** 3703 * Whether a context click button is currently pressed down. This is true when the stylus is 3704 * touching the screen and the primary button has been pressed, or if a mouse's right button is 3705 * pressed. This is false once the button is released or if the stylus has been lifted. 3706 */ 3707 private boolean mInContextButtonPress; 3708 3709 /** 3710 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 3711 * true after a stylus button press has occured, when the next up event should not be recognized 3712 * as a tap. 3713 */ 3714 private boolean mIgnoreNextUpEvent; 3715 3716 /** 3717 * The minimum height of the view. We'll try our best to have the height 3718 * of this view to at least this amount. 3719 */ 3720 @ViewDebug.ExportedProperty(category = "measurement") 3721 private int mMinHeight; 3722 3723 /** 3724 * The minimum width of the view. We'll try our best to have the width 3725 * of this view to at least this amount. 3726 */ 3727 @ViewDebug.ExportedProperty(category = "measurement") 3728 private int mMinWidth; 3729 3730 /** 3731 * The delegate to handle touch events that are physically in this view 3732 * but should be handled by another view. 3733 */ 3734 private TouchDelegate mTouchDelegate = null; 3735 3736 /** 3737 * Solid color to use as a background when creating the drawing cache. Enables 3738 * the cache to use 16 bit bitmaps instead of 32 bit. 3739 */ 3740 private int mDrawingCacheBackgroundColor = 0; 3741 3742 /** 3743 * Special tree observer used when mAttachInfo is null. 3744 */ 3745 private ViewTreeObserver mFloatingTreeObserver; 3746 3747 /** 3748 * Cache the touch slop from the context that created the view. 3749 */ 3750 private int mTouchSlop; 3751 3752 /** 3753 * Object that handles automatic animation of view properties. 3754 */ 3755 private ViewPropertyAnimator mAnimator = null; 3756 3757 /** 3758 * List of registered FrameMetricsObservers. 3759 */ 3760 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 3761 3762 /** 3763 * Flag indicating that a drag can cross window boundaries. When 3764 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3765 * with this flag set, all visible applications with targetSdkVersion >= 3766 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 3767 * in the drag operation and receive the dragged content. 3768 * 3769 * <p>If this is the only flag set, then the drag recipient will only have access to text data 3770 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 3771 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 3772 */ 3773 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 3774 3775 /** 3776 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3777 * request read access to the content URI(s) contained in the {@link ClipData} object. 3778 * @see android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION 3779 */ 3780 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3781 3782 /** 3783 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 3784 * request write access to the content URI(s) contained in the {@link ClipData} object. 3785 * @see android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION 3786 */ 3787 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3788 3789 /** 3790 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3791 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 3792 * reboots until explicitly revoked with 3793 * {@link android.content.Context#revokeUriPermission(Uri,int) Context.revokeUriPermission}. 3794 * @see android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION 3795 */ 3796 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 3797 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 3798 3799 /** 3800 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 3801 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 3802 * match against the original granted URI. 3803 * @see android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION 3804 */ 3805 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 3806 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 3807 3808 /** 3809 * Flag indicating that the drag shadow will be opaque. When 3810 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 3811 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 3812 */ 3813 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 3814 3815 /** 3816 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 3817 */ 3818 private float mVerticalScrollFactor; 3819 3820 /** 3821 * Position of the vertical scroll bar. 3822 */ 3823 private int mVerticalScrollbarPosition; 3824 3825 /** 3826 * Position the scroll bar at the default position as determined by the system. 3827 */ 3828 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 3829 3830 /** 3831 * Position the scroll bar along the left edge. 3832 */ 3833 public static final int SCROLLBAR_POSITION_LEFT = 1; 3834 3835 /** 3836 * Position the scroll bar along the right edge. 3837 */ 3838 public static final int SCROLLBAR_POSITION_RIGHT = 2; 3839 3840 /** 3841 * Indicates that the view does not have a layer. 3842 * 3843 * @see #getLayerType() 3844 * @see #setLayerType(int, android.graphics.Paint) 3845 * @see #LAYER_TYPE_SOFTWARE 3846 * @see #LAYER_TYPE_HARDWARE 3847 */ 3848 public static final int LAYER_TYPE_NONE = 0; 3849 3850 /** 3851 * <p>Indicates that the view has a software layer. A software layer is backed 3852 * by a bitmap and causes the view to be rendered using Android's software 3853 * rendering pipeline, even if hardware acceleration is enabled.</p> 3854 * 3855 * <p>Software layers have various usages:</p> 3856 * <p>When the application is not using hardware acceleration, a software layer 3857 * is useful to apply a specific color filter and/or blending mode and/or 3858 * translucency to a view and all its children.</p> 3859 * <p>When the application is using hardware acceleration, a software layer 3860 * is useful to render drawing primitives not supported by the hardware 3861 * accelerated pipeline. It can also be used to cache a complex view tree 3862 * into a texture and reduce the complexity of drawing operations. For instance, 3863 * when animating a complex view tree with a translation, a software layer can 3864 * be used to render the view tree only once.</p> 3865 * <p>Software layers should be avoided when the affected view tree updates 3866 * often. Every update will require to re-render the software layer, which can 3867 * potentially be slow (particularly when hardware acceleration is turned on 3868 * since the layer will have to be uploaded into a hardware texture after every 3869 * update.)</p> 3870 * 3871 * @see #getLayerType() 3872 * @see #setLayerType(int, android.graphics.Paint) 3873 * @see #LAYER_TYPE_NONE 3874 * @see #LAYER_TYPE_HARDWARE 3875 */ 3876 public static final int LAYER_TYPE_SOFTWARE = 1; 3877 3878 /** 3879 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 3880 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 3881 * OpenGL hardware) and causes the view to be rendered using Android's hardware 3882 * rendering pipeline, but only if hardware acceleration is turned on for the 3883 * view hierarchy. When hardware acceleration is turned off, hardware layers 3884 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 3885 * 3886 * <p>A hardware layer is useful to apply a specific color filter and/or 3887 * blending mode and/or translucency to a view and all its children.</p> 3888 * <p>A hardware layer can be used to cache a complex view tree into a 3889 * texture and reduce the complexity of drawing operations. For instance, 3890 * when animating a complex view tree with a translation, a hardware layer can 3891 * be used to render the view tree only once.</p> 3892 * <p>A hardware layer can also be used to increase the rendering quality when 3893 * rotation transformations are applied on a view. It can also be used to 3894 * prevent potential clipping issues when applying 3D transforms on a view.</p> 3895 * 3896 * @see #getLayerType() 3897 * @see #setLayerType(int, android.graphics.Paint) 3898 * @see #LAYER_TYPE_NONE 3899 * @see #LAYER_TYPE_SOFTWARE 3900 */ 3901 public static final int LAYER_TYPE_HARDWARE = 2; 3902 3903 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 3904 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 3905 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 3906 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 3907 }) 3908 int mLayerType = LAYER_TYPE_NONE; 3909 Paint mLayerPaint; 3910 3911 /** 3912 * Set to true when drawing cache is enabled and cannot be created. 3913 * 3914 * @hide 3915 */ 3916 public boolean mCachingFailed; 3917 private Bitmap mDrawingCache; 3918 private Bitmap mUnscaledDrawingCache; 3919 3920 /** 3921 * RenderNode holding View properties, potentially holding a DisplayList of View content. 3922 * <p> 3923 * When non-null and valid, this is expected to contain an up-to-date copy 3924 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 3925 * cleanup. 3926 */ 3927 final RenderNode mRenderNode; 3928 3929 /** 3930 * Set to true when the view is sending hover accessibility events because it 3931 * is the innermost hovered view. 3932 */ 3933 private boolean mSendingHoverAccessibilityEvents; 3934 3935 /** 3936 * Delegate for injecting accessibility functionality. 3937 */ 3938 AccessibilityDelegate mAccessibilityDelegate; 3939 3940 /** 3941 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 3942 * and add/remove objects to/from the overlay directly through the Overlay methods. 3943 */ 3944 ViewOverlay mOverlay; 3945 3946 /** 3947 * The currently active parent view for receiving delegated nested scrolling events. 3948 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 3949 * by {@link #stopNestedScroll()} at the same point where we clear 3950 * requestDisallowInterceptTouchEvent. 3951 */ 3952 private ViewParent mNestedScrollingParent; 3953 3954 /** 3955 * Consistency verifier for debugging purposes. 3956 * @hide 3957 */ 3958 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 3959 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 3960 new InputEventConsistencyVerifier(this, 0) : null; 3961 3962 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 3963 3964 private int[] mTempNestedScrollConsumed; 3965 3966 /** 3967 * An overlay is going to draw this View instead of being drawn as part of this 3968 * View's parent. mGhostView is the View in the Overlay that must be invalidated 3969 * when this view is invalidated. 3970 */ 3971 GhostView mGhostView; 3972 3973 /** 3974 * Holds pairs of adjacent attribute data: attribute name followed by its value. 3975 * @hide 3976 */ 3977 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 3978 public String[] mAttributes; 3979 3980 /** 3981 * Maps a Resource id to its name. 3982 */ 3983 private static SparseArray<String> mAttributeMap; 3984 3985 /** 3986 * Queue of pending runnables. Used to postpone calls to post() until this 3987 * view is attached and has a handler. 3988 */ 3989 private HandlerActionQueue mRunQueue; 3990 3991 /** 3992 * The pointer icon when the mouse hovers on this view. The default is null. 3993 */ 3994 private PointerIcon mPointerIcon; 3995 3996 /** 3997 * @hide 3998 */ 3999 String mStartActivityRequestWho; 4000 4001 @Nullable 4002 private RoundScrollbarRenderer mRoundScrollbarRenderer; 4003 4004 /** 4005 * Simple constructor to use when creating a view from code. 4006 * 4007 * @param context The Context the view is running in, through which it can 4008 * access the current theme, resources, etc. 4009 */ View(Context context)4010 public View(Context context) { 4011 mContext = context; 4012 mResources = context != null ? context.getResources() : null; 4013 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED; 4014 // Set some flags defaults 4015 mPrivateFlags2 = 4016 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 4017 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 4018 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 4019 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 4020 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 4021 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 4022 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 4023 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 4024 mUserPaddingStart = UNDEFINED_PADDING; 4025 mUserPaddingEnd = UNDEFINED_PADDING; 4026 mRenderNode = RenderNode.create(getClass().getName(), this); 4027 4028 if (!sCompatibilityDone && context != null) { 4029 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4030 4031 // Older apps may need this compatibility hack for measurement. 4032 sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1; 4033 4034 // Older apps expect onMeasure() to always be called on a layout pass, regardless 4035 // of whether a layout was requested on that View. 4036 sIgnoreMeasureCache = targetSdkVersion < KITKAT; 4037 4038 Canvas.sCompatibilityRestore = targetSdkVersion < M; 4039 4040 // In M and newer, our widgets can pass a "hint" value in the size 4041 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 4042 // know what the expected parent size is going to be, so e.g. list items can size 4043 // themselves at 1/3 the size of their container. It breaks older apps though, 4044 // specifically apps that use some popular open source libraries. 4045 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M; 4046 4047 // Old versions of the platform would give different results from 4048 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 4049 // modes, so we always need to run an additional EXACTLY pass. 4050 sAlwaysRemeasureExactly = targetSdkVersion <= M; 4051 4052 // Prior to N, layout params could change without requiring a 4053 // subsequent call to setLayoutParams() and they would usually 4054 // work. Partial layout breaks this assumption. 4055 sLayoutParamsAlwaysChanged = targetSdkVersion <= M; 4056 4057 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 4058 // On N+, we throw, but that breaks compatibility with apps that use these methods. 4059 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M; 4060 4061 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 4062 // in apps so we target check it to avoid breaking existing apps. 4063 sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N; 4064 4065 sCascadedDragDrop = targetSdkVersion < N; 4066 4067 sCompatibilityDone = true; 4068 } 4069 } 4070 4071 /** 4072 * Constructor that is called when inflating a view from XML. This is called 4073 * when a view is being constructed from an XML file, supplying attributes 4074 * that were specified in the XML file. This version uses a default style of 4075 * 0, so the only attribute values applied are those in the Context's Theme 4076 * and the given AttributeSet. 4077 * 4078 * <p> 4079 * The method onFinishInflate() will be called after all children have been 4080 * added. 4081 * 4082 * @param context The Context the view is running in, through which it can 4083 * access the current theme, resources, etc. 4084 * @param attrs The attributes of the XML tag that is inflating the view. 4085 * @see #View(Context, AttributeSet, int) 4086 */ 4087 public View(Context context, @Nullable AttributeSet attrs) { 4088 this(context, attrs, 0); 4089 } 4090 4091 /** 4092 * Perform inflation from XML and apply a class-specific base style from a 4093 * theme attribute. This constructor of View allows subclasses to use their 4094 * own base style when they are inflating. For example, a Button class's 4095 * constructor would call this version of the super class constructor and 4096 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 4097 * allows the theme's button style to modify all of the base view attributes 4098 * (in particular its background) as well as the Button class's attributes. 4099 * 4100 * @param context The Context the view is running in, through which it can 4101 * access the current theme, resources, etc. 4102 * @param attrs The attributes of the XML tag that is inflating the view. 4103 * @param defStyleAttr An attribute in the current theme that contains a 4104 * reference to a style resource that supplies default values for 4105 * the view. Can be 0 to not look for defaults. 4106 * @see #View(Context, AttributeSet) 4107 */ 4108 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 4109 this(context, attrs, defStyleAttr, 0); 4110 } 4111 4112 /** 4113 * Perform inflation from XML and apply a class-specific base style from a 4114 * theme attribute or style resource. This constructor of View allows 4115 * subclasses to use their own base style when they are inflating. 4116 * <p> 4117 * When determining the final value of a particular attribute, there are 4118 * four inputs that come into play: 4119 * <ol> 4120 * <li>Any attribute values in the given AttributeSet. 4121 * <li>The style resource specified in the AttributeSet (named "style"). 4122 * <li>The default style specified by <var>defStyleAttr</var>. 4123 * <li>The default style specified by <var>defStyleRes</var>. 4124 * <li>The base values in this theme. 4125 * </ol> 4126 * <p> 4127 * Each of these inputs is considered in-order, with the first listed taking 4128 * precedence over the following ones. In other words, if in the 4129 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 4130 * , then the button's text will <em>always</em> be black, regardless of 4131 * what is specified in any of the styles. 4132 * 4133 * @param context The Context the view is running in, through which it can 4134 * access the current theme, resources, etc. 4135 * @param attrs The attributes of the XML tag that is inflating the view. 4136 * @param defStyleAttr An attribute in the current theme that contains a 4137 * reference to a style resource that supplies default values for 4138 * the view. Can be 0 to not look for defaults. 4139 * @param defStyleRes A resource identifier of a style resource that 4140 * supplies default values for the view, used only if 4141 * defStyleAttr is 0 or can not be found in the theme. Can be 0 4142 * to not look for defaults. 4143 * @see #View(Context, AttributeSet, int) 4144 */ 4145 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 4146 this(context); 4147 4148 final TypedArray a = context.obtainStyledAttributes( 4149 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 4150 4151 if (mDebugViewAttributes) { 4152 saveAttributeData(attrs, a); 4153 } 4154 4155 Drawable background = null; 4156 4157 int leftPadding = -1; 4158 int topPadding = -1; 4159 int rightPadding = -1; 4160 int bottomPadding = -1; 4161 int startPadding = UNDEFINED_PADDING; 4162 int endPadding = UNDEFINED_PADDING; 4163 4164 int padding = -1; 4165 4166 int viewFlagValues = 0; 4167 int viewFlagMasks = 0; 4168 4169 boolean setScrollContainer = false; 4170 4171 int x = 0; 4172 int y = 0; 4173 4174 float tx = 0; 4175 float ty = 0; 4176 float tz = 0; 4177 float elevation = 0; 4178 float rotation = 0; 4179 float rotationX = 0; 4180 float rotationY = 0; 4181 float sx = 1f; 4182 float sy = 1f; 4183 boolean transformSet = false; 4184 4185 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 4186 int overScrollMode = mOverScrollMode; 4187 boolean initializeScrollbars = false; 4188 boolean initializeScrollIndicators = false; 4189 4190 boolean startPaddingDefined = false; 4191 boolean endPaddingDefined = false; 4192 boolean leftPaddingDefined = false; 4193 boolean rightPaddingDefined = false; 4194 4195 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 4196 4197 final int N = a.getIndexCount(); 4198 for (int i = 0; i < N; i++) { 4199 int attr = a.getIndex(i); 4200 switch (attr) { 4201 case com.android.internal.R.styleable.View_background: 4202 background = a.getDrawable(attr); 4203 break; 4204 case com.android.internal.R.styleable.View_padding: 4205 padding = a.getDimensionPixelSize(attr, -1); 4206 mUserPaddingLeftInitial = padding; 4207 mUserPaddingRightInitial = padding; 4208 leftPaddingDefined = true; 4209 rightPaddingDefined = true; 4210 break; 4211 case com.android.internal.R.styleable.View_paddingLeft: 4212 leftPadding = a.getDimensionPixelSize(attr, -1); 4213 mUserPaddingLeftInitial = leftPadding; 4214 leftPaddingDefined = true; 4215 break; 4216 case com.android.internal.R.styleable.View_paddingTop: 4217 topPadding = a.getDimensionPixelSize(attr, -1); 4218 break; 4219 case com.android.internal.R.styleable.View_paddingRight: 4220 rightPadding = a.getDimensionPixelSize(attr, -1); 4221 mUserPaddingRightInitial = rightPadding; 4222 rightPaddingDefined = true; 4223 break; 4224 case com.android.internal.R.styleable.View_paddingBottom: 4225 bottomPadding = a.getDimensionPixelSize(attr, -1); 4226 break; 4227 case com.android.internal.R.styleable.View_paddingStart: 4228 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4229 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 4230 break; 4231 case com.android.internal.R.styleable.View_paddingEnd: 4232 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 4233 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 4234 break; 4235 case com.android.internal.R.styleable.View_scrollX: 4236 x = a.getDimensionPixelOffset(attr, 0); 4237 break; 4238 case com.android.internal.R.styleable.View_scrollY: 4239 y = a.getDimensionPixelOffset(attr, 0); 4240 break; 4241 case com.android.internal.R.styleable.View_alpha: 4242 setAlpha(a.getFloat(attr, 1f)); 4243 break; 4244 case com.android.internal.R.styleable.View_transformPivotX: 4245 setPivotX(a.getDimension(attr, 0)); 4246 break; 4247 case com.android.internal.R.styleable.View_transformPivotY: 4248 setPivotY(a.getDimension(attr, 0)); 4249 break; 4250 case com.android.internal.R.styleable.View_translationX: 4251 tx = a.getDimension(attr, 0); 4252 transformSet = true; 4253 break; 4254 case com.android.internal.R.styleable.View_translationY: 4255 ty = a.getDimension(attr, 0); 4256 transformSet = true; 4257 break; 4258 case com.android.internal.R.styleable.View_translationZ: 4259 tz = a.getDimension(attr, 0); 4260 transformSet = true; 4261 break; 4262 case com.android.internal.R.styleable.View_elevation: 4263 elevation = a.getDimension(attr, 0); 4264 transformSet = true; 4265 break; 4266 case com.android.internal.R.styleable.View_rotation: 4267 rotation = a.getFloat(attr, 0); 4268 transformSet = true; 4269 break; 4270 case com.android.internal.R.styleable.View_rotationX: 4271 rotationX = a.getFloat(attr, 0); 4272 transformSet = true; 4273 break; 4274 case com.android.internal.R.styleable.View_rotationY: 4275 rotationY = a.getFloat(attr, 0); 4276 transformSet = true; 4277 break; 4278 case com.android.internal.R.styleable.View_scaleX: 4279 sx = a.getFloat(attr, 1f); 4280 transformSet = true; 4281 break; 4282 case com.android.internal.R.styleable.View_scaleY: 4283 sy = a.getFloat(attr, 1f); 4284 transformSet = true; 4285 break; 4286 case com.android.internal.R.styleable.View_id: 4287 mID = a.getResourceId(attr, NO_ID); 4288 break; 4289 case com.android.internal.R.styleable.View_tag: 4290 mTag = a.getText(attr); 4291 break; 4292 case com.android.internal.R.styleable.View_fitsSystemWindows: 4293 if (a.getBoolean(attr, false)) { 4294 viewFlagValues |= FITS_SYSTEM_WINDOWS; 4295 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 4296 } 4297 break; 4298 case com.android.internal.R.styleable.View_focusable: 4299 if (a.getBoolean(attr, false)) { 4300 viewFlagValues |= FOCUSABLE; 4301 viewFlagMasks |= FOCUSABLE_MASK; 4302 } 4303 break; 4304 case com.android.internal.R.styleable.View_focusableInTouchMode: 4305 if (a.getBoolean(attr, false)) { 4306 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 4307 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 4308 } 4309 break; 4310 case com.android.internal.R.styleable.View_clickable: 4311 if (a.getBoolean(attr, false)) { 4312 viewFlagValues |= CLICKABLE; 4313 viewFlagMasks |= CLICKABLE; 4314 } 4315 break; 4316 case com.android.internal.R.styleable.View_longClickable: 4317 if (a.getBoolean(attr, false)) { 4318 viewFlagValues |= LONG_CLICKABLE; 4319 viewFlagMasks |= LONG_CLICKABLE; 4320 } 4321 break; 4322 case com.android.internal.R.styleable.View_contextClickable: 4323 if (a.getBoolean(attr, false)) { 4324 viewFlagValues |= CONTEXT_CLICKABLE; 4325 viewFlagMasks |= CONTEXT_CLICKABLE; 4326 } 4327 break; 4328 case com.android.internal.R.styleable.View_saveEnabled: 4329 if (!a.getBoolean(attr, true)) { 4330 viewFlagValues |= SAVE_DISABLED; 4331 viewFlagMasks |= SAVE_DISABLED_MASK; 4332 } 4333 break; 4334 case com.android.internal.R.styleable.View_duplicateParentState: 4335 if (a.getBoolean(attr, false)) { 4336 viewFlagValues |= DUPLICATE_PARENT_STATE; 4337 viewFlagMasks |= DUPLICATE_PARENT_STATE; 4338 } 4339 break; 4340 case com.android.internal.R.styleable.View_visibility: 4341 final int visibility = a.getInt(attr, 0); 4342 if (visibility != 0) { 4343 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 4344 viewFlagMasks |= VISIBILITY_MASK; 4345 } 4346 break; 4347 case com.android.internal.R.styleable.View_layoutDirection: 4348 // Clear any layout direction flags (included resolved bits) already set 4349 mPrivateFlags2 &= 4350 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 4351 // Set the layout direction flags depending on the value of the attribute 4352 final int layoutDirection = a.getInt(attr, -1); 4353 final int value = (layoutDirection != -1) ? 4354 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 4355 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 4356 break; 4357 case com.android.internal.R.styleable.View_drawingCacheQuality: 4358 final int cacheQuality = a.getInt(attr, 0); 4359 if (cacheQuality != 0) { 4360 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 4361 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 4362 } 4363 break; 4364 case com.android.internal.R.styleable.View_contentDescription: 4365 setContentDescription(a.getString(attr)); 4366 break; 4367 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 4368 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 4369 break; 4370 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 4371 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 4372 break; 4373 case com.android.internal.R.styleable.View_labelFor: 4374 setLabelFor(a.getResourceId(attr, NO_ID)); 4375 break; 4376 case com.android.internal.R.styleable.View_soundEffectsEnabled: 4377 if (!a.getBoolean(attr, true)) { 4378 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 4379 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 4380 } 4381 break; 4382 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 4383 if (!a.getBoolean(attr, true)) { 4384 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 4385 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 4386 } 4387 break; 4388 case R.styleable.View_scrollbars: 4389 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 4390 if (scrollbars != SCROLLBARS_NONE) { 4391 viewFlagValues |= scrollbars; 4392 viewFlagMasks |= SCROLLBARS_MASK; 4393 initializeScrollbars = true; 4394 } 4395 break; 4396 //noinspection deprecation 4397 case R.styleable.View_fadingEdge: 4398 if (targetSdkVersion >= ICE_CREAM_SANDWICH) { 4399 // Ignore the attribute starting with ICS 4400 break; 4401 } 4402 // With builds < ICS, fall through and apply fading edges 4403 case R.styleable.View_requiresFadingEdge: 4404 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 4405 if (fadingEdge != FADING_EDGE_NONE) { 4406 viewFlagValues |= fadingEdge; 4407 viewFlagMasks |= FADING_EDGE_MASK; 4408 initializeFadingEdgeInternal(a); 4409 } 4410 break; 4411 case R.styleable.View_scrollbarStyle: 4412 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 4413 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4414 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 4415 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 4416 } 4417 break; 4418 case R.styleable.View_isScrollContainer: 4419 setScrollContainer = true; 4420 if (a.getBoolean(attr, false)) { 4421 setScrollContainer(true); 4422 } 4423 break; 4424 case com.android.internal.R.styleable.View_keepScreenOn: 4425 if (a.getBoolean(attr, false)) { 4426 viewFlagValues |= KEEP_SCREEN_ON; 4427 viewFlagMasks |= KEEP_SCREEN_ON; 4428 } 4429 break; 4430 case R.styleable.View_filterTouchesWhenObscured: 4431 if (a.getBoolean(attr, false)) { 4432 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 4433 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 4434 } 4435 break; 4436 case R.styleable.View_nextFocusLeft: 4437 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 4438 break; 4439 case R.styleable.View_nextFocusRight: 4440 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 4441 break; 4442 case R.styleable.View_nextFocusUp: 4443 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 4444 break; 4445 case R.styleable.View_nextFocusDown: 4446 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 4447 break; 4448 case R.styleable.View_nextFocusForward: 4449 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 4450 break; 4451 case R.styleable.View_minWidth: 4452 mMinWidth = a.getDimensionPixelSize(attr, 0); 4453 break; 4454 case R.styleable.View_minHeight: 4455 mMinHeight = a.getDimensionPixelSize(attr, 0); 4456 break; 4457 case R.styleable.View_onClick: 4458 if (context.isRestricted()) { 4459 throw new IllegalStateException("The android:onClick attribute cannot " 4460 + "be used within a restricted context"); 4461 } 4462 4463 final String handlerName = a.getString(attr); 4464 if (handlerName != null) { 4465 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 4466 } 4467 break; 4468 case R.styleable.View_overScrollMode: 4469 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 4470 break; 4471 case R.styleable.View_verticalScrollbarPosition: 4472 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 4473 break; 4474 case R.styleable.View_layerType: 4475 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 4476 break; 4477 case R.styleable.View_textDirection: 4478 // Clear any text direction flag already set 4479 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 4480 // Set the text direction flags depending on the value of the attribute 4481 final int textDirection = a.getInt(attr, -1); 4482 if (textDirection != -1) { 4483 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 4484 } 4485 break; 4486 case R.styleable.View_textAlignment: 4487 // Clear any text alignment flag already set 4488 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 4489 // Set the text alignment flag depending on the value of the attribute 4490 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 4491 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 4492 break; 4493 case R.styleable.View_importantForAccessibility: 4494 setImportantForAccessibility(a.getInt(attr, 4495 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 4496 break; 4497 case R.styleable.View_accessibilityLiveRegion: 4498 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 4499 break; 4500 case R.styleable.View_transitionName: 4501 setTransitionName(a.getString(attr)); 4502 break; 4503 case R.styleable.View_nestedScrollingEnabled: 4504 setNestedScrollingEnabled(a.getBoolean(attr, false)); 4505 break; 4506 case R.styleable.View_stateListAnimator: 4507 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 4508 a.getResourceId(attr, 0))); 4509 break; 4510 case R.styleable.View_backgroundTint: 4511 // This will get applied later during setBackground(). 4512 if (mBackgroundTint == null) { 4513 mBackgroundTint = new TintInfo(); 4514 } 4515 mBackgroundTint.mTintList = a.getColorStateList( 4516 R.styleable.View_backgroundTint); 4517 mBackgroundTint.mHasTintList = true; 4518 break; 4519 case R.styleable.View_backgroundTintMode: 4520 // This will get applied later during setBackground(). 4521 if (mBackgroundTint == null) { 4522 mBackgroundTint = new TintInfo(); 4523 } 4524 mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt( 4525 R.styleable.View_backgroundTintMode, -1), null); 4526 mBackgroundTint.mHasTintMode = true; 4527 break; 4528 case R.styleable.View_outlineProvider: 4529 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 4530 PROVIDER_BACKGROUND)); 4531 break; 4532 case R.styleable.View_foreground: 4533 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4534 setForeground(a.getDrawable(attr)); 4535 } 4536 break; 4537 case R.styleable.View_foregroundGravity: 4538 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4539 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 4540 } 4541 break; 4542 case R.styleable.View_foregroundTintMode: 4543 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4544 setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); 4545 } 4546 break; 4547 case R.styleable.View_foregroundTint: 4548 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4549 setForegroundTintList(a.getColorStateList(attr)); 4550 } 4551 break; 4552 case R.styleable.View_foregroundInsidePadding: 4553 if (targetSdkVersion >= VERSION_CODES.M || this instanceof FrameLayout) { 4554 if (mForegroundInfo == null) { 4555 mForegroundInfo = new ForegroundInfo(); 4556 } 4557 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 4558 mForegroundInfo.mInsidePadding); 4559 } 4560 break; 4561 case R.styleable.View_scrollIndicators: 4562 final int scrollIndicators = 4563 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 4564 & SCROLL_INDICATORS_PFLAG3_MASK; 4565 if (scrollIndicators != 0) { 4566 mPrivateFlags3 |= scrollIndicators; 4567 initializeScrollIndicators = true; 4568 } 4569 break; 4570 case R.styleable.View_pointerIcon: 4571 final int resourceId = a.getResourceId(attr, 0); 4572 if (resourceId != 0) { 4573 setPointerIcon(PointerIcon.load( 4574 context.getResources(), resourceId)); 4575 } else { 4576 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 4577 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 4578 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 4579 } 4580 } 4581 break; 4582 case R.styleable.View_forceHasOverlappingRendering: 4583 if (a.peekValue(attr) != null) { 4584 forceHasOverlappingRendering(a.getBoolean(attr, true)); 4585 } 4586 break; 4587 4588 } 4589 } 4590 4591 setOverScrollMode(overScrollMode); 4592 4593 // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet 4594 // the resolved layout direction). Those cached values will be used later during padding 4595 // resolution. 4596 mUserPaddingStart = startPadding; 4597 mUserPaddingEnd = endPadding; 4598 4599 if (background != null) { 4600 setBackground(background); 4601 } 4602 4603 // setBackground above will record that padding is currently provided by the background. 4604 // If we have padding specified via xml, record that here instead and use it. 4605 mLeftPaddingDefined = leftPaddingDefined; 4606 mRightPaddingDefined = rightPaddingDefined; 4607 4608 if (padding >= 0) { 4609 leftPadding = padding; 4610 topPadding = padding; 4611 rightPadding = padding; 4612 bottomPadding = padding; 4613 mUserPaddingLeftInitial = padding; 4614 mUserPaddingRightInitial = padding; 4615 } 4616 4617 if (isRtlCompatibilityMode()) { 4618 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 4619 // left / right padding are used if defined (meaning here nothing to do). If they are not 4620 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 4621 // start / end and resolve them as left / right (layout direction is not taken into account). 4622 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4623 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4624 // defined. 4625 if (!mLeftPaddingDefined && startPaddingDefined) { 4626 leftPadding = startPadding; 4627 } 4628 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 4629 if (!mRightPaddingDefined && endPaddingDefined) { 4630 rightPadding = endPadding; 4631 } 4632 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 4633 } else { 4634 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 4635 // values defined. Otherwise, left /right values are used. 4636 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 4637 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 4638 // defined. 4639 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 4640 4641 if (mLeftPaddingDefined && !hasRelativePadding) { 4642 mUserPaddingLeftInitial = leftPadding; 4643 } 4644 if (mRightPaddingDefined && !hasRelativePadding) { 4645 mUserPaddingRightInitial = rightPadding; 4646 } 4647 } 4648 4649 internalSetPadding( 4650 mUserPaddingLeftInitial, 4651 topPadding >= 0 ? topPadding : mPaddingTop, 4652 mUserPaddingRightInitial, 4653 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 4654 4655 if (viewFlagMasks != 0) { 4656 setFlags(viewFlagValues, viewFlagMasks); 4657 } 4658 4659 if (initializeScrollbars) { 4660 initializeScrollbarsInternal(a); 4661 } 4662 4663 if (initializeScrollIndicators) { 4664 initializeScrollIndicatorsInternal(); 4665 } 4666 4667 a.recycle(); 4668 4669 // Needs to be called after mViewFlags is set 4670 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 4671 recomputePadding(); 4672 } 4673 4674 if (x != 0 || y != 0) { 4675 scrollTo(x, y); 4676 } 4677 4678 if (transformSet) { 4679 setTranslationX(tx); 4680 setTranslationY(ty); 4681 setTranslationZ(tz); 4682 setElevation(elevation); 4683 setRotation(rotation); 4684 setRotationX(rotationX); 4685 setRotationY(rotationY); 4686 setScaleX(sx); 4687 setScaleY(sy); 4688 } 4689 4690 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 4691 setScrollContainer(true); 4692 } 4693 4694 computeOpaqueFlags(); 4695 } 4696 4697 /** 4698 * An implementation of OnClickListener that attempts to lazily load a 4699 * named click handling method from a parent or ancestor context. 4700 */ 4701 private static class DeclaredOnClickListener implements OnClickListener { 4702 private final View mHostView; 4703 private final String mMethodName; 4704 4705 private Method mResolvedMethod; 4706 private Context mResolvedContext; 4707 DeclaredOnClickListener(@onNull View hostView, @NonNull String methodName)4708 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 4709 mHostView = hostView; 4710 mMethodName = methodName; 4711 } 4712 4713 @Override onClick(@onNull View v)4714 public void onClick(@NonNull View v) { 4715 if (mResolvedMethod == null) { 4716 resolveMethod(mHostView.getContext(), mMethodName); 4717 } 4718 4719 try { 4720 mResolvedMethod.invoke(mResolvedContext, v); 4721 } catch (IllegalAccessException e) { 4722 throw new IllegalStateException( 4723 "Could not execute non-public method for android:onClick", e); 4724 } catch (InvocationTargetException e) { 4725 throw new IllegalStateException( 4726 "Could not execute method for android:onClick", e); 4727 } 4728 } 4729 4730 @NonNull resolveMethod(@ullable Context context, @NonNull String name)4731 private void resolveMethod(@Nullable Context context, @NonNull String name) { 4732 while (context != null) { 4733 try { 4734 if (!context.isRestricted()) { 4735 final Method method = context.getClass().getMethod(mMethodName, View.class); 4736 if (method != null) { 4737 mResolvedMethod = method; 4738 mResolvedContext = context; 4739 return; 4740 } 4741 } 4742 } catch (NoSuchMethodException e) { 4743 // Failed to find method, keep searching up the hierarchy. 4744 } 4745 4746 if (context instanceof ContextWrapper) { 4747 context = ((ContextWrapper) context).getBaseContext(); 4748 } else { 4749 // Can't search up the hierarchy, null out and fail. 4750 context = null; 4751 } 4752 } 4753 4754 final int id = mHostView.getId(); 4755 final String idText = id == NO_ID ? "" : " with id '" 4756 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 4757 throw new IllegalStateException("Could not find method " + mMethodName 4758 + "(View) in a parent or ancestor Context for android:onClick " 4759 + "attribute defined on view " + mHostView.getClass() + idText); 4760 } 4761 } 4762 4763 /** 4764 * Non-public constructor for use in testing 4765 */ View()4766 View() { 4767 mResources = null; 4768 mRenderNode = RenderNode.create(getClass().getName(), this); 4769 } 4770 getAttributeMap()4771 private static SparseArray<String> getAttributeMap() { 4772 if (mAttributeMap == null) { 4773 mAttributeMap = new SparseArray<>(); 4774 } 4775 return mAttributeMap; 4776 } 4777 saveAttributeData(@ullable AttributeSet attrs, @NonNull TypedArray t)4778 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 4779 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 4780 final int indexCount = t.getIndexCount(); 4781 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 4782 4783 int i = 0; 4784 4785 // Store raw XML attributes. 4786 for (int j = 0; j < attrsCount; ++j) { 4787 attributes[i] = attrs.getAttributeName(j); 4788 attributes[i + 1] = attrs.getAttributeValue(j); 4789 i += 2; 4790 } 4791 4792 // Store resolved styleable attributes. 4793 final Resources res = t.getResources(); 4794 final SparseArray<String> attributeMap = getAttributeMap(); 4795 for (int j = 0; j < indexCount; ++j) { 4796 final int index = t.getIndex(j); 4797 if (!t.hasValueOrEmpty(index)) { 4798 // Value is undefined. Skip it. 4799 continue; 4800 } 4801 4802 final int resourceId = t.getResourceId(index, 0); 4803 if (resourceId == 0) { 4804 // Value is not a reference. Skip it. 4805 continue; 4806 } 4807 4808 String resourceName = attributeMap.get(resourceId); 4809 if (resourceName == null) { 4810 try { 4811 resourceName = res.getResourceName(resourceId); 4812 } catch (Resources.NotFoundException e) { 4813 resourceName = "0x" + Integer.toHexString(resourceId); 4814 } 4815 attributeMap.put(resourceId, resourceName); 4816 } 4817 4818 attributes[i] = resourceName; 4819 attributes[i + 1] = t.getString(index); 4820 i += 2; 4821 } 4822 4823 // Trim to fit contents. 4824 final String[] trimmed = new String[i]; 4825 System.arraycopy(attributes, 0, trimmed, 0, i); 4826 mAttributes = trimmed; 4827 } 4828 toString()4829 public String toString() { 4830 StringBuilder out = new StringBuilder(128); 4831 out.append(getClass().getName()); 4832 out.append('{'); 4833 out.append(Integer.toHexString(System.identityHashCode(this))); 4834 out.append(' '); 4835 switch (mViewFlags&VISIBILITY_MASK) { 4836 case VISIBLE: out.append('V'); break; 4837 case INVISIBLE: out.append('I'); break; 4838 case GONE: out.append('G'); break; 4839 default: out.append('.'); break; 4840 } 4841 out.append((mViewFlags&FOCUSABLE_MASK) == FOCUSABLE ? 'F' : '.'); 4842 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 4843 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 4844 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 4845 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 4846 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 4847 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 4848 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 4849 out.append(' '); 4850 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 4851 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 4852 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 4853 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 4854 out.append('p'); 4855 } else { 4856 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 4857 } 4858 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 4859 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 4860 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 4861 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 4862 out.append(' '); 4863 out.append(mLeft); 4864 out.append(','); 4865 out.append(mTop); 4866 out.append('-'); 4867 out.append(mRight); 4868 out.append(','); 4869 out.append(mBottom); 4870 final int id = getId(); 4871 if (id != NO_ID) { 4872 out.append(" #"); 4873 out.append(Integer.toHexString(id)); 4874 final Resources r = mResources; 4875 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 4876 try { 4877 String pkgname; 4878 switch (id&0xff000000) { 4879 case 0x7f000000: 4880 pkgname="app"; 4881 break; 4882 case 0x01000000: 4883 pkgname="android"; 4884 break; 4885 default: 4886 pkgname = r.getResourcePackageName(id); 4887 break; 4888 } 4889 String typename = r.getResourceTypeName(id); 4890 String entryname = r.getResourceEntryName(id); 4891 out.append(" "); 4892 out.append(pkgname); 4893 out.append(":"); 4894 out.append(typename); 4895 out.append("/"); 4896 out.append(entryname); 4897 } catch (Resources.NotFoundException e) { 4898 } 4899 } 4900 } 4901 out.append("}"); 4902 return out.toString(); 4903 } 4904 4905 /** 4906 * <p> 4907 * Initializes the fading edges from a given set of styled attributes. This 4908 * method should be called by subclasses that need fading edges and when an 4909 * instance of these subclasses is created programmatically rather than 4910 * being inflated from XML. This method is automatically called when the XML 4911 * is inflated. 4912 * </p> 4913 * 4914 * @param a the styled attributes set to initialize the fading edges from 4915 * 4916 * @removed 4917 */ initializeFadingEdge(TypedArray a)4918 protected void initializeFadingEdge(TypedArray a) { 4919 // This method probably shouldn't have been included in the SDK to begin with. 4920 // It relies on 'a' having been initialized using an attribute filter array that is 4921 // not publicly available to the SDK. The old method has been renamed 4922 // to initializeFadingEdgeInternal and hidden for framework use only; 4923 // this one initializes using defaults to make it safe to call for apps. 4924 4925 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 4926 4927 initializeFadingEdgeInternal(arr); 4928 4929 arr.recycle(); 4930 } 4931 4932 /** 4933 * <p> 4934 * Initializes the fading edges from a given set of styled attributes. This 4935 * method should be called by subclasses that need fading edges and when an 4936 * instance of these subclasses is created programmatically rather than 4937 * being inflated from XML. This method is automatically called when the XML 4938 * is inflated. 4939 * </p> 4940 * 4941 * @param a the styled attributes set to initialize the fading edges from 4942 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 4943 */ initializeFadingEdgeInternal(TypedArray a)4944 protected void initializeFadingEdgeInternal(TypedArray a) { 4945 initScrollCache(); 4946 4947 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 4948 R.styleable.View_fadingEdgeLength, 4949 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 4950 } 4951 4952 /** 4953 * Returns the size of the vertical faded edges used to indicate that more 4954 * content in this view is visible. 4955 * 4956 * @return The size in pixels of the vertical faded edge or 0 if vertical 4957 * faded edges are not enabled for this view. 4958 * @attr ref android.R.styleable#View_fadingEdgeLength 4959 */ getVerticalFadingEdgeLength()4960 public int getVerticalFadingEdgeLength() { 4961 if (isVerticalFadingEdgeEnabled()) { 4962 ScrollabilityCache cache = mScrollCache; 4963 if (cache != null) { 4964 return cache.fadingEdgeLength; 4965 } 4966 } 4967 return 0; 4968 } 4969 4970 /** 4971 * Set the size of the faded edge used to indicate that more content in this 4972 * view is available. Will not change whether the fading edge is enabled; use 4973 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 4974 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 4975 * for the vertical or horizontal fading edges. 4976 * 4977 * @param length The size in pixels of the faded edge used to indicate that more 4978 * content in this view is visible. 4979 */ setFadingEdgeLength(int length)4980 public void setFadingEdgeLength(int length) { 4981 initScrollCache(); 4982 mScrollCache.fadingEdgeLength = length; 4983 } 4984 4985 /** 4986 * Returns the size of the horizontal faded edges used to indicate that more 4987 * content in this view is visible. 4988 * 4989 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 4990 * faded edges are not enabled for this view. 4991 * @attr ref android.R.styleable#View_fadingEdgeLength 4992 */ getHorizontalFadingEdgeLength()4993 public int getHorizontalFadingEdgeLength() { 4994 if (isHorizontalFadingEdgeEnabled()) { 4995 ScrollabilityCache cache = mScrollCache; 4996 if (cache != null) { 4997 return cache.fadingEdgeLength; 4998 } 4999 } 5000 return 0; 5001 } 5002 5003 /** 5004 * Returns the width of the vertical scrollbar. 5005 * 5006 * @return The width in pixels of the vertical scrollbar or 0 if there 5007 * is no vertical scrollbar. 5008 */ getVerticalScrollbarWidth()5009 public int getVerticalScrollbarWidth() { 5010 ScrollabilityCache cache = mScrollCache; 5011 if (cache != null) { 5012 ScrollBarDrawable scrollBar = cache.scrollBar; 5013 if (scrollBar != null) { 5014 int size = scrollBar.getSize(true); 5015 if (size <= 0) { 5016 size = cache.scrollBarSize; 5017 } 5018 return size; 5019 } 5020 return 0; 5021 } 5022 return 0; 5023 } 5024 5025 /** 5026 * Returns the height of the horizontal scrollbar. 5027 * 5028 * @return The height in pixels of the horizontal scrollbar or 0 if 5029 * there is no horizontal scrollbar. 5030 */ getHorizontalScrollbarHeight()5031 protected int getHorizontalScrollbarHeight() { 5032 ScrollabilityCache cache = mScrollCache; 5033 if (cache != null) { 5034 ScrollBarDrawable scrollBar = cache.scrollBar; 5035 if (scrollBar != null) { 5036 int size = scrollBar.getSize(false); 5037 if (size <= 0) { 5038 size = cache.scrollBarSize; 5039 } 5040 return size; 5041 } 5042 return 0; 5043 } 5044 return 0; 5045 } 5046 5047 /** 5048 * <p> 5049 * Initializes the scrollbars from a given set of styled attributes. This 5050 * method should be called by subclasses that need scrollbars and when an 5051 * instance of these subclasses is created programmatically rather than 5052 * being inflated from XML. This method is automatically called when the XML 5053 * is inflated. 5054 * </p> 5055 * 5056 * @param a the styled attributes set to initialize the scrollbars from 5057 * 5058 * @removed 5059 */ initializeScrollbars(TypedArray a)5060 protected void initializeScrollbars(TypedArray a) { 5061 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 5062 // using the View filter array which is not available to the SDK. As such, internal 5063 // framework usage now uses initializeScrollbarsInternal and we grab a default 5064 // TypedArray with the right filter instead here. 5065 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 5066 5067 initializeScrollbarsInternal(arr); 5068 5069 // We ignored the method parameter. Recycle the one we actually did use. 5070 arr.recycle(); 5071 } 5072 5073 /** 5074 * <p> 5075 * Initializes the scrollbars from a given set of styled attributes. This 5076 * method should be called by subclasses that need scrollbars and when an 5077 * instance of these subclasses is created programmatically rather than 5078 * being inflated from XML. This method is automatically called when the XML 5079 * is inflated. 5080 * </p> 5081 * 5082 * @param a the styled attributes set to initialize the scrollbars from 5083 * @hide 5084 */ initializeScrollbarsInternal(TypedArray a)5085 protected void initializeScrollbarsInternal(TypedArray a) { 5086 initScrollCache(); 5087 5088 final ScrollabilityCache scrollabilityCache = mScrollCache; 5089 5090 if (scrollabilityCache.scrollBar == null) { 5091 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 5092 scrollabilityCache.scrollBar.setState(getDrawableState()); 5093 scrollabilityCache.scrollBar.setCallback(this); 5094 } 5095 5096 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 5097 5098 if (!fadeScrollbars) { 5099 scrollabilityCache.state = ScrollabilityCache.ON; 5100 } 5101 scrollabilityCache.fadeScrollBars = fadeScrollbars; 5102 5103 5104 scrollabilityCache.scrollBarFadeDuration = a.getInt( 5105 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 5106 .getScrollBarFadeDuration()); 5107 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 5108 R.styleable.View_scrollbarDefaultDelayBeforeFade, 5109 ViewConfiguration.getScrollDefaultDelay()); 5110 5111 5112 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 5113 com.android.internal.R.styleable.View_scrollbarSize, 5114 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 5115 5116 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 5117 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 5118 5119 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 5120 if (thumb != null) { 5121 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 5122 } 5123 5124 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 5125 false); 5126 if (alwaysDraw) { 5127 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 5128 } 5129 5130 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 5131 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 5132 5133 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 5134 if (thumb != null) { 5135 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 5136 } 5137 5138 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 5139 false); 5140 if (alwaysDraw) { 5141 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 5142 } 5143 5144 // Apply layout direction to the new Drawables if needed 5145 final int layoutDirection = getLayoutDirection(); 5146 if (track != null) { 5147 track.setLayoutDirection(layoutDirection); 5148 } 5149 if (thumb != null) { 5150 thumb.setLayoutDirection(layoutDirection); 5151 } 5152 5153 // Re-apply user/background padding so that scrollbar(s) get added 5154 resolvePadding(); 5155 } 5156 initializeScrollIndicatorsInternal()5157 private void initializeScrollIndicatorsInternal() { 5158 // Some day maybe we'll break this into top/left/start/etc. and let the 5159 // client control it. Until then, you can have any scroll indicator you 5160 // want as long as it's a 1dp foreground-colored rectangle. 5161 if (mScrollIndicatorDrawable == null) { 5162 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 5163 } 5164 } 5165 5166 /** 5167 * <p> 5168 * Initalizes the scrollability cache if necessary. 5169 * </p> 5170 */ initScrollCache()5171 private void initScrollCache() { 5172 if (mScrollCache == null) { 5173 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 5174 } 5175 } 5176 getScrollCache()5177 private ScrollabilityCache getScrollCache() { 5178 initScrollCache(); 5179 return mScrollCache; 5180 } 5181 5182 /** 5183 * Set the position of the vertical scroll bar. Should be one of 5184 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 5185 * {@link #SCROLLBAR_POSITION_RIGHT}. 5186 * 5187 * @param position Where the vertical scroll bar should be positioned. 5188 */ setVerticalScrollbarPosition(int position)5189 public void setVerticalScrollbarPosition(int position) { 5190 if (mVerticalScrollbarPosition != position) { 5191 mVerticalScrollbarPosition = position; 5192 computeOpaqueFlags(); 5193 resolvePadding(); 5194 } 5195 } 5196 5197 /** 5198 * @return The position where the vertical scroll bar will show, if applicable. 5199 * @see #setVerticalScrollbarPosition(int) 5200 */ getVerticalScrollbarPosition()5201 public int getVerticalScrollbarPosition() { 5202 return mVerticalScrollbarPosition; 5203 } 5204 isOnScrollbar(float x, float y)5205 boolean isOnScrollbar(float x, float y) { 5206 if (mScrollCache == null) { 5207 return false; 5208 } 5209 x += getScrollX(); 5210 y += getScrollY(); 5211 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5212 final Rect bounds = mScrollCache.mScrollBarBounds; 5213 getVerticalScrollBarBounds(bounds); 5214 if (bounds.contains((int)x, (int)y)) { 5215 return true; 5216 } 5217 } 5218 if (isHorizontalScrollBarEnabled()) { 5219 final Rect bounds = mScrollCache.mScrollBarBounds; 5220 getHorizontalScrollBarBounds(bounds); 5221 if (bounds.contains((int)x, (int)y)) { 5222 return true; 5223 } 5224 } 5225 return false; 5226 } 5227 isOnScrollbarThumb(float x, float y)5228 boolean isOnScrollbarThumb(float x, float y) { 5229 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 5230 } 5231 isOnVerticalScrollbarThumb(float x, float y)5232 private boolean isOnVerticalScrollbarThumb(float x, float y) { 5233 if (mScrollCache == null) { 5234 return false; 5235 } 5236 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden()) { 5237 x += getScrollX(); 5238 y += getScrollY(); 5239 final Rect bounds = mScrollCache.mScrollBarBounds; 5240 getVerticalScrollBarBounds(bounds); 5241 final int range = computeVerticalScrollRange(); 5242 final int offset = computeVerticalScrollOffset(); 5243 final int extent = computeVerticalScrollExtent(); 5244 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 5245 extent, range); 5246 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 5247 extent, range, offset); 5248 final int thumbTop = bounds.top + thumbOffset; 5249 if (x >= bounds.left && x <= bounds.right && y >= thumbTop 5250 && y <= thumbTop + thumbLength) { 5251 return true; 5252 } 5253 } 5254 return false; 5255 } 5256 isOnHorizontalScrollbarThumb(float x, float y)5257 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 5258 if (mScrollCache == null) { 5259 return false; 5260 } 5261 if (isHorizontalScrollBarEnabled()) { 5262 x += getScrollX(); 5263 y += getScrollY(); 5264 final Rect bounds = mScrollCache.mScrollBarBounds; 5265 getHorizontalScrollBarBounds(bounds); 5266 final int range = computeHorizontalScrollRange(); 5267 final int offset = computeHorizontalScrollOffset(); 5268 final int extent = computeHorizontalScrollExtent(); 5269 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 5270 extent, range); 5271 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 5272 extent, range, offset); 5273 final int thumbLeft = bounds.left + thumbOffset; 5274 if (x >= thumbLeft && x <= thumbLeft + thumbLength && y >= bounds.top 5275 && y <= bounds.bottom) { 5276 return true; 5277 } 5278 } 5279 return false; 5280 } 5281 isDraggingScrollBar()5282 boolean isDraggingScrollBar() { 5283 return mScrollCache != null 5284 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 5285 } 5286 5287 /** 5288 * Sets the state of all scroll indicators. 5289 * <p> 5290 * See {@link #setScrollIndicators(int, int)} for usage information. 5291 * 5292 * @param indicators a bitmask of indicators that should be enabled, or 5293 * {@code 0} to disable all indicators 5294 * @see #setScrollIndicators(int, int) 5295 * @see #getScrollIndicators() 5296 * @attr ref android.R.styleable#View_scrollIndicators 5297 */ setScrollIndicators(@crollIndicators int indicators)5298 public void setScrollIndicators(@ScrollIndicators int indicators) { 5299 setScrollIndicators(indicators, 5300 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 5301 } 5302 5303 /** 5304 * Sets the state of the scroll indicators specified by the mask. To change 5305 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 5306 * <p> 5307 * When a scroll indicator is enabled, it will be displayed if the view 5308 * can scroll in the direction of the indicator. 5309 * <p> 5310 * Multiple indicator types may be enabled or disabled by passing the 5311 * logical OR of the desired types. If multiple types are specified, they 5312 * will all be set to the same enabled state. 5313 * <p> 5314 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 5315 * 5316 * @param indicators the indicator direction, or the logical OR of multiple 5317 * indicator directions. One or more of: 5318 * <ul> 5319 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 5320 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 5321 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 5322 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 5323 * <li>{@link #SCROLL_INDICATOR_START}</li> 5324 * <li>{@link #SCROLL_INDICATOR_END}</li> 5325 * </ul> 5326 * @see #setScrollIndicators(int) 5327 * @see #getScrollIndicators() 5328 * @attr ref android.R.styleable#View_scrollIndicators 5329 */ setScrollIndicators(@crollIndicators int indicators, @ScrollIndicators int mask)5330 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 5331 // Shift and sanitize mask. 5332 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5333 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 5334 5335 // Shift and mask indicators. 5336 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5337 indicators &= mask; 5338 5339 // Merge with non-masked flags. 5340 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 5341 5342 if (mPrivateFlags3 != updatedFlags) { 5343 mPrivateFlags3 = updatedFlags; 5344 5345 if (indicators != 0) { 5346 initializeScrollIndicatorsInternal(); 5347 } 5348 invalidate(); 5349 } 5350 } 5351 5352 /** 5353 * Returns a bitmask representing the enabled scroll indicators. 5354 * <p> 5355 * For example, if the top and left scroll indicators are enabled and all 5356 * other indicators are disabled, the return value will be 5357 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 5358 * <p> 5359 * To check whether the bottom scroll indicator is enabled, use the value 5360 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 5361 * 5362 * @return a bitmask representing the enabled scroll indicators 5363 */ 5364 @ScrollIndicators getScrollIndicators()5365 public int getScrollIndicators() { 5366 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 5367 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 5368 } 5369 getListenerInfo()5370 ListenerInfo getListenerInfo() { 5371 if (mListenerInfo != null) { 5372 return mListenerInfo; 5373 } 5374 mListenerInfo = new ListenerInfo(); 5375 return mListenerInfo; 5376 } 5377 5378 /** 5379 * Register a callback to be invoked when the scroll X or Y positions of 5380 * this view change. 5381 * <p> 5382 * <b>Note:</b> Some views handle scrolling independently from View and may 5383 * have their own separate listeners for scroll-type events. For example, 5384 * {@link android.widget.ListView ListView} allows clients to register an 5385 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 5386 * to listen for changes in list scroll position. 5387 * 5388 * @param l The listener to notify when the scroll X or Y position changes. 5389 * @see android.view.View#getScrollX() 5390 * @see android.view.View#getScrollY() 5391 */ setOnScrollChangeListener(OnScrollChangeListener l)5392 public void setOnScrollChangeListener(OnScrollChangeListener l) { 5393 getListenerInfo().mOnScrollChangeListener = l; 5394 } 5395 5396 /** 5397 * Register a callback to be invoked when focus of this view changed. 5398 * 5399 * @param l The callback that will run. 5400 */ setOnFocusChangeListener(OnFocusChangeListener l)5401 public void setOnFocusChangeListener(OnFocusChangeListener l) { 5402 getListenerInfo().mOnFocusChangeListener = l; 5403 } 5404 5405 /** 5406 * Add a listener that will be called when the bounds of the view change due to 5407 * layout processing. 5408 * 5409 * @param listener The listener that will be called when layout bounds change. 5410 */ addOnLayoutChangeListener(OnLayoutChangeListener listener)5411 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 5412 ListenerInfo li = getListenerInfo(); 5413 if (li.mOnLayoutChangeListeners == null) { 5414 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 5415 } 5416 if (!li.mOnLayoutChangeListeners.contains(listener)) { 5417 li.mOnLayoutChangeListeners.add(listener); 5418 } 5419 } 5420 5421 /** 5422 * Remove a listener for layout changes. 5423 * 5424 * @param listener The listener for layout bounds change. 5425 */ removeOnLayoutChangeListener(OnLayoutChangeListener listener)5426 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 5427 ListenerInfo li = mListenerInfo; 5428 if (li == null || li.mOnLayoutChangeListeners == null) { 5429 return; 5430 } 5431 li.mOnLayoutChangeListeners.remove(listener); 5432 } 5433 5434 /** 5435 * Add a listener for attach state changes. 5436 * 5437 * This listener will be called whenever this view is attached or detached 5438 * from a window. Remove the listener using 5439 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 5440 * 5441 * @param listener Listener to attach 5442 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 5443 */ addOnAttachStateChangeListener(OnAttachStateChangeListener listener)5444 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5445 ListenerInfo li = getListenerInfo(); 5446 if (li.mOnAttachStateChangeListeners == null) { 5447 li.mOnAttachStateChangeListeners 5448 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 5449 } 5450 li.mOnAttachStateChangeListeners.add(listener); 5451 } 5452 5453 /** 5454 * Remove a listener for attach state changes. The listener will receive no further 5455 * notification of window attach/detach events. 5456 * 5457 * @param listener Listener to remove 5458 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 5459 */ removeOnAttachStateChangeListener(OnAttachStateChangeListener listener)5460 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 5461 ListenerInfo li = mListenerInfo; 5462 if (li == null || li.mOnAttachStateChangeListeners == null) { 5463 return; 5464 } 5465 li.mOnAttachStateChangeListeners.remove(listener); 5466 } 5467 5468 /** 5469 * Returns the focus-change callback registered for this view. 5470 * 5471 * @return The callback, or null if one is not registered. 5472 */ getOnFocusChangeListener()5473 public OnFocusChangeListener getOnFocusChangeListener() { 5474 ListenerInfo li = mListenerInfo; 5475 return li != null ? li.mOnFocusChangeListener : null; 5476 } 5477 5478 /** 5479 * Register a callback to be invoked when this view is clicked. If this view is not 5480 * clickable, it becomes clickable. 5481 * 5482 * @param l The callback that will run 5483 * 5484 * @see #setClickable(boolean) 5485 */ setOnClickListener(@ullable OnClickListener l)5486 public void setOnClickListener(@Nullable OnClickListener l) { 5487 if (!isClickable()) { 5488 setClickable(true); 5489 } 5490 getListenerInfo().mOnClickListener = l; 5491 } 5492 5493 /** 5494 * Return whether this view has an attached OnClickListener. Returns 5495 * true if there is a listener, false if there is none. 5496 */ hasOnClickListeners()5497 public boolean hasOnClickListeners() { 5498 ListenerInfo li = mListenerInfo; 5499 return (li != null && li.mOnClickListener != null); 5500 } 5501 5502 /** 5503 * Register a callback to be invoked when this view is clicked and held. If this view is not 5504 * long clickable, it becomes long clickable. 5505 * 5506 * @param l The callback that will run 5507 * 5508 * @see #setLongClickable(boolean) 5509 */ setOnLongClickListener(@ullable OnLongClickListener l)5510 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 5511 if (!isLongClickable()) { 5512 setLongClickable(true); 5513 } 5514 getListenerInfo().mOnLongClickListener = l; 5515 } 5516 5517 /** 5518 * Register a callback to be invoked when this view is context clicked. If the view is not 5519 * context clickable, it becomes context clickable. 5520 * 5521 * @param l The callback that will run 5522 * @see #setContextClickable(boolean) 5523 */ setOnContextClickListener(@ullable OnContextClickListener l)5524 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 5525 if (!isContextClickable()) { 5526 setContextClickable(true); 5527 } 5528 getListenerInfo().mOnContextClickListener = l; 5529 } 5530 5531 /** 5532 * Register a callback to be invoked when the context menu for this view is 5533 * being built. If this view is not long clickable, it becomes long clickable. 5534 * 5535 * @param l The callback that will run 5536 * 5537 */ setOnCreateContextMenuListener(OnCreateContextMenuListener l)5538 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 5539 if (!isLongClickable()) { 5540 setLongClickable(true); 5541 } 5542 getListenerInfo().mOnCreateContextMenuListener = l; 5543 } 5544 5545 /** 5546 * Set an observer to collect stats for each frame rendered for this view. 5547 * 5548 * @hide 5549 */ addFrameMetricsListener(Window window, Window.OnFrameMetricsAvailableListener listener, Handler handler)5550 public void addFrameMetricsListener(Window window, 5551 Window.OnFrameMetricsAvailableListener listener, 5552 Handler handler) { 5553 if (mAttachInfo != null) { 5554 if (mAttachInfo.mHardwareRenderer != null) { 5555 if (mFrameMetricsObservers == null) { 5556 mFrameMetricsObservers = new ArrayList<>(); 5557 } 5558 5559 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5560 handler.getLooper(), listener); 5561 mFrameMetricsObservers.add(fmo); 5562 mAttachInfo.mHardwareRenderer.addFrameMetricsObserver(fmo); 5563 } else { 5564 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5565 } 5566 } else { 5567 if (mFrameMetricsObservers == null) { 5568 mFrameMetricsObservers = new ArrayList<>(); 5569 } 5570 5571 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 5572 handler.getLooper(), listener); 5573 mFrameMetricsObservers.add(fmo); 5574 } 5575 } 5576 5577 /** 5578 * Remove observer configured to collect frame stats for this view. 5579 * 5580 * @hide 5581 */ removeFrameMetricsListener( Window.OnFrameMetricsAvailableListener listener)5582 public void removeFrameMetricsListener( 5583 Window.OnFrameMetricsAvailableListener listener) { 5584 ThreadedRenderer renderer = getHardwareRenderer(); 5585 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 5586 if (fmo == null) { 5587 throw new IllegalArgumentException( 5588 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 5589 } 5590 5591 if (mFrameMetricsObservers != null) { 5592 mFrameMetricsObservers.remove(fmo); 5593 if (renderer != null) { 5594 renderer.removeFrameMetricsObserver(fmo); 5595 } 5596 } 5597 } 5598 registerPendingFrameMetricsObservers()5599 private void registerPendingFrameMetricsObservers() { 5600 if (mFrameMetricsObservers != null) { 5601 ThreadedRenderer renderer = getHardwareRenderer(); 5602 if (renderer != null) { 5603 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 5604 renderer.addFrameMetricsObserver(fmo); 5605 } 5606 } else { 5607 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 5608 } 5609 } 5610 } 5611 findFrameMetricsObserver( Window.OnFrameMetricsAvailableListener listener)5612 private FrameMetricsObserver findFrameMetricsObserver( 5613 Window.OnFrameMetricsAvailableListener listener) { 5614 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 5615 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 5616 if (observer.mListener == listener) { 5617 return observer; 5618 } 5619 } 5620 5621 return null; 5622 } 5623 5624 /** 5625 * Call this view's OnClickListener, if it is defined. Performs all normal 5626 * actions associated with clicking: reporting accessibility event, playing 5627 * a sound, etc. 5628 * 5629 * @return True there was an assigned OnClickListener that was called, false 5630 * otherwise is returned. 5631 */ performClick()5632 public boolean performClick() { 5633 final boolean result; 5634 final ListenerInfo li = mListenerInfo; 5635 if (li != null && li.mOnClickListener != null) { 5636 playSoundEffect(SoundEffectConstants.CLICK); 5637 li.mOnClickListener.onClick(this); 5638 result = true; 5639 } else { 5640 result = false; 5641 } 5642 5643 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 5644 return result; 5645 } 5646 5647 /** 5648 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 5649 * this only calls the listener, and does not do any associated clicking 5650 * actions like reporting an accessibility event. 5651 * 5652 * @return True there was an assigned OnClickListener that was called, false 5653 * otherwise is returned. 5654 */ callOnClick()5655 public boolean callOnClick() { 5656 ListenerInfo li = mListenerInfo; 5657 if (li != null && li.mOnClickListener != null) { 5658 li.mOnClickListener.onClick(this); 5659 return true; 5660 } 5661 return false; 5662 } 5663 5664 /** 5665 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5666 * context menu if the OnLongClickListener did not consume the event. 5667 * 5668 * @return {@code true} if one of the above receivers consumed the event, 5669 * {@code false} otherwise 5670 */ performLongClick()5671 public boolean performLongClick() { 5672 return performLongClickInternal(mLongClickX, mLongClickY); 5673 } 5674 5675 /** 5676 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5677 * context menu if the OnLongClickListener did not consume the event, 5678 * anchoring it to an (x,y) coordinate. 5679 * 5680 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5681 * to disable anchoring 5682 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5683 * to disable anchoring 5684 * @return {@code true} if one of the above receivers consumed the event, 5685 * {@code false} otherwise 5686 */ performLongClick(float x, float y)5687 public boolean performLongClick(float x, float y) { 5688 mLongClickX = x; 5689 mLongClickY = y; 5690 final boolean handled = performLongClick(); 5691 mLongClickX = Float.NaN; 5692 mLongClickY = Float.NaN; 5693 return handled; 5694 } 5695 5696 /** 5697 * Calls this view's OnLongClickListener, if it is defined. Invokes the 5698 * context menu if the OnLongClickListener did not consume the event, 5699 * optionally anchoring it to an (x,y) coordinate. 5700 * 5701 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 5702 * to disable anchoring 5703 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 5704 * to disable anchoring 5705 * @return {@code true} if one of the above receivers consumed the event, 5706 * {@code false} otherwise 5707 */ performLongClickInternal(float x, float y)5708 private boolean performLongClickInternal(float x, float y) { 5709 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 5710 5711 boolean handled = false; 5712 final ListenerInfo li = mListenerInfo; 5713 if (li != null && li.mOnLongClickListener != null) { 5714 handled = li.mOnLongClickListener.onLongClick(View.this); 5715 } 5716 if (!handled) { 5717 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 5718 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 5719 } 5720 if (handled) { 5721 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 5722 } 5723 return handled; 5724 } 5725 5726 /** 5727 * Call this view's OnContextClickListener, if it is defined. 5728 * 5729 * @param x the x coordinate of the context click 5730 * @param y the y coordinate of the context click 5731 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5732 * otherwise. 5733 */ performContextClick(float x, float y)5734 public boolean performContextClick(float x, float y) { 5735 return performContextClick(); 5736 } 5737 5738 /** 5739 * Call this view's OnContextClickListener, if it is defined. 5740 * 5741 * @return True if there was an assigned OnContextClickListener that consumed the event, false 5742 * otherwise. 5743 */ performContextClick()5744 public boolean performContextClick() { 5745 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 5746 5747 boolean handled = false; 5748 ListenerInfo li = mListenerInfo; 5749 if (li != null && li.mOnContextClickListener != null) { 5750 handled = li.mOnContextClickListener.onContextClick(View.this); 5751 } 5752 if (handled) { 5753 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 5754 } 5755 return handled; 5756 } 5757 5758 /** 5759 * Performs button-related actions during a touch down event. 5760 * 5761 * @param event The event. 5762 * @return True if the down was consumed. 5763 * 5764 * @hide 5765 */ performButtonActionOnTouchDown(MotionEvent event)5766 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 5767 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 5768 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 5769 showContextMenu(event.getX(), event.getY()); 5770 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 5771 return true; 5772 } 5773 return false; 5774 } 5775 5776 /** 5777 * Shows the context menu for this view. 5778 * 5779 * @return {@code true} if the context menu was shown, {@code false} 5780 * otherwise 5781 * @see #showContextMenu(float, float) 5782 */ showContextMenu()5783 public boolean showContextMenu() { 5784 return getParent().showContextMenuForChild(this); 5785 } 5786 5787 /** 5788 * Shows the context menu for this view anchored to the specified 5789 * view-relative coordinate. 5790 * 5791 * @param x the X coordinate in pixels relative to the view to which the 5792 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5793 * @param y the Y coordinate in pixels relative to the view to which the 5794 * menu should be anchored, or {@link Float#NaN} to disable anchoring 5795 * @return {@code true} if the context menu was shown, {@code false} 5796 * otherwise 5797 */ showContextMenu(float x, float y)5798 public boolean showContextMenu(float x, float y) { 5799 return getParent().showContextMenuForChild(this, x, y); 5800 } 5801 5802 /** 5803 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 5804 * 5805 * @param callback Callback that will control the lifecycle of the action mode 5806 * @return The new action mode if it is started, null otherwise 5807 * 5808 * @see ActionMode 5809 * @see #startActionMode(android.view.ActionMode.Callback, int) 5810 */ startActionMode(ActionMode.Callback callback)5811 public ActionMode startActionMode(ActionMode.Callback callback) { 5812 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 5813 } 5814 5815 /** 5816 * Start an action mode with the given type. 5817 * 5818 * @param callback Callback that will control the lifecycle of the action mode 5819 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 5820 * @return The new action mode if it is started, null otherwise 5821 * 5822 * @see ActionMode 5823 */ startActionMode(ActionMode.Callback callback, int type)5824 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 5825 ViewParent parent = getParent(); 5826 if (parent == null) return null; 5827 try { 5828 return parent.startActionModeForChild(this, callback, type); 5829 } catch (AbstractMethodError ame) { 5830 // Older implementations of custom views might not implement this. 5831 return parent.startActionModeForChild(this, callback); 5832 } 5833 } 5834 5835 /** 5836 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 5837 * Context, creating a unique View identifier to retrieve the result. 5838 * 5839 * @param intent The Intent to be started. 5840 * @param requestCode The request code to use. 5841 * @hide 5842 */ startActivityForResult(Intent intent, int requestCode)5843 public void startActivityForResult(Intent intent, int requestCode) { 5844 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 5845 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 5846 } 5847 5848 /** 5849 * If this View corresponds to the calling who, dispatches the activity result. 5850 * @param who The identifier for the targeted View to receive the result. 5851 * @param requestCode The integer request code originally supplied to 5852 * startActivityForResult(), allowing you to identify who this 5853 * result came from. 5854 * @param resultCode The integer result code returned by the child activity 5855 * through its setResult(). 5856 * @param data An Intent, which can return result data to the caller 5857 * (various data can be attached to Intent "extras"). 5858 * @return {@code true} if the activity result was dispatched. 5859 * @hide 5860 */ dispatchActivityResult( String who, int requestCode, int resultCode, Intent data)5861 public boolean dispatchActivityResult( 5862 String who, int requestCode, int resultCode, Intent data) { 5863 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 5864 onActivityResult(requestCode, resultCode, data); 5865 mStartActivityRequestWho = null; 5866 return true; 5867 } 5868 return false; 5869 } 5870 5871 /** 5872 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 5873 * 5874 * @param requestCode The integer request code originally supplied to 5875 * startActivityForResult(), allowing you to identify who this 5876 * result came from. 5877 * @param resultCode The integer result code returned by the child activity 5878 * through its setResult(). 5879 * @param data An Intent, which can return result data to the caller 5880 * (various data can be attached to Intent "extras"). 5881 * @hide 5882 */ onActivityResult(int requestCode, int resultCode, Intent data)5883 public void onActivityResult(int requestCode, int resultCode, Intent data) { 5884 // Do nothing. 5885 } 5886 5887 /** 5888 * Register a callback to be invoked when a hardware key is pressed in this view. 5889 * Key presses in software input methods will generally not trigger the methods of 5890 * this listener. 5891 * @param l the key listener to attach to this view 5892 */ setOnKeyListener(OnKeyListener l)5893 public void setOnKeyListener(OnKeyListener l) { 5894 getListenerInfo().mOnKeyListener = l; 5895 } 5896 5897 /** 5898 * Register a callback to be invoked when a touch event is sent to this view. 5899 * @param l the touch listener to attach to this view 5900 */ setOnTouchListener(OnTouchListener l)5901 public void setOnTouchListener(OnTouchListener l) { 5902 getListenerInfo().mOnTouchListener = l; 5903 } 5904 5905 /** 5906 * Register a callback to be invoked when a generic motion event is sent to this view. 5907 * @param l the generic motion listener to attach to this view 5908 */ setOnGenericMotionListener(OnGenericMotionListener l)5909 public void setOnGenericMotionListener(OnGenericMotionListener l) { 5910 getListenerInfo().mOnGenericMotionListener = l; 5911 } 5912 5913 /** 5914 * Register a callback to be invoked when a hover event is sent to this view. 5915 * @param l the hover listener to attach to this view 5916 */ setOnHoverListener(OnHoverListener l)5917 public void setOnHoverListener(OnHoverListener l) { 5918 getListenerInfo().mOnHoverListener = l; 5919 } 5920 5921 /** 5922 * Register a drag event listener callback object for this View. The parameter is 5923 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 5924 * View, the system calls the 5925 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 5926 * @param l An implementation of {@link android.view.View.OnDragListener}. 5927 */ setOnDragListener(OnDragListener l)5928 public void setOnDragListener(OnDragListener l) { 5929 getListenerInfo().mOnDragListener = l; 5930 } 5931 5932 /** 5933 * Give this view focus. This will cause 5934 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 5935 * 5936 * Note: this does not check whether this {@link View} should get focus, it just 5937 * gives it focus no matter what. It should only be called internally by framework 5938 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 5939 * 5940 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 5941 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 5942 * focus moved when requestFocus() is called. It may not always 5943 * apply, in which case use the default View.FOCUS_DOWN. 5944 * @param previouslyFocusedRect The rectangle of the view that had focus 5945 * prior in this View's coordinate system. 5946 */ handleFocusGainInternal(@ocusRealDirection int direction, Rect previouslyFocusedRect)5947 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 5948 if (DBG) { 5949 System.out.println(this + " requestFocus()"); 5950 } 5951 5952 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 5953 mPrivateFlags |= PFLAG_FOCUSED; 5954 5955 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 5956 5957 if (mParent != null) { 5958 mParent.requestChildFocus(this, this); 5959 } 5960 5961 if (mAttachInfo != null) { 5962 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 5963 } 5964 5965 onFocusChanged(true, direction, previouslyFocusedRect); 5966 refreshDrawableState(); 5967 } 5968 } 5969 5970 /** 5971 * Sets this view's preference for reveal behavior when it gains focus. 5972 * 5973 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 5974 * this view would prefer to be brought fully into view when it gains focus. 5975 * For example, a text field that a user is meant to type into. Other views such 5976 * as scrolling containers may prefer to opt-out of this behavior.</p> 5977 * 5978 * <p>The default value for views is true, though subclasses may change this 5979 * based on their preferred behavior.</p> 5980 * 5981 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 5982 * 5983 * @see #getRevealOnFocusHint() 5984 */ setRevealOnFocusHint(boolean revealOnFocus)5985 public final void setRevealOnFocusHint(boolean revealOnFocus) { 5986 if (revealOnFocus) { 5987 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 5988 } else { 5989 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 5990 } 5991 } 5992 5993 /** 5994 * Returns this view's preference for reveal behavior when it gains focus. 5995 * 5996 * <p>When this method returns true for a child view requesting focus, ancestor 5997 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 5998 * should make a best effort to make the newly focused child fully visible to the user. 5999 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 6000 * other properties affecting visibility to the user as part of the focus change.</p> 6001 * 6002 * @return true if this view would prefer to become fully visible when it gains focus, 6003 * false if it would prefer not to disrupt scroll positioning 6004 * 6005 * @see #setRevealOnFocusHint(boolean) 6006 */ getRevealOnFocusHint()6007 public final boolean getRevealOnFocusHint() { 6008 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 6009 } 6010 6011 /** 6012 * Populates <code>outRect</code> with the hotspot bounds. By default, 6013 * the hotspot bounds are identical to the screen bounds. 6014 * 6015 * @param outRect rect to populate with hotspot bounds 6016 * @hide Only for internal use by views and widgets. 6017 */ getHotspotBounds(Rect outRect)6018 public void getHotspotBounds(Rect outRect) { 6019 final Drawable background = getBackground(); 6020 if (background != null) { 6021 background.getHotspotBounds(outRect); 6022 } else { 6023 getBoundsOnScreen(outRect); 6024 } 6025 } 6026 6027 /** 6028 * Request that a rectangle of this view be visible on the screen, 6029 * scrolling if necessary just enough. 6030 * 6031 * <p>A View should call this if it maintains some notion of which part 6032 * of its content is interesting. For example, a text editing view 6033 * should call this when its cursor moves. 6034 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6035 * It should not be affected by which part of the View is currently visible or its scroll 6036 * position. 6037 * 6038 * @param rectangle The rectangle in the View's content coordinate space 6039 * @return Whether any parent scrolled. 6040 */ requestRectangleOnScreen(Rect rectangle)6041 public boolean requestRectangleOnScreen(Rect rectangle) { 6042 return requestRectangleOnScreen(rectangle, false); 6043 } 6044 6045 /** 6046 * Request that a rectangle of this view be visible on the screen, 6047 * scrolling if necessary just enough. 6048 * 6049 * <p>A View should call this if it maintains some notion of which part 6050 * of its content is interesting. For example, a text editing view 6051 * should call this when its cursor moves. 6052 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 6053 * It should not be affected by which part of the View is currently visible or its scroll 6054 * position. 6055 * <p>When <code>immediate</code> is set to true, scrolling will not be 6056 * animated. 6057 * 6058 * @param rectangle The rectangle in the View's content coordinate space 6059 * @param immediate True to forbid animated scrolling, false otherwise 6060 * @return Whether any parent scrolled. 6061 */ requestRectangleOnScreen(Rect rectangle, boolean immediate)6062 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 6063 if (mParent == null) { 6064 return false; 6065 } 6066 6067 View child = this; 6068 6069 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 6070 position.set(rectangle); 6071 6072 ViewParent parent = mParent; 6073 boolean scrolled = false; 6074 while (parent != null) { 6075 rectangle.set((int) position.left, (int) position.top, 6076 (int) position.right, (int) position.bottom); 6077 6078 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 6079 6080 if (!(parent instanceof View)) { 6081 break; 6082 } 6083 6084 // move it from child's content coordinate space to parent's content coordinate space 6085 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 6086 6087 child = (View) parent; 6088 parent = child.getParent(); 6089 } 6090 6091 return scrolled; 6092 } 6093 6094 /** 6095 * Called when this view wants to give up focus. If focus is cleared 6096 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 6097 * <p> 6098 * <strong>Note:</strong> When a View clears focus the framework is trying 6099 * to give focus to the first focusable View from the top. Hence, if this 6100 * View is the first from the top that can take focus, then all callbacks 6101 * related to clearing focus will be invoked after which the framework will 6102 * give focus to this view. 6103 * </p> 6104 */ clearFocus()6105 public void clearFocus() { 6106 if (DBG) { 6107 System.out.println(this + " clearFocus()"); 6108 } 6109 6110 clearFocusInternal(null, true, true); 6111 } 6112 6113 /** 6114 * Clears focus from the view, optionally propagating the change up through 6115 * the parent hierarchy and requesting that the root view place new focus. 6116 * 6117 * @param propagate whether to propagate the change up through the parent 6118 * hierarchy 6119 * @param refocus when propagate is true, specifies whether to request the 6120 * root view place new focus 6121 */ clearFocusInternal(View focused, boolean propagate, boolean refocus)6122 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 6123 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 6124 mPrivateFlags &= ~PFLAG_FOCUSED; 6125 6126 if (propagate && mParent != null) { 6127 mParent.clearChildFocus(this); 6128 } 6129 6130 onFocusChanged(false, 0, null); 6131 refreshDrawableState(); 6132 6133 if (propagate && (!refocus || !rootViewRequestFocus())) { 6134 notifyGlobalFocusCleared(this); 6135 } 6136 } 6137 } 6138 notifyGlobalFocusCleared(View oldFocus)6139 void notifyGlobalFocusCleared(View oldFocus) { 6140 if (oldFocus != null && mAttachInfo != null) { 6141 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 6142 } 6143 } 6144 rootViewRequestFocus()6145 boolean rootViewRequestFocus() { 6146 final View root = getRootView(); 6147 return root != null && root.requestFocus(); 6148 } 6149 6150 /** 6151 * Called internally by the view system when a new view is getting focus. 6152 * This is what clears the old focus. 6153 * <p> 6154 * <b>NOTE:</b> The parent view's focused child must be updated manually 6155 * after calling this method. Otherwise, the view hierarchy may be left in 6156 * an inconstent state. 6157 */ unFocus(View focused)6158 void unFocus(View focused) { 6159 if (DBG) { 6160 System.out.println(this + " unFocus()"); 6161 } 6162 6163 clearFocusInternal(focused, false, false); 6164 } 6165 6166 /** 6167 * Returns true if this view has focus itself, or is the ancestor of the 6168 * view that has focus. 6169 * 6170 * @return True if this view has or contains focus, false otherwise. 6171 */ 6172 @ViewDebug.ExportedProperty(category = "focus") hasFocus()6173 public boolean hasFocus() { 6174 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 6175 } 6176 6177 /** 6178 * Returns true if this view is focusable or if it contains a reachable View 6179 * for which {@link #hasFocusable()} returns true. A "reachable hasFocusable()" 6180 * is a View whose parents do not block descendants focus. 6181 * 6182 * Only {@link #VISIBLE} views are considered focusable. 6183 * 6184 * @return True if the view is focusable or if the view contains a focusable 6185 * View, false otherwise. 6186 * 6187 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 6188 * @see ViewGroup#getTouchscreenBlocksFocus() 6189 */ hasFocusable()6190 public boolean hasFocusable() { 6191 if (!isFocusableInTouchMode()) { 6192 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 6193 final ViewGroup g = (ViewGroup) p; 6194 if (g.shouldBlockFocusForTouchscreen()) { 6195 return false; 6196 } 6197 } 6198 } 6199 return (mViewFlags & VISIBILITY_MASK) == VISIBLE && isFocusable(); 6200 } 6201 6202 /** 6203 * Called by the view system when the focus state of this view changes. 6204 * When the focus change event is caused by directional navigation, direction 6205 * and previouslyFocusedRect provide insight into where the focus is coming from. 6206 * When overriding, be sure to call up through to the super class so that 6207 * the standard focus handling will occur. 6208 * 6209 * @param gainFocus True if the View has focus; false otherwise. 6210 * @param direction The direction focus has moved when requestFocus() 6211 * is called to give this view focus. Values are 6212 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 6213 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 6214 * It may not always apply, in which case use the default. 6215 * @param previouslyFocusedRect The rectangle, in this view's coordinate 6216 * system, of the previously focused view. If applicable, this will be 6217 * passed in as finer grained information about where the focus is coming 6218 * from (in addition to direction). Will be <code>null</code> otherwise. 6219 */ 6220 @CallSuper onFocusChanged(boolean gainFocus, @FocusDirection int direction, @Nullable Rect previouslyFocusedRect)6221 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 6222 @Nullable Rect previouslyFocusedRect) { 6223 if (gainFocus) { 6224 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 6225 } else { 6226 notifyViewAccessibilityStateChangedIfNeeded( 6227 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 6228 } 6229 6230 InputMethodManager imm = InputMethodManager.peekInstance(); 6231 if (!gainFocus) { 6232 if (isPressed()) { 6233 setPressed(false); 6234 } 6235 if (imm != null && mAttachInfo != null 6236 && mAttachInfo.mHasWindowFocus) { 6237 imm.focusOut(this); 6238 } 6239 onFocusLost(); 6240 } else if (imm != null && mAttachInfo != null 6241 && mAttachInfo.mHasWindowFocus) { 6242 imm.focusIn(this); 6243 } 6244 6245 invalidate(true); 6246 ListenerInfo li = mListenerInfo; 6247 if (li != null && li.mOnFocusChangeListener != null) { 6248 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 6249 } 6250 6251 if (mAttachInfo != null) { 6252 mAttachInfo.mKeyDispatchState.reset(this); 6253 } 6254 } 6255 6256 /** 6257 * Sends an accessibility event of the given type. If accessibility is 6258 * not enabled this method has no effect. The default implementation calls 6259 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 6260 * to populate information about the event source (this View), then calls 6261 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 6262 * populate the text content of the event source including its descendants, 6263 * and last calls 6264 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 6265 * on its parent to request sending of the event to interested parties. 6266 * <p> 6267 * If an {@link AccessibilityDelegate} has been specified via calling 6268 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6269 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 6270 * responsible for handling this call. 6271 * </p> 6272 * 6273 * @param eventType The type of the event to send, as defined by several types from 6274 * {@link android.view.accessibility.AccessibilityEvent}, such as 6275 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 6276 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 6277 * 6278 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6279 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6280 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 6281 * @see AccessibilityDelegate 6282 */ sendAccessibilityEvent(int eventType)6283 public void sendAccessibilityEvent(int eventType) { 6284 if (mAccessibilityDelegate != null) { 6285 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 6286 } else { 6287 sendAccessibilityEventInternal(eventType); 6288 } 6289 } 6290 6291 /** 6292 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 6293 * {@link AccessibilityEvent} to make an announcement which is related to some 6294 * sort of a context change for which none of the events representing UI transitions 6295 * is a good fit. For example, announcing a new page in a book. If accessibility 6296 * is not enabled this method does nothing. 6297 * 6298 * @param text The announcement text. 6299 */ announceForAccessibility(CharSequence text)6300 public void announceForAccessibility(CharSequence text) { 6301 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 6302 AccessibilityEvent event = AccessibilityEvent.obtain( 6303 AccessibilityEvent.TYPE_ANNOUNCEMENT); 6304 onInitializeAccessibilityEvent(event); 6305 event.getText().add(text); 6306 event.setContentDescription(null); 6307 mParent.requestSendAccessibilityEvent(this, event); 6308 } 6309 } 6310 6311 /** 6312 * @see #sendAccessibilityEvent(int) 6313 * 6314 * Note: Called from the default {@link AccessibilityDelegate}. 6315 * 6316 * @hide 6317 */ sendAccessibilityEventInternal(int eventType)6318 public void sendAccessibilityEventInternal(int eventType) { 6319 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 6320 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 6321 } 6322 } 6323 6324 /** 6325 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 6326 * takes as an argument an empty {@link AccessibilityEvent} and does not 6327 * perform a check whether accessibility is enabled. 6328 * <p> 6329 * If an {@link AccessibilityDelegate} has been specified via calling 6330 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6331 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 6332 * is responsible for handling this call. 6333 * </p> 6334 * 6335 * @param event The event to send. 6336 * 6337 * @see #sendAccessibilityEvent(int) 6338 */ sendAccessibilityEventUnchecked(AccessibilityEvent event)6339 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 6340 if (mAccessibilityDelegate != null) { 6341 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 6342 } else { 6343 sendAccessibilityEventUncheckedInternal(event); 6344 } 6345 } 6346 6347 /** 6348 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 6349 * 6350 * Note: Called from the default {@link AccessibilityDelegate}. 6351 * 6352 * @hide 6353 */ sendAccessibilityEventUncheckedInternal(AccessibilityEvent event)6354 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 6355 if (!isShown()) { 6356 return; 6357 } 6358 onInitializeAccessibilityEvent(event); 6359 // Only a subset of accessibility events populates text content. 6360 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 6361 dispatchPopulateAccessibilityEvent(event); 6362 } 6363 // In the beginning we called #isShown(), so we know that getParent() is not null. 6364 getParent().requestSendAccessibilityEvent(this, event); 6365 } 6366 6367 /** 6368 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 6369 * to its children for adding their text content to the event. Note that the 6370 * event text is populated in a separate dispatch path since we add to the 6371 * event not only the text of the source but also the text of all its descendants. 6372 * A typical implementation will call 6373 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 6374 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6375 * on each child. Override this method if custom population of the event text 6376 * content is required. 6377 * <p> 6378 * If an {@link AccessibilityDelegate} has been specified via calling 6379 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6380 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 6381 * is responsible for handling this call. 6382 * </p> 6383 * <p> 6384 * <em>Note:</em> Accessibility events of certain types are not dispatched for 6385 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 6386 * </p> 6387 * 6388 * @param event The event. 6389 * 6390 * @return True if the event population was completed. 6391 */ dispatchPopulateAccessibilityEvent(AccessibilityEvent event)6392 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 6393 if (mAccessibilityDelegate != null) { 6394 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 6395 } else { 6396 return dispatchPopulateAccessibilityEventInternal(event); 6397 } 6398 } 6399 6400 /** 6401 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6402 * 6403 * Note: Called from the default {@link AccessibilityDelegate}. 6404 * 6405 * @hide 6406 */ dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event)6407 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6408 onPopulateAccessibilityEvent(event); 6409 return false; 6410 } 6411 6412 /** 6413 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 6414 * giving a chance to this View to populate the accessibility event with its 6415 * text content. While this method is free to modify event 6416 * attributes other than text content, doing so should normally be performed in 6417 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 6418 * <p> 6419 * Example: Adding formatted date string to an accessibility event in addition 6420 * to the text added by the super implementation: 6421 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6422 * super.onPopulateAccessibilityEvent(event); 6423 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 6424 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 6425 * mCurrentDate.getTimeInMillis(), flags); 6426 * event.getText().add(selectedDateUtterance); 6427 * }</pre> 6428 * <p> 6429 * If an {@link AccessibilityDelegate} has been specified via calling 6430 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6431 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 6432 * is responsible for handling this call. 6433 * </p> 6434 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6435 * information to the event, in case the default implementation has basic information to add. 6436 * </p> 6437 * 6438 * @param event The accessibility event which to populate. 6439 * 6440 * @see #sendAccessibilityEvent(int) 6441 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6442 */ 6443 @CallSuper onPopulateAccessibilityEvent(AccessibilityEvent event)6444 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 6445 if (mAccessibilityDelegate != null) { 6446 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 6447 } else { 6448 onPopulateAccessibilityEventInternal(event); 6449 } 6450 } 6451 6452 /** 6453 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 6454 * 6455 * Note: Called from the default {@link AccessibilityDelegate}. 6456 * 6457 * @hide 6458 */ onPopulateAccessibilityEventInternal(AccessibilityEvent event)6459 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 6460 } 6461 6462 /** 6463 * Initializes an {@link AccessibilityEvent} with information about 6464 * this View which is the event source. In other words, the source of 6465 * an accessibility event is the view whose state change triggered firing 6466 * the event. 6467 * <p> 6468 * Example: Setting the password property of an event in addition 6469 * to properties set by the super implementation: 6470 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6471 * super.onInitializeAccessibilityEvent(event); 6472 * event.setPassword(true); 6473 * }</pre> 6474 * <p> 6475 * If an {@link AccessibilityDelegate} has been specified via calling 6476 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6477 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 6478 * is responsible for handling this call. 6479 * </p> 6480 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 6481 * information to the event, in case the default implementation has basic information to add. 6482 * </p> 6483 * @param event The event to initialize. 6484 * 6485 * @see #sendAccessibilityEvent(int) 6486 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 6487 */ 6488 @CallSuper onInitializeAccessibilityEvent(AccessibilityEvent event)6489 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 6490 if (mAccessibilityDelegate != null) { 6491 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 6492 } else { 6493 onInitializeAccessibilityEventInternal(event); 6494 } 6495 } 6496 6497 /** 6498 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 6499 * 6500 * Note: Called from the default {@link AccessibilityDelegate}. 6501 * 6502 * @hide 6503 */ onInitializeAccessibilityEventInternal(AccessibilityEvent event)6504 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 6505 event.setSource(this); 6506 event.setClassName(getAccessibilityClassName()); 6507 event.setPackageName(getContext().getPackageName()); 6508 event.setEnabled(isEnabled()); 6509 event.setContentDescription(mContentDescription); 6510 6511 switch (event.getEventType()) { 6512 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 6513 ArrayList<View> focusablesTempList = (mAttachInfo != null) 6514 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 6515 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 6516 event.setItemCount(focusablesTempList.size()); 6517 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 6518 if (mAttachInfo != null) { 6519 focusablesTempList.clear(); 6520 } 6521 } break; 6522 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 6523 CharSequence text = getIterableTextForAccessibility(); 6524 if (text != null && text.length() > 0) { 6525 event.setFromIndex(getAccessibilitySelectionStart()); 6526 event.setToIndex(getAccessibilitySelectionEnd()); 6527 event.setItemCount(text.length()); 6528 } 6529 } break; 6530 } 6531 } 6532 6533 /** 6534 * Returns an {@link AccessibilityNodeInfo} representing this view from the 6535 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 6536 * This method is responsible for obtaining an accessibility node info from a 6537 * pool of reusable instances and calling 6538 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 6539 * initialize the former. 6540 * <p> 6541 * Note: The client is responsible for recycling the obtained instance by calling 6542 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 6543 * </p> 6544 * 6545 * @return A populated {@link AccessibilityNodeInfo}. 6546 * 6547 * @see AccessibilityNodeInfo 6548 */ createAccessibilityNodeInfo()6549 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 6550 if (mAccessibilityDelegate != null) { 6551 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 6552 } else { 6553 return createAccessibilityNodeInfoInternal(); 6554 } 6555 } 6556 6557 /** 6558 * @see #createAccessibilityNodeInfo() 6559 * 6560 * @hide 6561 */ createAccessibilityNodeInfoInternal()6562 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 6563 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6564 if (provider != null) { 6565 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 6566 } else { 6567 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 6568 onInitializeAccessibilityNodeInfo(info); 6569 return info; 6570 } 6571 } 6572 6573 /** 6574 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 6575 * The base implementation sets: 6576 * <ul> 6577 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 6578 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 6579 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 6580 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 6581 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 6582 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 6583 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 6584 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 6585 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 6586 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 6587 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 6588 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 6589 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 6590 * </ul> 6591 * <p> 6592 * Subclasses should override this method, call the super implementation, 6593 * and set additional attributes. 6594 * </p> 6595 * <p> 6596 * If an {@link AccessibilityDelegate} has been specified via calling 6597 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 6598 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 6599 * is responsible for handling this call. 6600 * </p> 6601 * 6602 * @param info The instance to initialize. 6603 */ 6604 @CallSuper onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info)6605 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 6606 if (mAccessibilityDelegate != null) { 6607 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 6608 } else { 6609 onInitializeAccessibilityNodeInfoInternal(info); 6610 } 6611 } 6612 6613 /** 6614 * Gets the location of this view in screen coordinates. 6615 * 6616 * @param outRect The output location 6617 * @hide 6618 */ getBoundsOnScreen(Rect outRect)6619 public void getBoundsOnScreen(Rect outRect) { 6620 getBoundsOnScreen(outRect, false); 6621 } 6622 6623 /** 6624 * Gets the location of this view in screen coordinates. 6625 * 6626 * @param outRect The output location 6627 * @param clipToParent Whether to clip child bounds to the parent ones. 6628 * @hide 6629 */ getBoundsOnScreen(Rect outRect, boolean clipToParent)6630 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 6631 if (mAttachInfo == null) { 6632 return; 6633 } 6634 6635 RectF position = mAttachInfo.mTmpTransformRect; 6636 position.set(0, 0, mRight - mLeft, mBottom - mTop); 6637 6638 if (!hasIdentityMatrix()) { 6639 getMatrix().mapRect(position); 6640 } 6641 6642 position.offset(mLeft, mTop); 6643 6644 ViewParent parent = mParent; 6645 while (parent instanceof View) { 6646 View parentView = (View) parent; 6647 6648 position.offset(-parentView.mScrollX, -parentView.mScrollY); 6649 6650 if (clipToParent) { 6651 position.left = Math.max(position.left, 0); 6652 position.top = Math.max(position.top, 0); 6653 position.right = Math.min(position.right, parentView.getWidth()); 6654 position.bottom = Math.min(position.bottom, parentView.getHeight()); 6655 } 6656 6657 if (!parentView.hasIdentityMatrix()) { 6658 parentView.getMatrix().mapRect(position); 6659 } 6660 6661 position.offset(parentView.mLeft, parentView.mTop); 6662 6663 parent = parentView.mParent; 6664 } 6665 6666 if (parent instanceof ViewRootImpl) { 6667 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 6668 position.offset(0, -viewRootImpl.mCurScrollY); 6669 } 6670 6671 position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 6672 6673 outRect.set(Math.round(position.left), Math.round(position.top), 6674 Math.round(position.right), Math.round(position.bottom)); 6675 } 6676 6677 /** 6678 * Return the class name of this object to be used for accessibility purposes. 6679 * Subclasses should only override this if they are implementing something that 6680 * should be seen as a completely new class of view when used by accessibility, 6681 * unrelated to the class it is deriving from. This is used to fill in 6682 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 6683 */ getAccessibilityClassName()6684 public CharSequence getAccessibilityClassName() { 6685 return View.class.getName(); 6686 } 6687 6688 /** 6689 * Called when assist structure is being retrieved from a view as part of 6690 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 6691 * @param structure Fill in with structured view data. The default implementation 6692 * fills in all data that can be inferred from the view itself. 6693 */ onProvideStructure(ViewStructure structure)6694 public void onProvideStructure(ViewStructure structure) { 6695 final int id = mID; 6696 if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0 6697 && (id&0x0000ffff) != 0) { 6698 String pkg, type, entry; 6699 try { 6700 final Resources res = getResources(); 6701 entry = res.getResourceEntryName(id); 6702 type = res.getResourceTypeName(id); 6703 pkg = res.getResourcePackageName(id); 6704 } catch (Resources.NotFoundException e) { 6705 entry = type = pkg = null; 6706 } 6707 structure.setId(id, pkg, type, entry); 6708 } else { 6709 structure.setId(id, null, null, null); 6710 } 6711 structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop); 6712 if (!hasIdentityMatrix()) { 6713 structure.setTransformation(getMatrix()); 6714 } 6715 structure.setElevation(getZ()); 6716 structure.setVisibility(getVisibility()); 6717 structure.setEnabled(isEnabled()); 6718 if (isClickable()) { 6719 structure.setClickable(true); 6720 } 6721 if (isFocusable()) { 6722 structure.setFocusable(true); 6723 } 6724 if (isFocused()) { 6725 structure.setFocused(true); 6726 } 6727 if (isAccessibilityFocused()) { 6728 structure.setAccessibilityFocused(true); 6729 } 6730 if (isSelected()) { 6731 structure.setSelected(true); 6732 } 6733 if (isActivated()) { 6734 structure.setActivated(true); 6735 } 6736 if (isLongClickable()) { 6737 structure.setLongClickable(true); 6738 } 6739 if (this instanceof Checkable) { 6740 structure.setCheckable(true); 6741 if (((Checkable)this).isChecked()) { 6742 structure.setChecked(true); 6743 } 6744 } 6745 if (isContextClickable()) { 6746 structure.setContextClickable(true); 6747 } 6748 structure.setClassName(getAccessibilityClassName().toString()); 6749 structure.setContentDescription(getContentDescription()); 6750 } 6751 6752 /** 6753 * Called when assist structure is being retrieved from a view as part of 6754 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 6755 * generate additional virtual structure under this view. The defaullt implementation 6756 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 6757 * view's virtual accessibility nodes, if any. You can override this for a more 6758 * optimal implementation providing this data. 6759 */ onProvideVirtualStructure(ViewStructure structure)6760 public void onProvideVirtualStructure(ViewStructure structure) { 6761 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 6762 if (provider != null) { 6763 AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 6764 structure.setChildCount(1); 6765 ViewStructure root = structure.newChild(0); 6766 populateVirtualStructure(root, provider, info); 6767 info.recycle(); 6768 } 6769 } 6770 populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info)6771 private void populateVirtualStructure(ViewStructure structure, 6772 AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { 6773 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 6774 null, null, null); 6775 Rect rect = structure.getTempRect(); 6776 info.getBoundsInParent(rect); 6777 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 6778 structure.setVisibility(VISIBLE); 6779 structure.setEnabled(info.isEnabled()); 6780 if (info.isClickable()) { 6781 structure.setClickable(true); 6782 } 6783 if (info.isFocusable()) { 6784 structure.setFocusable(true); 6785 } 6786 if (info.isFocused()) { 6787 structure.setFocused(true); 6788 } 6789 if (info.isAccessibilityFocused()) { 6790 structure.setAccessibilityFocused(true); 6791 } 6792 if (info.isSelected()) { 6793 structure.setSelected(true); 6794 } 6795 if (info.isLongClickable()) { 6796 structure.setLongClickable(true); 6797 } 6798 if (info.isCheckable()) { 6799 structure.setCheckable(true); 6800 if (info.isChecked()) { 6801 structure.setChecked(true); 6802 } 6803 } 6804 if (info.isContextClickable()) { 6805 structure.setContextClickable(true); 6806 } 6807 CharSequence cname = info.getClassName(); 6808 structure.setClassName(cname != null ? cname.toString() : null); 6809 structure.setContentDescription(info.getContentDescription()); 6810 if (info.getText() != null || info.getError() != null) { 6811 structure.setText(info.getText(), info.getTextSelectionStart(), 6812 info.getTextSelectionEnd()); 6813 } 6814 final int NCHILDREN = info.getChildCount(); 6815 if (NCHILDREN > 0) { 6816 structure.setChildCount(NCHILDREN); 6817 for (int i=0; i<NCHILDREN; i++) { 6818 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 6819 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 6820 ViewStructure child = structure.newChild(i); 6821 populateVirtualStructure(child, provider, cinfo); 6822 cinfo.recycle(); 6823 } 6824 } 6825 } 6826 6827 /** 6828 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 6829 * implementation calls {@link #onProvideStructure} and 6830 * {@link #onProvideVirtualStructure}. 6831 */ dispatchProvideStructure(ViewStructure structure)6832 public void dispatchProvideStructure(ViewStructure structure) { 6833 if (!isAssistBlocked()) { 6834 onProvideStructure(structure); 6835 onProvideVirtualStructure(structure); 6836 } else { 6837 structure.setClassName(getAccessibilityClassName().toString()); 6838 structure.setAssistBlocked(true); 6839 } 6840 } 6841 6842 /** 6843 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 6844 * 6845 * Note: Called from the default {@link AccessibilityDelegate}. 6846 * 6847 * @hide 6848 */ onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)6849 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 6850 if (mAttachInfo == null) { 6851 return; 6852 } 6853 6854 Rect bounds = mAttachInfo.mTmpInvalRect; 6855 6856 getDrawingRect(bounds); 6857 info.setBoundsInParent(bounds); 6858 6859 getBoundsOnScreen(bounds, true); 6860 info.setBoundsInScreen(bounds); 6861 6862 ViewParent parent = getParentForAccessibility(); 6863 if (parent instanceof View) { 6864 info.setParent((View) parent); 6865 } 6866 6867 if (mID != View.NO_ID) { 6868 View rootView = getRootView(); 6869 if (rootView == null) { 6870 rootView = this; 6871 } 6872 6873 View label = rootView.findLabelForView(this, mID); 6874 if (label != null) { 6875 info.setLabeledBy(label); 6876 } 6877 6878 if ((mAttachInfo.mAccessibilityFetchFlags 6879 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 6880 && Resources.resourceHasPackage(mID)) { 6881 try { 6882 String viewId = getResources().getResourceName(mID); 6883 info.setViewIdResourceName(viewId); 6884 } catch (Resources.NotFoundException nfe) { 6885 /* ignore */ 6886 } 6887 } 6888 } 6889 6890 if (mLabelForId != View.NO_ID) { 6891 View rootView = getRootView(); 6892 if (rootView == null) { 6893 rootView = this; 6894 } 6895 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 6896 if (labeled != null) { 6897 info.setLabelFor(labeled); 6898 } 6899 } 6900 6901 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 6902 View rootView = getRootView(); 6903 if (rootView == null) { 6904 rootView = this; 6905 } 6906 View next = rootView.findViewInsideOutShouldExist(this, 6907 mAccessibilityTraversalBeforeId); 6908 if (next != null && next.includeForAccessibility()) { 6909 info.setTraversalBefore(next); 6910 } 6911 } 6912 6913 if (mAccessibilityTraversalAfterId != View.NO_ID) { 6914 View rootView = getRootView(); 6915 if (rootView == null) { 6916 rootView = this; 6917 } 6918 View next = rootView.findViewInsideOutShouldExist(this, 6919 mAccessibilityTraversalAfterId); 6920 if (next != null && next.includeForAccessibility()) { 6921 info.setTraversalAfter(next); 6922 } 6923 } 6924 6925 info.setVisibleToUser(isVisibleToUser()); 6926 6927 if ((mAttachInfo != null) && ((mAttachInfo.mAccessibilityFetchFlags 6928 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0)) { 6929 info.setImportantForAccessibility(isImportantForAccessibility()); 6930 } else { 6931 info.setImportantForAccessibility(true); 6932 } 6933 6934 info.setPackageName(mContext.getPackageName()); 6935 info.setClassName(getAccessibilityClassName()); 6936 info.setContentDescription(getContentDescription()); 6937 6938 info.setEnabled(isEnabled()); 6939 info.setClickable(isClickable()); 6940 info.setFocusable(isFocusable()); 6941 info.setFocused(isFocused()); 6942 info.setAccessibilityFocused(isAccessibilityFocused()); 6943 info.setSelected(isSelected()); 6944 info.setLongClickable(isLongClickable()); 6945 info.setContextClickable(isContextClickable()); 6946 info.setLiveRegion(getAccessibilityLiveRegion()); 6947 6948 // TODO: These make sense only if we are in an AdapterView but all 6949 // views can be selected. Maybe from accessibility perspective 6950 // we should report as selectable view in an AdapterView. 6951 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 6952 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 6953 6954 if (isFocusable()) { 6955 if (isFocused()) { 6956 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 6957 } else { 6958 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 6959 } 6960 } 6961 6962 if (!isAccessibilityFocused()) { 6963 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 6964 } else { 6965 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 6966 } 6967 6968 if (isClickable() && isEnabled()) { 6969 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 6970 } 6971 6972 if (isLongClickable() && isEnabled()) { 6973 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 6974 } 6975 6976 if (isContextClickable() && isEnabled()) { 6977 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 6978 } 6979 6980 CharSequence text = getIterableTextForAccessibility(); 6981 if (text != null && text.length() > 0) { 6982 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 6983 6984 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 6985 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 6986 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 6987 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 6988 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 6989 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 6990 } 6991 6992 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 6993 populateAccessibilityNodeInfoDrawingOrderInParent(info); 6994 } 6995 6996 /** 6997 * Determine the order in which this view will be drawn relative to its siblings for a11y 6998 * 6999 * @param info The info whose drawing order should be populated 7000 */ populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info)7001 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 7002 /* 7003 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 7004 * drawing order may not be well-defined, and some Views with custom drawing order may 7005 * not be initialized sufficiently to respond properly getChildDrawingOrder. 7006 */ 7007 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 7008 info.setDrawingOrder(0); 7009 return; 7010 } 7011 int drawingOrderInParent = 1; 7012 // Iterate up the hierarchy if parents are not important for a11y 7013 View viewAtDrawingLevel = this; 7014 final ViewParent parent = getParentForAccessibility(); 7015 while (viewAtDrawingLevel != parent) { 7016 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 7017 if (!(currentParent instanceof ViewGroup)) { 7018 // Should only happen for the Decor 7019 drawingOrderInParent = 0; 7020 break; 7021 } else { 7022 final ViewGroup parentGroup = (ViewGroup) currentParent; 7023 final int childCount = parentGroup.getChildCount(); 7024 if (childCount > 1) { 7025 List<View> preorderedList = parentGroup.buildOrderedChildList(); 7026 if (preorderedList != null) { 7027 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 7028 for (int i = 0; i < childDrawIndex; i++) { 7029 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 7030 } 7031 } else { 7032 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 7033 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 7034 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 7035 .getChildDrawingOrder(childCount, childIndex) : childIndex; 7036 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 7037 if (childDrawIndex != 0) { 7038 for (int i = 0; i < numChildrenToIterate; i++) { 7039 final int otherDrawIndex = (customOrder ? 7040 parentGroup.getChildDrawingOrder(childCount, i) : i); 7041 if (otherDrawIndex < childDrawIndex) { 7042 drawingOrderInParent += 7043 numViewsForAccessibility(parentGroup.getChildAt(i)); 7044 } 7045 } 7046 } 7047 } 7048 } 7049 } 7050 viewAtDrawingLevel = (View) currentParent; 7051 } 7052 info.setDrawingOrder(drawingOrderInParent); 7053 } 7054 numViewsForAccessibility(View view)7055 private static int numViewsForAccessibility(View view) { 7056 if (view != null) { 7057 if (view.includeForAccessibility()) { 7058 return 1; 7059 } else if (view instanceof ViewGroup) { 7060 return ((ViewGroup) view).getNumChildrenForAccessibility(); 7061 } 7062 } 7063 return 0; 7064 } 7065 findLabelForView(View view, int labeledId)7066 private View findLabelForView(View view, int labeledId) { 7067 if (mMatchLabelForPredicate == null) { 7068 mMatchLabelForPredicate = new MatchLabelForPredicate(); 7069 } 7070 mMatchLabelForPredicate.mLabeledId = labeledId; 7071 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 7072 } 7073 7074 /** 7075 * Computes whether this view is visible to the user. Such a view is 7076 * attached, visible, all its predecessors are visible, it is not clipped 7077 * entirely by its predecessors, and has an alpha greater than zero. 7078 * 7079 * @return Whether the view is visible on the screen. 7080 * 7081 * @hide 7082 */ isVisibleToUser()7083 protected boolean isVisibleToUser() { 7084 return isVisibleToUser(null); 7085 } 7086 7087 /** 7088 * Computes whether the given portion of this view is visible to the user. 7089 * Such a view is attached, visible, all its predecessors are visible, 7090 * has an alpha greater than zero, and the specified portion is not 7091 * clipped entirely by its predecessors. 7092 * 7093 * @param boundInView the portion of the view to test; coordinates should be relative; may be 7094 * <code>null</code>, and the entire view will be tested in this case. 7095 * When <code>true</code> is returned by the function, the actual visible 7096 * region will be stored in this parameter; that is, if boundInView is fully 7097 * contained within the view, no modification will be made, otherwise regions 7098 * outside of the visible area of the view will be clipped. 7099 * 7100 * @return Whether the specified portion of the view is visible on the screen. 7101 * 7102 * @hide 7103 */ isVisibleToUser(Rect boundInView)7104 protected boolean isVisibleToUser(Rect boundInView) { 7105 if (mAttachInfo != null) { 7106 // Attached to invisible window means this view is not visible. 7107 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 7108 return false; 7109 } 7110 // An invisible predecessor or one with alpha zero means 7111 // that this view is not visible to the user. 7112 Object current = this; 7113 while (current instanceof View) { 7114 View view = (View) current; 7115 // We have attach info so this view is attached and there is no 7116 // need to check whether we reach to ViewRootImpl on the way up. 7117 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 7118 view.getVisibility() != VISIBLE) { 7119 return false; 7120 } 7121 current = view.mParent; 7122 } 7123 // Check if the view is entirely covered by its predecessors. 7124 Rect visibleRect = mAttachInfo.mTmpInvalRect; 7125 Point offset = mAttachInfo.mPoint; 7126 if (!getGlobalVisibleRect(visibleRect, offset)) { 7127 return false; 7128 } 7129 // Check if the visible portion intersects the rectangle of interest. 7130 if (boundInView != null) { 7131 visibleRect.offset(-offset.x, -offset.y); 7132 return boundInView.intersect(visibleRect); 7133 } 7134 return true; 7135 } 7136 return false; 7137 } 7138 7139 /** 7140 * Returns the delegate for implementing accessibility support via 7141 * composition. For more details see {@link AccessibilityDelegate}. 7142 * 7143 * @return The delegate, or null if none set. 7144 * 7145 * @hide 7146 */ getAccessibilityDelegate()7147 public AccessibilityDelegate getAccessibilityDelegate() { 7148 return mAccessibilityDelegate; 7149 } 7150 7151 /** 7152 * Sets a delegate for implementing accessibility support via composition 7153 * (as opposed to inheritance). For more details, see 7154 * {@link AccessibilityDelegate}. 7155 * <p> 7156 * <strong>Note:</strong> On platform versions prior to 7157 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 7158 * views in the {@code android.widget.*} package are called <i>before</i> 7159 * host methods. This prevents certain properties such as class name from 7160 * being modified by overriding 7161 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 7162 * as any changes will be overwritten by the host class. 7163 * <p> 7164 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 7165 * methods are called <i>after</i> host methods, which all properties to be 7166 * modified without being overwritten by the host class. 7167 * 7168 * @param delegate the object to which accessibility method calls should be 7169 * delegated 7170 * @see AccessibilityDelegate 7171 */ setAccessibilityDelegate(@ullable AccessibilityDelegate delegate)7172 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 7173 mAccessibilityDelegate = delegate; 7174 } 7175 7176 /** 7177 * Gets the provider for managing a virtual view hierarchy rooted at this View 7178 * and reported to {@link android.accessibilityservice.AccessibilityService}s 7179 * that explore the window content. 7180 * <p> 7181 * If this method returns an instance, this instance is responsible for managing 7182 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 7183 * View including the one representing the View itself. Similarly the returned 7184 * instance is responsible for performing accessibility actions on any virtual 7185 * view or the root view itself. 7186 * </p> 7187 * <p> 7188 * If an {@link AccessibilityDelegate} has been specified via calling 7189 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7190 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 7191 * is responsible for handling this call. 7192 * </p> 7193 * 7194 * @return The provider. 7195 * 7196 * @see AccessibilityNodeProvider 7197 */ getAccessibilityNodeProvider()7198 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 7199 if (mAccessibilityDelegate != null) { 7200 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 7201 } else { 7202 return null; 7203 } 7204 } 7205 7206 /** 7207 * Gets the unique identifier of this view on the screen for accessibility purposes. 7208 * If this {@link View} is not attached to any window, {@value #NO_ID} is returned. 7209 * 7210 * @return The view accessibility id. 7211 * 7212 * @hide 7213 */ getAccessibilityViewId()7214 public int getAccessibilityViewId() { 7215 if (mAccessibilityViewId == NO_ID) { 7216 mAccessibilityViewId = sNextAccessibilityViewId++; 7217 } 7218 return mAccessibilityViewId; 7219 } 7220 7221 /** 7222 * Gets the unique identifier of the window in which this View reseides. 7223 * 7224 * @return The window accessibility id. 7225 * 7226 * @hide 7227 */ getAccessibilityWindowId()7228 public int getAccessibilityWindowId() { 7229 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 7230 : AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 7231 } 7232 7233 /** 7234 * Returns the {@link View}'s content description. 7235 * <p> 7236 * <strong>Note:</strong> Do not override this method, as it will have no 7237 * effect on the content description presented to accessibility services. 7238 * You must call {@link #setContentDescription(CharSequence)} to modify the 7239 * content description. 7240 * 7241 * @return the content description 7242 * @see #setContentDescription(CharSequence) 7243 * @attr ref android.R.styleable#View_contentDescription 7244 */ 7245 @ViewDebug.ExportedProperty(category = "accessibility") getContentDescription()7246 public CharSequence getContentDescription() { 7247 return mContentDescription; 7248 } 7249 7250 /** 7251 * Sets the {@link View}'s content description. 7252 * <p> 7253 * A content description briefly describes the view and is primarily used 7254 * for accessibility support to determine how a view should be presented to 7255 * the user. In the case of a view with no textual representation, such as 7256 * {@link android.widget.ImageButton}, a useful content description 7257 * explains what the view does. For example, an image button with a phone 7258 * icon that is used to place a call may use "Call" as its content 7259 * description. An image of a floppy disk that is used to save a file may 7260 * use "Save". 7261 * 7262 * @param contentDescription The content description. 7263 * @see #getContentDescription() 7264 * @attr ref android.R.styleable#View_contentDescription 7265 */ 7266 @RemotableViewMethod setContentDescription(CharSequence contentDescription)7267 public void setContentDescription(CharSequence contentDescription) { 7268 if (mContentDescription == null) { 7269 if (contentDescription == null) { 7270 return; 7271 } 7272 } else if (mContentDescription.equals(contentDescription)) { 7273 return; 7274 } 7275 mContentDescription = contentDescription; 7276 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 7277 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 7278 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 7279 notifySubtreeAccessibilityStateChangedIfNeeded(); 7280 } else { 7281 notifyViewAccessibilityStateChangedIfNeeded( 7282 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 7283 } 7284 } 7285 7286 /** 7287 * Sets the id of a view before which this one is visited in accessibility traversal. 7288 * A screen-reader must visit the content of this view before the content of the one 7289 * it precedes. For example, if view B is set to be before view A, then a screen-reader 7290 * will traverse the entire content of B before traversing the entire content of A, 7291 * regardles of what traversal strategy it is using. 7292 * <p> 7293 * Views that do not have specified before/after relationships are traversed in order 7294 * determined by the screen-reader. 7295 * </p> 7296 * <p> 7297 * Setting that this view is before a view that is not important for accessibility 7298 * or if this view is not important for accessibility will have no effect as the 7299 * screen-reader is not aware of unimportant views. 7300 * </p> 7301 * 7302 * @param beforeId The id of a view this one precedes in accessibility traversal. 7303 * 7304 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 7305 * 7306 * @see #setImportantForAccessibility(int) 7307 */ 7308 @RemotableViewMethod setAccessibilityTraversalBefore(int beforeId)7309 public void setAccessibilityTraversalBefore(int beforeId) { 7310 if (mAccessibilityTraversalBeforeId == beforeId) { 7311 return; 7312 } 7313 mAccessibilityTraversalBeforeId = beforeId; 7314 notifyViewAccessibilityStateChangedIfNeeded( 7315 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7316 } 7317 7318 /** 7319 * Gets the id of a view before which this one is visited in accessibility traversal. 7320 * 7321 * @return The id of a view this one precedes in accessibility traversal if 7322 * specified, otherwise {@link #NO_ID}. 7323 * 7324 * @see #setAccessibilityTraversalBefore(int) 7325 */ getAccessibilityTraversalBefore()7326 public int getAccessibilityTraversalBefore() { 7327 return mAccessibilityTraversalBeforeId; 7328 } 7329 7330 /** 7331 * Sets the id of a view after which this one is visited in accessibility traversal. 7332 * A screen-reader must visit the content of the other view before the content of this 7333 * one. For example, if view B is set to be after view A, then a screen-reader 7334 * will traverse the entire content of A before traversing the entire content of B, 7335 * regardles of what traversal strategy it is using. 7336 * <p> 7337 * Views that do not have specified before/after relationships are traversed in order 7338 * determined by the screen-reader. 7339 * </p> 7340 * <p> 7341 * Setting that this view is after a view that is not important for accessibility 7342 * or if this view is not important for accessibility will have no effect as the 7343 * screen-reader is not aware of unimportant views. 7344 * </p> 7345 * 7346 * @param afterId The id of a view this one succedees in accessibility traversal. 7347 * 7348 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 7349 * 7350 * @see #setImportantForAccessibility(int) 7351 */ 7352 @RemotableViewMethod setAccessibilityTraversalAfter(int afterId)7353 public void setAccessibilityTraversalAfter(int afterId) { 7354 if (mAccessibilityTraversalAfterId == afterId) { 7355 return; 7356 } 7357 mAccessibilityTraversalAfterId = afterId; 7358 notifyViewAccessibilityStateChangedIfNeeded( 7359 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7360 } 7361 7362 /** 7363 * Gets the id of a view after which this one is visited in accessibility traversal. 7364 * 7365 * @return The id of a view this one succeedes in accessibility traversal if 7366 * specified, otherwise {@link #NO_ID}. 7367 * 7368 * @see #setAccessibilityTraversalAfter(int) 7369 */ getAccessibilityTraversalAfter()7370 public int getAccessibilityTraversalAfter() { 7371 return mAccessibilityTraversalAfterId; 7372 } 7373 7374 /** 7375 * Gets the id of a view for which this view serves as a label for 7376 * accessibility purposes. 7377 * 7378 * @return The labeled view id. 7379 */ 7380 @ViewDebug.ExportedProperty(category = "accessibility") getLabelFor()7381 public int getLabelFor() { 7382 return mLabelForId; 7383 } 7384 7385 /** 7386 * Sets the id of a view for which this view serves as a label for 7387 * accessibility purposes. 7388 * 7389 * @param id The labeled view id. 7390 */ 7391 @RemotableViewMethod setLabelFor(@dRes int id)7392 public void setLabelFor(@IdRes int id) { 7393 if (mLabelForId == id) { 7394 return; 7395 } 7396 mLabelForId = id; 7397 if (mLabelForId != View.NO_ID 7398 && mID == View.NO_ID) { 7399 mID = generateViewId(); 7400 } 7401 notifyViewAccessibilityStateChangedIfNeeded( 7402 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7403 } 7404 7405 /** 7406 * Invoked whenever this view loses focus, either by losing window focus or by losing 7407 * focus within its window. This method can be used to clear any state tied to the 7408 * focus. For instance, if a button is held pressed with the trackball and the window 7409 * loses focus, this method can be used to cancel the press. 7410 * 7411 * Subclasses of View overriding this method should always call super.onFocusLost(). 7412 * 7413 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 7414 * @see #onWindowFocusChanged(boolean) 7415 * 7416 * @hide pending API council approval 7417 */ 7418 @CallSuper onFocusLost()7419 protected void onFocusLost() { 7420 resetPressedState(); 7421 } 7422 resetPressedState()7423 private void resetPressedState() { 7424 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 7425 return; 7426 } 7427 7428 if (isPressed()) { 7429 setPressed(false); 7430 7431 if (!mHasPerformedLongPress) { 7432 removeLongPressCallback(); 7433 } 7434 } 7435 } 7436 7437 /** 7438 * Returns true if this view has focus 7439 * 7440 * @return True if this view has focus, false otherwise. 7441 */ 7442 @ViewDebug.ExportedProperty(category = "focus") isFocused()7443 public boolean isFocused() { 7444 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7445 } 7446 7447 /** 7448 * Find the view in the hierarchy rooted at this view that currently has 7449 * focus. 7450 * 7451 * @return The view that currently has focus, or null if no focused view can 7452 * be found. 7453 */ findFocus()7454 public View findFocus() { 7455 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 7456 } 7457 7458 /** 7459 * Indicates whether this view is one of the set of scrollable containers in 7460 * its window. 7461 * 7462 * @return whether this view is one of the set of scrollable containers in 7463 * its window 7464 * 7465 * @attr ref android.R.styleable#View_isScrollContainer 7466 */ isScrollContainer()7467 public boolean isScrollContainer() { 7468 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 7469 } 7470 7471 /** 7472 * Change whether this view is one of the set of scrollable containers in 7473 * its window. This will be used to determine whether the window can 7474 * resize or must pan when a soft input area is open -- scrollable 7475 * containers allow the window to use resize mode since the container 7476 * will appropriately shrink. 7477 * 7478 * @attr ref android.R.styleable#View_isScrollContainer 7479 */ setScrollContainer(boolean isScrollContainer)7480 public void setScrollContainer(boolean isScrollContainer) { 7481 if (isScrollContainer) { 7482 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 7483 mAttachInfo.mScrollContainers.add(this); 7484 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 7485 } 7486 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 7487 } else { 7488 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 7489 mAttachInfo.mScrollContainers.remove(this); 7490 } 7491 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 7492 } 7493 } 7494 7495 /** 7496 * Returns the quality of the drawing cache. 7497 * 7498 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7499 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7500 * 7501 * @see #setDrawingCacheQuality(int) 7502 * @see #setDrawingCacheEnabled(boolean) 7503 * @see #isDrawingCacheEnabled() 7504 * 7505 * @attr ref android.R.styleable#View_drawingCacheQuality 7506 */ 7507 @DrawingCacheQuality getDrawingCacheQuality()7508 public int getDrawingCacheQuality() { 7509 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 7510 } 7511 7512 /** 7513 * Set the drawing cache quality of this view. This value is used only when the 7514 * drawing cache is enabled 7515 * 7516 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 7517 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 7518 * 7519 * @see #getDrawingCacheQuality() 7520 * @see #setDrawingCacheEnabled(boolean) 7521 * @see #isDrawingCacheEnabled() 7522 * 7523 * @attr ref android.R.styleable#View_drawingCacheQuality 7524 */ setDrawingCacheQuality(@rawingCacheQuality int quality)7525 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 7526 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 7527 } 7528 7529 /** 7530 * Returns whether the screen should remain on, corresponding to the current 7531 * value of {@link #KEEP_SCREEN_ON}. 7532 * 7533 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 7534 * 7535 * @see #setKeepScreenOn(boolean) 7536 * 7537 * @attr ref android.R.styleable#View_keepScreenOn 7538 */ getKeepScreenOn()7539 public boolean getKeepScreenOn() { 7540 return (mViewFlags & KEEP_SCREEN_ON) != 0; 7541 } 7542 7543 /** 7544 * Controls whether the screen should remain on, modifying the 7545 * value of {@link #KEEP_SCREEN_ON}. 7546 * 7547 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 7548 * 7549 * @see #getKeepScreenOn() 7550 * 7551 * @attr ref android.R.styleable#View_keepScreenOn 7552 */ setKeepScreenOn(boolean keepScreenOn)7553 public void setKeepScreenOn(boolean keepScreenOn) { 7554 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 7555 } 7556 7557 /** 7558 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7559 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7560 * 7561 * @attr ref android.R.styleable#View_nextFocusLeft 7562 */ getNextFocusLeftId()7563 public int getNextFocusLeftId() { 7564 return mNextFocusLeftId; 7565 } 7566 7567 /** 7568 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 7569 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 7570 * decide automatically. 7571 * 7572 * @attr ref android.R.styleable#View_nextFocusLeft 7573 */ setNextFocusLeftId(int nextFocusLeftId)7574 public void setNextFocusLeftId(int nextFocusLeftId) { 7575 mNextFocusLeftId = nextFocusLeftId; 7576 } 7577 7578 /** 7579 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7580 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7581 * 7582 * @attr ref android.R.styleable#View_nextFocusRight 7583 */ getNextFocusRightId()7584 public int getNextFocusRightId() { 7585 return mNextFocusRightId; 7586 } 7587 7588 /** 7589 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 7590 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 7591 * decide automatically. 7592 * 7593 * @attr ref android.R.styleable#View_nextFocusRight 7594 */ setNextFocusRightId(int nextFocusRightId)7595 public void setNextFocusRightId(int nextFocusRightId) { 7596 mNextFocusRightId = nextFocusRightId; 7597 } 7598 7599 /** 7600 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7601 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7602 * 7603 * @attr ref android.R.styleable#View_nextFocusUp 7604 */ getNextFocusUpId()7605 public int getNextFocusUpId() { 7606 return mNextFocusUpId; 7607 } 7608 7609 /** 7610 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 7611 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 7612 * decide automatically. 7613 * 7614 * @attr ref android.R.styleable#View_nextFocusUp 7615 */ setNextFocusUpId(int nextFocusUpId)7616 public void setNextFocusUpId(int nextFocusUpId) { 7617 mNextFocusUpId = nextFocusUpId; 7618 } 7619 7620 /** 7621 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7622 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7623 * 7624 * @attr ref android.R.styleable#View_nextFocusDown 7625 */ getNextFocusDownId()7626 public int getNextFocusDownId() { 7627 return mNextFocusDownId; 7628 } 7629 7630 /** 7631 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 7632 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 7633 * decide automatically. 7634 * 7635 * @attr ref android.R.styleable#View_nextFocusDown 7636 */ setNextFocusDownId(int nextFocusDownId)7637 public void setNextFocusDownId(int nextFocusDownId) { 7638 mNextFocusDownId = nextFocusDownId; 7639 } 7640 7641 /** 7642 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 7643 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 7644 * 7645 * @attr ref android.R.styleable#View_nextFocusForward 7646 */ getNextFocusForwardId()7647 public int getNextFocusForwardId() { 7648 return mNextFocusForwardId; 7649 } 7650 7651 /** 7652 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 7653 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 7654 * decide automatically. 7655 * 7656 * @attr ref android.R.styleable#View_nextFocusForward 7657 */ setNextFocusForwardId(int nextFocusForwardId)7658 public void setNextFocusForwardId(int nextFocusForwardId) { 7659 mNextFocusForwardId = nextFocusForwardId; 7660 } 7661 7662 /** 7663 * Returns the visibility of this view and all of its ancestors 7664 * 7665 * @return True if this view and all of its ancestors are {@link #VISIBLE} 7666 */ isShown()7667 public boolean isShown() { 7668 View current = this; 7669 //noinspection ConstantConditions 7670 do { 7671 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 7672 return false; 7673 } 7674 ViewParent parent = current.mParent; 7675 if (parent == null) { 7676 return false; // We are not attached to the view root 7677 } 7678 if (!(parent instanceof View)) { 7679 return true; 7680 } 7681 current = (View) parent; 7682 } while (current != null); 7683 7684 return false; 7685 } 7686 7687 /** 7688 * Called by the view hierarchy when the content insets for a window have 7689 * changed, to allow it to adjust its content to fit within those windows. 7690 * The content insets tell you the space that the status bar, input method, 7691 * and other system windows infringe on the application's window. 7692 * 7693 * <p>You do not normally need to deal with this function, since the default 7694 * window decoration given to applications takes care of applying it to the 7695 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 7696 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 7697 * and your content can be placed under those system elements. You can then 7698 * use this method within your view hierarchy if you have parts of your UI 7699 * which you would like to ensure are not being covered. 7700 * 7701 * <p>The default implementation of this method simply applies the content 7702 * insets to the view's padding, consuming that content (modifying the 7703 * insets to be 0), and returning true. This behavior is off by default, but can 7704 * be enabled through {@link #setFitsSystemWindows(boolean)}. 7705 * 7706 * <p>This function's traversal down the hierarchy is depth-first. The same content 7707 * insets object is propagated down the hierarchy, so any changes made to it will 7708 * be seen by all following views (including potentially ones above in 7709 * the hierarchy since this is a depth-first traversal). The first view 7710 * that returns true will abort the entire traversal. 7711 * 7712 * <p>The default implementation works well for a situation where it is 7713 * used with a container that covers the entire window, allowing it to 7714 * apply the appropriate insets to its content on all edges. If you need 7715 * a more complicated layout (such as two different views fitting system 7716 * windows, one on the top of the window, and one on the bottom), 7717 * you can override the method and handle the insets however you would like. 7718 * Note that the insets provided by the framework are always relative to the 7719 * far edges of the window, not accounting for the location of the called view 7720 * within that window. (In fact when this method is called you do not yet know 7721 * where the layout will place the view, as it is done before layout happens.) 7722 * 7723 * <p>Note: unlike many View methods, there is no dispatch phase to this 7724 * call. If you are overriding it in a ViewGroup and want to allow the 7725 * call to continue to your children, you must be sure to call the super 7726 * implementation. 7727 * 7728 * <p>Here is a sample layout that makes use of fitting system windows 7729 * to have controls for a video view placed inside of the window decorations 7730 * that it hides and shows. This can be used with code like the second 7731 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 7732 * 7733 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 7734 * 7735 * @param insets Current content insets of the window. Prior to 7736 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 7737 * the insets or else you and Android will be unhappy. 7738 * 7739 * @return {@code true} if this view applied the insets and it should not 7740 * continue propagating further down the hierarchy, {@code false} otherwise. 7741 * @see #getFitsSystemWindows() 7742 * @see #setFitsSystemWindows(boolean) 7743 * @see #setSystemUiVisibility(int) 7744 * 7745 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 7746 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 7747 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 7748 * to implement handling their own insets. 7749 */ fitSystemWindows(Rect insets)7750 protected boolean fitSystemWindows(Rect insets) { 7751 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 7752 if (insets == null) { 7753 // Null insets by definition have already been consumed. 7754 // This call cannot apply insets since there are none to apply, 7755 // so return false. 7756 return false; 7757 } 7758 // If we're not in the process of dispatching the newer apply insets call, 7759 // that means we're not in the compatibility path. Dispatch into the newer 7760 // apply insets path and take things from there. 7761 try { 7762 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 7763 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 7764 } finally { 7765 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 7766 } 7767 } else { 7768 // We're being called from the newer apply insets path. 7769 // Perform the standard fallback behavior. 7770 return fitSystemWindowsInt(insets); 7771 } 7772 } 7773 fitSystemWindowsInt(Rect insets)7774 private boolean fitSystemWindowsInt(Rect insets) { 7775 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 7776 mUserPaddingStart = UNDEFINED_PADDING; 7777 mUserPaddingEnd = UNDEFINED_PADDING; 7778 Rect localInsets = sThreadLocal.get(); 7779 if (localInsets == null) { 7780 localInsets = new Rect(); 7781 sThreadLocal.set(localInsets); 7782 } 7783 boolean res = computeFitSystemWindows(insets, localInsets); 7784 mUserPaddingLeftInitial = localInsets.left; 7785 mUserPaddingRightInitial = localInsets.right; 7786 internalSetPadding(localInsets.left, localInsets.top, 7787 localInsets.right, localInsets.bottom); 7788 return res; 7789 } 7790 return false; 7791 } 7792 7793 /** 7794 * Called when the view should apply {@link WindowInsets} according to its internal policy. 7795 * 7796 * <p>This method should be overridden by views that wish to apply a policy different from or 7797 * in addition to the default behavior. Clients that wish to force a view subtree 7798 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 7799 * 7800 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 7801 * it will be called during dispatch instead of this method. The listener may optionally 7802 * call this method from its own implementation if it wishes to apply the view's default 7803 * insets policy in addition to its own.</p> 7804 * 7805 * <p>Implementations of this method should either return the insets parameter unchanged 7806 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 7807 * that this view applied itself. This allows new inset types added in future platform 7808 * versions to pass through existing implementations unchanged without being erroneously 7809 * consumed.</p> 7810 * 7811 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 7812 * property is set then the view will consume the system window insets and apply them 7813 * as padding for the view.</p> 7814 * 7815 * @param insets Insets to apply 7816 * @return The supplied insets with any applied insets consumed 7817 */ onApplyWindowInsets(WindowInsets insets)7818 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 7819 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 7820 // We weren't called from within a direct call to fitSystemWindows, 7821 // call into it as a fallback in case we're in a class that overrides it 7822 // and has logic to perform. 7823 if (fitSystemWindows(insets.getSystemWindowInsets())) { 7824 return insets.consumeSystemWindowInsets(); 7825 } 7826 } else { 7827 // We were called from within a direct call to fitSystemWindows. 7828 if (fitSystemWindowsInt(insets.getSystemWindowInsets())) { 7829 return insets.consumeSystemWindowInsets(); 7830 } 7831 } 7832 return insets; 7833 } 7834 7835 /** 7836 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 7837 * window insets to this view. The listener's 7838 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 7839 * method will be called instead of the view's 7840 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 7841 * 7842 * @param listener Listener to set 7843 * 7844 * @see #onApplyWindowInsets(WindowInsets) 7845 */ setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)7846 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 7847 getListenerInfo().mOnApplyWindowInsetsListener = listener; 7848 } 7849 7850 /** 7851 * Request to apply the given window insets to this view or another view in its subtree. 7852 * 7853 * <p>This method should be called by clients wishing to apply insets corresponding to areas 7854 * obscured by window decorations or overlays. This can include the status and navigation bars, 7855 * action bars, input methods and more. New inset categories may be added in the future. 7856 * The method returns the insets provided minus any that were applied by this view or its 7857 * children.</p> 7858 * 7859 * <p>Clients wishing to provide custom behavior should override the 7860 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 7861 * {@link OnApplyWindowInsetsListener} via the 7862 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 7863 * method.</p> 7864 * 7865 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 7866 * </p> 7867 * 7868 * @param insets Insets to apply 7869 * @return The provided insets minus the insets that were consumed 7870 */ dispatchApplyWindowInsets(WindowInsets insets)7871 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 7872 try { 7873 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 7874 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 7875 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 7876 } else { 7877 return onApplyWindowInsets(insets); 7878 } 7879 } finally { 7880 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 7881 } 7882 } 7883 7884 /** 7885 * Compute the view's coordinate within the surface. 7886 * 7887 * <p>Computes the coordinates of this view in its surface. The argument 7888 * must be an array of two integers. After the method returns, the array 7889 * contains the x and y location in that order.</p> 7890 * @hide 7891 * @param location an array of two integers in which to hold the coordinates 7892 */ getLocationInSurface(@ize2) int[] location)7893 public void getLocationInSurface(@Size(2) int[] location) { 7894 getLocationInWindow(location); 7895 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 7896 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 7897 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 7898 } 7899 } 7900 7901 /** 7902 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 7903 * only available if the view is attached. 7904 * 7905 * @return WindowInsets from the top of the view hierarchy or null if View is detached 7906 */ getRootWindowInsets()7907 public WindowInsets getRootWindowInsets() { 7908 if (mAttachInfo != null) { 7909 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 7910 } 7911 return null; 7912 } 7913 7914 /** 7915 * @hide Compute the insets that should be consumed by this view and the ones 7916 * that should propagate to those under it. 7917 */ computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets)7918 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 7919 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 7920 || mAttachInfo == null 7921 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 7922 && !mAttachInfo.mOverscanRequested)) { 7923 outLocalInsets.set(inoutInsets); 7924 inoutInsets.set(0, 0, 0, 0); 7925 return true; 7926 } else { 7927 // The application wants to take care of fitting system window for 7928 // the content... however we still need to take care of any overscan here. 7929 final Rect overscan = mAttachInfo.mOverscanInsets; 7930 outLocalInsets.set(overscan); 7931 inoutInsets.left -= overscan.left; 7932 inoutInsets.top -= overscan.top; 7933 inoutInsets.right -= overscan.right; 7934 inoutInsets.bottom -= overscan.bottom; 7935 return false; 7936 } 7937 } 7938 7939 /** 7940 * Compute insets that should be consumed by this view and the ones that should propagate 7941 * to those under it. 7942 * 7943 * @param in Insets currently being processed by this View, likely received as a parameter 7944 * to {@link #onApplyWindowInsets(WindowInsets)}. 7945 * @param outLocalInsets A Rect that will receive the insets that should be consumed 7946 * by this view 7947 * @return Insets that should be passed along to views under this one 7948 */ computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets)7949 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 7950 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 7951 || mAttachInfo == null 7952 || (mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0) { 7953 outLocalInsets.set(in.getSystemWindowInsets()); 7954 return in.consumeSystemWindowInsets(); 7955 } else { 7956 outLocalInsets.set(0, 0, 0, 0); 7957 return in; 7958 } 7959 } 7960 7961 /** 7962 * Sets whether or not this view should account for system screen decorations 7963 * such as the status bar and inset its content; that is, controlling whether 7964 * the default implementation of {@link #fitSystemWindows(Rect)} will be 7965 * executed. See that method for more details. 7966 * 7967 * <p>Note that if you are providing your own implementation of 7968 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 7969 * flag to true -- your implementation will be overriding the default 7970 * implementation that checks this flag. 7971 * 7972 * @param fitSystemWindows If true, then the default implementation of 7973 * {@link #fitSystemWindows(Rect)} will be executed. 7974 * 7975 * @attr ref android.R.styleable#View_fitsSystemWindows 7976 * @see #getFitsSystemWindows() 7977 * @see #fitSystemWindows(Rect) 7978 * @see #setSystemUiVisibility(int) 7979 */ setFitsSystemWindows(boolean fitSystemWindows)7980 public void setFitsSystemWindows(boolean fitSystemWindows) { 7981 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 7982 } 7983 7984 /** 7985 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 7986 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 7987 * will be executed. 7988 * 7989 * @return {@code true} if the default implementation of 7990 * {@link #fitSystemWindows(Rect)} will be executed. 7991 * 7992 * @attr ref android.R.styleable#View_fitsSystemWindows 7993 * @see #setFitsSystemWindows(boolean) 7994 * @see #fitSystemWindows(Rect) 7995 * @see #setSystemUiVisibility(int) 7996 */ 7997 @ViewDebug.ExportedProperty getFitsSystemWindows()7998 public boolean getFitsSystemWindows() { 7999 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 8000 } 8001 8002 /** @hide */ fitsSystemWindows()8003 public boolean fitsSystemWindows() { 8004 return getFitsSystemWindows(); 8005 } 8006 8007 /** 8008 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 8009 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 8010 */ requestFitSystemWindows()8011 public void requestFitSystemWindows() { 8012 if (mParent != null) { 8013 mParent.requestFitSystemWindows(); 8014 } 8015 } 8016 8017 /** 8018 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 8019 */ requestApplyInsets()8020 public void requestApplyInsets() { 8021 requestFitSystemWindows(); 8022 } 8023 8024 /** 8025 * For use by PhoneWindow to make its own system window fitting optional. 8026 * @hide 8027 */ makeOptionalFitsSystemWindows()8028 public void makeOptionalFitsSystemWindows() { 8029 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 8030 } 8031 8032 /** 8033 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 8034 * treat them as such. 8035 * @hide 8036 */ getOutsets(Rect outOutsetRect)8037 public void getOutsets(Rect outOutsetRect) { 8038 if (mAttachInfo != null) { 8039 outOutsetRect.set(mAttachInfo.mOutsets); 8040 } else { 8041 outOutsetRect.setEmpty(); 8042 } 8043 } 8044 8045 /** 8046 * Returns the visibility status for this view. 8047 * 8048 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8049 * @attr ref android.R.styleable#View_visibility 8050 */ 8051 @ViewDebug.ExportedProperty(mapping = { 8052 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 8053 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 8054 @ViewDebug.IntToString(from = GONE, to = "GONE") 8055 }) 8056 @Visibility getVisibility()8057 public int getVisibility() { 8058 return mViewFlags & VISIBILITY_MASK; 8059 } 8060 8061 /** 8062 * Set the visibility state of this view. 8063 * 8064 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 8065 * @attr ref android.R.styleable#View_visibility 8066 */ 8067 @RemotableViewMethod setVisibility(@isibility int visibility)8068 public void setVisibility(@Visibility int visibility) { 8069 setFlags(visibility, VISIBILITY_MASK); 8070 } 8071 8072 /** 8073 * Returns the enabled status for this view. The interpretation of the 8074 * enabled state varies by subclass. 8075 * 8076 * @return True if this view is enabled, false otherwise. 8077 */ 8078 @ViewDebug.ExportedProperty isEnabled()8079 public boolean isEnabled() { 8080 return (mViewFlags & ENABLED_MASK) == ENABLED; 8081 } 8082 8083 /** 8084 * Set the enabled state of this view. The interpretation of the enabled 8085 * state varies by subclass. 8086 * 8087 * @param enabled True if this view is enabled, false otherwise. 8088 */ 8089 @RemotableViewMethod setEnabled(boolean enabled)8090 public void setEnabled(boolean enabled) { 8091 if (enabled == isEnabled()) return; 8092 8093 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 8094 8095 /* 8096 * The View most likely has to change its appearance, so refresh 8097 * the drawable state. 8098 */ 8099 refreshDrawableState(); 8100 8101 // Invalidate too, since the default behavior for views is to be 8102 // be drawn at 50% alpha rather than to change the drawable. 8103 invalidate(true); 8104 8105 if (!enabled) { 8106 cancelPendingInputEvents(); 8107 } 8108 } 8109 8110 /** 8111 * Set whether this view can receive the focus. 8112 * 8113 * Setting this to false will also ensure that this view is not focusable 8114 * in touch mode. 8115 * 8116 * @param focusable If true, this view can receive the focus. 8117 * 8118 * @see #setFocusableInTouchMode(boolean) 8119 * @attr ref android.R.styleable#View_focusable 8120 */ setFocusable(boolean focusable)8121 public void setFocusable(boolean focusable) { 8122 if (!focusable) { 8123 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 8124 } 8125 setFlags(focusable ? FOCUSABLE : NOT_FOCUSABLE, FOCUSABLE_MASK); 8126 } 8127 8128 /** 8129 * Set whether this view can receive focus while in touch mode. 8130 * 8131 * Setting this to true will also ensure that this view is focusable. 8132 * 8133 * @param focusableInTouchMode If true, this view can receive the focus while 8134 * in touch mode. 8135 * 8136 * @see #setFocusable(boolean) 8137 * @attr ref android.R.styleable#View_focusableInTouchMode 8138 */ setFocusableInTouchMode(boolean focusableInTouchMode)8139 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 8140 // Focusable in touch mode should always be set before the focusable flag 8141 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 8142 // which, in touch mode, will not successfully request focus on this view 8143 // because the focusable in touch mode flag is not set 8144 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 8145 if (focusableInTouchMode) { 8146 setFlags(FOCUSABLE, FOCUSABLE_MASK); 8147 } 8148 } 8149 8150 /** 8151 * Set whether this view should have sound effects enabled for events such as 8152 * clicking and touching. 8153 * 8154 * <p>You may wish to disable sound effects for a view if you already play sounds, 8155 * for instance, a dial key that plays dtmf tones. 8156 * 8157 * @param soundEffectsEnabled whether sound effects are enabled for this view. 8158 * @see #isSoundEffectsEnabled() 8159 * @see #playSoundEffect(int) 8160 * @attr ref android.R.styleable#View_soundEffectsEnabled 8161 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)8162 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 8163 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 8164 } 8165 8166 /** 8167 * @return whether this view should have sound effects enabled for events such as 8168 * clicking and touching. 8169 * 8170 * @see #setSoundEffectsEnabled(boolean) 8171 * @see #playSoundEffect(int) 8172 * @attr ref android.R.styleable#View_soundEffectsEnabled 8173 */ 8174 @ViewDebug.ExportedProperty isSoundEffectsEnabled()8175 public boolean isSoundEffectsEnabled() { 8176 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 8177 } 8178 8179 /** 8180 * Set whether this view should have haptic feedback for events such as 8181 * long presses. 8182 * 8183 * <p>You may wish to disable haptic feedback if your view already controls 8184 * its own haptic feedback. 8185 * 8186 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 8187 * @see #isHapticFeedbackEnabled() 8188 * @see #performHapticFeedback(int) 8189 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8190 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)8191 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 8192 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 8193 } 8194 8195 /** 8196 * @return whether this view should have haptic feedback enabled for events 8197 * long presses. 8198 * 8199 * @see #setHapticFeedbackEnabled(boolean) 8200 * @see #performHapticFeedback(int) 8201 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 8202 */ 8203 @ViewDebug.ExportedProperty isHapticFeedbackEnabled()8204 public boolean isHapticFeedbackEnabled() { 8205 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 8206 } 8207 8208 /** 8209 * Returns the layout direction for this view. 8210 * 8211 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 8212 * {@link #LAYOUT_DIRECTION_RTL}, 8213 * {@link #LAYOUT_DIRECTION_INHERIT} or 8214 * {@link #LAYOUT_DIRECTION_LOCALE}. 8215 * 8216 * @attr ref android.R.styleable#View_layoutDirection 8217 * 8218 * @hide 8219 */ 8220 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8221 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 8222 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 8223 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 8224 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 8225 }) 8226 @LayoutDir getRawLayoutDirection()8227 public int getRawLayoutDirection() { 8228 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 8229 } 8230 8231 /** 8232 * Set the layout direction for this view. This will propagate a reset of layout direction 8233 * resolution to the view's children and resolve layout direction for this view. 8234 * 8235 * @param layoutDirection the layout direction to set. Should be one of: 8236 * 8237 * {@link #LAYOUT_DIRECTION_LTR}, 8238 * {@link #LAYOUT_DIRECTION_RTL}, 8239 * {@link #LAYOUT_DIRECTION_INHERIT}, 8240 * {@link #LAYOUT_DIRECTION_LOCALE}. 8241 * 8242 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 8243 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 8244 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 8245 * 8246 * @attr ref android.R.styleable#View_layoutDirection 8247 */ 8248 @RemotableViewMethod setLayoutDirection(@ayoutDir int layoutDirection)8249 public void setLayoutDirection(@LayoutDir int layoutDirection) { 8250 if (getRawLayoutDirection() != layoutDirection) { 8251 // Reset the current layout direction and the resolved one 8252 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 8253 resetRtlProperties(); 8254 // Set the new layout direction (filtered) 8255 mPrivateFlags2 |= 8256 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 8257 // We need to resolve all RTL properties as they all depend on layout direction 8258 resolveRtlPropertiesIfNeeded(); 8259 requestLayout(); 8260 invalidate(true); 8261 } 8262 } 8263 8264 /** 8265 * Returns the resolved layout direction for this view. 8266 * 8267 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 8268 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 8269 * 8270 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 8271 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 8272 * 8273 * @attr ref android.R.styleable#View_layoutDirection 8274 */ 8275 @ViewDebug.ExportedProperty(category = "layout", mapping = { 8276 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 8277 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 8278 }) 8279 @ResolvedLayoutDir getLayoutDirection()8280 public int getLayoutDirection() { 8281 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 8282 if (targetSdkVersion < JELLY_BEAN_MR1) { 8283 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 8284 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 8285 } 8286 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 8287 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 8288 } 8289 8290 /** 8291 * Indicates whether or not this view's layout is right-to-left. This is resolved from 8292 * layout attribute and/or the inherited value from the parent 8293 * 8294 * @return true if the layout is right-to-left. 8295 * 8296 * @hide 8297 */ 8298 @ViewDebug.ExportedProperty(category = "layout") isLayoutRtl()8299 public boolean isLayoutRtl() { 8300 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 8301 } 8302 8303 /** 8304 * Indicates whether the view is currently tracking transient state that the 8305 * app should not need to concern itself with saving and restoring, but that 8306 * the framework should take special note to preserve when possible. 8307 * 8308 * <p>A view with transient state cannot be trivially rebound from an external 8309 * data source, such as an adapter binding item views in a list. This may be 8310 * because the view is performing an animation, tracking user selection 8311 * of content, or similar.</p> 8312 * 8313 * @return true if the view has transient state 8314 */ 8315 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()8316 public boolean hasTransientState() { 8317 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 8318 } 8319 8320 /** 8321 * Set whether this view is currently tracking transient state that the 8322 * framework should attempt to preserve when possible. This flag is reference counted, 8323 * so every call to setHasTransientState(true) should be paired with a later call 8324 * to setHasTransientState(false). 8325 * 8326 * <p>A view with transient state cannot be trivially rebound from an external 8327 * data source, such as an adapter binding item views in a list. This may be 8328 * because the view is performing an animation, tracking user selection 8329 * of content, or similar.</p> 8330 * 8331 * @param hasTransientState true if this view has transient state 8332 */ setHasTransientState(boolean hasTransientState)8333 public void setHasTransientState(boolean hasTransientState) { 8334 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 8335 mTransientStateCount - 1; 8336 if (mTransientStateCount < 0) { 8337 mTransientStateCount = 0; 8338 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 8339 "unmatched pair of setHasTransientState calls"); 8340 } else if ((hasTransientState && mTransientStateCount == 1) || 8341 (!hasTransientState && mTransientStateCount == 0)) { 8342 // update flag if we've just incremented up from 0 or decremented down to 0 8343 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 8344 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 8345 if (mParent != null) { 8346 try { 8347 mParent.childHasTransientStateChanged(this, hasTransientState); 8348 } catch (AbstractMethodError e) { 8349 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 8350 " does not fully implement ViewParent", e); 8351 } 8352 } 8353 } 8354 } 8355 8356 /** 8357 * Returns true if this view is currently attached to a window. 8358 */ isAttachedToWindow()8359 public boolean isAttachedToWindow() { 8360 return mAttachInfo != null; 8361 } 8362 8363 /** 8364 * Returns true if this view has been through at least one layout since it 8365 * was last attached to or detached from a window. 8366 */ isLaidOut()8367 public boolean isLaidOut() { 8368 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 8369 } 8370 8371 /** 8372 * If this view doesn't do any drawing on its own, set this flag to 8373 * allow further optimizations. By default, this flag is not set on 8374 * View, but could be set on some View subclasses such as ViewGroup. 8375 * 8376 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 8377 * you should clear this flag. 8378 * 8379 * @param willNotDraw whether or not this View draw on its own 8380 */ setWillNotDraw(boolean willNotDraw)8381 public void setWillNotDraw(boolean willNotDraw) { 8382 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 8383 } 8384 8385 /** 8386 * Returns whether or not this View draws on its own. 8387 * 8388 * @return true if this view has nothing to draw, false otherwise 8389 */ 8390 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()8391 public boolean willNotDraw() { 8392 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 8393 } 8394 8395 /** 8396 * When a View's drawing cache is enabled, drawing is redirected to an 8397 * offscreen bitmap. Some views, like an ImageView, must be able to 8398 * bypass this mechanism if they already draw a single bitmap, to avoid 8399 * unnecessary usage of the memory. 8400 * 8401 * @param willNotCacheDrawing true if this view does not cache its 8402 * drawing, false otherwise 8403 */ setWillNotCacheDrawing(boolean willNotCacheDrawing)8404 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 8405 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 8406 } 8407 8408 /** 8409 * Returns whether or not this View can cache its drawing or not. 8410 * 8411 * @return true if this view does not cache its drawing, false otherwise 8412 */ 8413 @ViewDebug.ExportedProperty(category = "drawing") willNotCacheDrawing()8414 public boolean willNotCacheDrawing() { 8415 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 8416 } 8417 8418 /** 8419 * Indicates whether this view reacts to click events or not. 8420 * 8421 * @return true if the view is clickable, false otherwise 8422 * 8423 * @see #setClickable(boolean) 8424 * @attr ref android.R.styleable#View_clickable 8425 */ 8426 @ViewDebug.ExportedProperty isClickable()8427 public boolean isClickable() { 8428 return (mViewFlags & CLICKABLE) == CLICKABLE; 8429 } 8430 8431 /** 8432 * Enables or disables click events for this view. When a view 8433 * is clickable it will change its state to "pressed" on every click. 8434 * Subclasses should set the view clickable to visually react to 8435 * user's clicks. 8436 * 8437 * @param clickable true to make the view clickable, false otherwise 8438 * 8439 * @see #isClickable() 8440 * @attr ref android.R.styleable#View_clickable 8441 */ setClickable(boolean clickable)8442 public void setClickable(boolean clickable) { 8443 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 8444 } 8445 8446 /** 8447 * Indicates whether this view reacts to long click events or not. 8448 * 8449 * @return true if the view is long clickable, false otherwise 8450 * 8451 * @see #setLongClickable(boolean) 8452 * @attr ref android.R.styleable#View_longClickable 8453 */ isLongClickable()8454 public boolean isLongClickable() { 8455 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 8456 } 8457 8458 /** 8459 * Enables or disables long click events for this view. When a view is long 8460 * clickable it reacts to the user holding down the button for a longer 8461 * duration than a tap. This event can either launch the listener or a 8462 * context menu. 8463 * 8464 * @param longClickable true to make the view long clickable, false otherwise 8465 * @see #isLongClickable() 8466 * @attr ref android.R.styleable#View_longClickable 8467 */ setLongClickable(boolean longClickable)8468 public void setLongClickable(boolean longClickable) { 8469 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 8470 } 8471 8472 /** 8473 * Indicates whether this view reacts to context clicks or not. 8474 * 8475 * @return true if the view is context clickable, false otherwise 8476 * @see #setContextClickable(boolean) 8477 * @attr ref android.R.styleable#View_contextClickable 8478 */ isContextClickable()8479 public boolean isContextClickable() { 8480 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 8481 } 8482 8483 /** 8484 * Enables or disables context clicking for this view. This event can launch the listener. 8485 * 8486 * @param contextClickable true to make the view react to a context click, false otherwise 8487 * @see #isContextClickable() 8488 * @attr ref android.R.styleable#View_contextClickable 8489 */ setContextClickable(boolean contextClickable)8490 public void setContextClickable(boolean contextClickable) { 8491 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 8492 } 8493 8494 /** 8495 * Sets the pressed state for this view and provides a touch coordinate for 8496 * animation hinting. 8497 * 8498 * @param pressed Pass true to set the View's internal state to "pressed", 8499 * or false to reverts the View's internal state from a 8500 * previously set "pressed" state. 8501 * @param x The x coordinate of the touch that caused the press 8502 * @param y The y coordinate of the touch that caused the press 8503 */ setPressed(boolean pressed, float x, float y)8504 private void setPressed(boolean pressed, float x, float y) { 8505 if (pressed) { 8506 drawableHotspotChanged(x, y); 8507 } 8508 8509 setPressed(pressed); 8510 } 8511 8512 /** 8513 * Sets the pressed state for this view. 8514 * 8515 * @see #isClickable() 8516 * @see #setClickable(boolean) 8517 * 8518 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 8519 * the View's internal state from a previously set "pressed" state. 8520 */ setPressed(boolean pressed)8521 public void setPressed(boolean pressed) { 8522 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 8523 8524 if (pressed) { 8525 mPrivateFlags |= PFLAG_PRESSED; 8526 } else { 8527 mPrivateFlags &= ~PFLAG_PRESSED; 8528 } 8529 8530 if (needsRefresh) { 8531 refreshDrawableState(); 8532 } 8533 dispatchSetPressed(pressed); 8534 } 8535 8536 /** 8537 * Dispatch setPressed to all of this View's children. 8538 * 8539 * @see #setPressed(boolean) 8540 * 8541 * @param pressed The new pressed state 8542 */ dispatchSetPressed(boolean pressed)8543 protected void dispatchSetPressed(boolean pressed) { 8544 } 8545 8546 /** 8547 * Indicates whether the view is currently in pressed state. Unless 8548 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 8549 * the pressed state. 8550 * 8551 * @see #setPressed(boolean) 8552 * @see #isClickable() 8553 * @see #setClickable(boolean) 8554 * 8555 * @return true if the view is currently pressed, false otherwise 8556 */ 8557 @ViewDebug.ExportedProperty isPressed()8558 public boolean isPressed() { 8559 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 8560 } 8561 8562 /** 8563 * @hide 8564 * Indicates whether this view will participate in data collection through 8565 * {@link ViewStructure}. If true, it will not provide any data 8566 * for itself or its children. If false, the normal data collection will be allowed. 8567 * 8568 * @return Returns false if assist data collection is not blocked, else true. 8569 * 8570 * @see #setAssistBlocked(boolean) 8571 * @attr ref android.R.styleable#View_assistBlocked 8572 */ isAssistBlocked()8573 public boolean isAssistBlocked() { 8574 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 8575 } 8576 8577 /** 8578 * @hide 8579 * Controls whether assist data collection from this view and its children is enabled 8580 * (that is, whether {@link #onProvideStructure} and 8581 * {@link #onProvideVirtualStructure} will be called). The default value is false, 8582 * allowing normal assist collection. Setting this to false will disable assist collection. 8583 * 8584 * @param enabled Set to true to <em>disable</em> assist data collection, or false 8585 * (the default) to allow it. 8586 * 8587 * @see #isAssistBlocked() 8588 * @see #onProvideStructure 8589 * @see #onProvideVirtualStructure 8590 * @attr ref android.R.styleable#View_assistBlocked 8591 */ setAssistBlocked(boolean enabled)8592 public void setAssistBlocked(boolean enabled) { 8593 if (enabled) { 8594 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 8595 } else { 8596 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 8597 } 8598 } 8599 8600 /** 8601 * Indicates whether this view will save its state (that is, 8602 * whether its {@link #onSaveInstanceState} method will be called). 8603 * 8604 * @return Returns true if the view state saving is enabled, else false. 8605 * 8606 * @see #setSaveEnabled(boolean) 8607 * @attr ref android.R.styleable#View_saveEnabled 8608 */ isSaveEnabled()8609 public boolean isSaveEnabled() { 8610 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 8611 } 8612 8613 /** 8614 * Controls whether the saving of this view's state is 8615 * enabled (that is, whether its {@link #onSaveInstanceState} method 8616 * will be called). Note that even if freezing is enabled, the 8617 * view still must have an id assigned to it (via {@link #setId(int)}) 8618 * for its state to be saved. This flag can only disable the 8619 * saving of this view; any child views may still have their state saved. 8620 * 8621 * @param enabled Set to false to <em>disable</em> state saving, or true 8622 * (the default) to allow it. 8623 * 8624 * @see #isSaveEnabled() 8625 * @see #setId(int) 8626 * @see #onSaveInstanceState() 8627 * @attr ref android.R.styleable#View_saveEnabled 8628 */ setSaveEnabled(boolean enabled)8629 public void setSaveEnabled(boolean enabled) { 8630 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 8631 } 8632 8633 /** 8634 * Gets whether the framework should discard touches when the view's 8635 * window is obscured by another visible window. 8636 * Refer to the {@link View} security documentation for more details. 8637 * 8638 * @return True if touch filtering is enabled. 8639 * 8640 * @see #setFilterTouchesWhenObscured(boolean) 8641 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 8642 */ 8643 @ViewDebug.ExportedProperty getFilterTouchesWhenObscured()8644 public boolean getFilterTouchesWhenObscured() { 8645 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 8646 } 8647 8648 /** 8649 * Sets whether the framework should discard touches when the view's 8650 * window is obscured by another visible window. 8651 * Refer to the {@link View} security documentation for more details. 8652 * 8653 * @param enabled True if touch filtering should be enabled. 8654 * 8655 * @see #getFilterTouchesWhenObscured 8656 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 8657 */ setFilterTouchesWhenObscured(boolean enabled)8658 public void setFilterTouchesWhenObscured(boolean enabled) { 8659 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 8660 FILTER_TOUCHES_WHEN_OBSCURED); 8661 } 8662 8663 /** 8664 * Indicates whether the entire hierarchy under this view will save its 8665 * state when a state saving traversal occurs from its parent. The default 8666 * is true; if false, these views will not be saved unless 8667 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 8668 * 8669 * @return Returns true if the view state saving from parent is enabled, else false. 8670 * 8671 * @see #setSaveFromParentEnabled(boolean) 8672 */ isSaveFromParentEnabled()8673 public boolean isSaveFromParentEnabled() { 8674 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 8675 } 8676 8677 /** 8678 * Controls whether the entire hierarchy under this view will save its 8679 * state when a state saving traversal occurs from its parent. The default 8680 * is true; if false, these views will not be saved unless 8681 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 8682 * 8683 * @param enabled Set to false to <em>disable</em> state saving, or true 8684 * (the default) to allow it. 8685 * 8686 * @see #isSaveFromParentEnabled() 8687 * @see #setId(int) 8688 * @see #onSaveInstanceState() 8689 */ setSaveFromParentEnabled(boolean enabled)8690 public void setSaveFromParentEnabled(boolean enabled) { 8691 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 8692 } 8693 8694 8695 /** 8696 * Returns whether this View is able to take focus. 8697 * 8698 * @return True if this view can take focus, or false otherwise. 8699 * @attr ref android.R.styleable#View_focusable 8700 */ 8701 @ViewDebug.ExportedProperty(category = "focus") isFocusable()8702 public final boolean isFocusable() { 8703 return FOCUSABLE == (mViewFlags & FOCUSABLE_MASK); 8704 } 8705 8706 /** 8707 * When a view is focusable, it may not want to take focus when in touch mode. 8708 * For example, a button would like focus when the user is navigating via a D-pad 8709 * so that the user can click on it, but once the user starts touching the screen, 8710 * the button shouldn't take focus 8711 * @return Whether the view is focusable in touch mode. 8712 * @attr ref android.R.styleable#View_focusableInTouchMode 8713 */ 8714 @ViewDebug.ExportedProperty isFocusableInTouchMode()8715 public final boolean isFocusableInTouchMode() { 8716 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 8717 } 8718 8719 /** 8720 * Find the nearest view in the specified direction that can take focus. 8721 * This does not actually give focus to that view. 8722 * 8723 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 8724 * 8725 * @return The nearest focusable in the specified direction, or null if none 8726 * can be found. 8727 */ focusSearch(@ocusRealDirection int direction)8728 public View focusSearch(@FocusRealDirection int direction) { 8729 if (mParent != null) { 8730 return mParent.focusSearch(this, direction); 8731 } else { 8732 return null; 8733 } 8734 } 8735 8736 /** 8737 * This method is the last chance for the focused view and its ancestors to 8738 * respond to an arrow key. This is called when the focused view did not 8739 * consume the key internally, nor could the view system find a new view in 8740 * the requested direction to give focus to. 8741 * 8742 * @param focused The currently focused view. 8743 * @param direction The direction focus wants to move. One of FOCUS_UP, 8744 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 8745 * @return True if the this view consumed this unhandled move. 8746 */ dispatchUnhandledMove(View focused, @FocusRealDirection int direction)8747 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 8748 return false; 8749 } 8750 8751 /** 8752 * If a user manually specified the next view id for a particular direction, 8753 * use the root to look up the view. 8754 * @param root The root view of the hierarchy containing this view. 8755 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 8756 * or FOCUS_BACKWARD. 8757 * @return The user specified next view, or null if there is none. 8758 */ findUserSetNextFocus(View root, @FocusDirection int direction)8759 View findUserSetNextFocus(View root, @FocusDirection int direction) { 8760 switch (direction) { 8761 case FOCUS_LEFT: 8762 if (mNextFocusLeftId == View.NO_ID) return null; 8763 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 8764 case FOCUS_RIGHT: 8765 if (mNextFocusRightId == View.NO_ID) return null; 8766 return findViewInsideOutShouldExist(root, mNextFocusRightId); 8767 case FOCUS_UP: 8768 if (mNextFocusUpId == View.NO_ID) return null; 8769 return findViewInsideOutShouldExist(root, mNextFocusUpId); 8770 case FOCUS_DOWN: 8771 if (mNextFocusDownId == View.NO_ID) return null; 8772 return findViewInsideOutShouldExist(root, mNextFocusDownId); 8773 case FOCUS_FORWARD: 8774 if (mNextFocusForwardId == View.NO_ID) return null; 8775 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 8776 case FOCUS_BACKWARD: { 8777 if (mID == View.NO_ID) return null; 8778 final int id = mID; 8779 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 8780 @Override 8781 public boolean apply(View t) { 8782 return t.mNextFocusForwardId == id; 8783 } 8784 }); 8785 } 8786 } 8787 return null; 8788 } 8789 findViewInsideOutShouldExist(View root, int id)8790 private View findViewInsideOutShouldExist(View root, int id) { 8791 if (mMatchIdPredicate == null) { 8792 mMatchIdPredicate = new MatchIdPredicate(); 8793 } 8794 mMatchIdPredicate.mId = id; 8795 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 8796 if (result == null) { 8797 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 8798 } 8799 return result; 8800 } 8801 8802 /** 8803 * Find and return all focusable views that are descendants of this view, 8804 * possibly including this view if it is focusable itself. 8805 * 8806 * @param direction The direction of the focus 8807 * @return A list of focusable views 8808 */ getFocusables(@ocusDirection int direction)8809 public ArrayList<View> getFocusables(@FocusDirection int direction) { 8810 ArrayList<View> result = new ArrayList<View>(24); 8811 addFocusables(result, direction); 8812 return result; 8813 } 8814 8815 /** 8816 * Add any focusable views that are descendants of this view (possibly 8817 * including this view if it is focusable itself) to views. If we are in touch mode, 8818 * only add views that are also focusable in touch mode. 8819 * 8820 * @param views Focusable views found so far 8821 * @param direction The direction of the focus 8822 */ addFocusables(ArrayList<View> views, @FocusDirection int direction)8823 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 8824 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 8825 } 8826 8827 /** 8828 * Adds any focusable views that are descendants of this view (possibly 8829 * including this view if it is focusable itself) to views. This method 8830 * adds all focusable views regardless if we are in touch mode or 8831 * only views focusable in touch mode if we are in touch mode or 8832 * only views that can take accessibility focus if accessibility is enabled 8833 * depending on the focusable mode parameter. 8834 * 8835 * @param views Focusable views found so far or null if all we are interested is 8836 * the number of focusables. 8837 * @param direction The direction of the focus. 8838 * @param focusableMode The type of focusables to be added. 8839 * 8840 * @see #FOCUSABLES_ALL 8841 * @see #FOCUSABLES_TOUCH_MODE 8842 */ addFocusables(ArrayList<View> views, @FocusDirection int direction, @FocusableMode int focusableMode)8843 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 8844 @FocusableMode int focusableMode) { 8845 if (views == null) { 8846 return; 8847 } 8848 if (!isFocusable()) { 8849 return; 8850 } 8851 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 8852 && !isFocusableInTouchMode()) { 8853 return; 8854 } 8855 views.add(this); 8856 } 8857 8858 /** 8859 * Finds the Views that contain given text. The containment is case insensitive. 8860 * The search is performed by either the text that the View renders or the content 8861 * description that describes the view for accessibility purposes and the view does 8862 * not render or both. Clients can specify how the search is to be performed via 8863 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 8864 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 8865 * 8866 * @param outViews The output list of matching Views. 8867 * @param searched The text to match against. 8868 * 8869 * @see #FIND_VIEWS_WITH_TEXT 8870 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 8871 * @see #setContentDescription(CharSequence) 8872 */ findViewsWithText(ArrayList<View> outViews, CharSequence searched, @FindViewFlags int flags)8873 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 8874 @FindViewFlags int flags) { 8875 if (getAccessibilityNodeProvider() != null) { 8876 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 8877 outViews.add(this); 8878 } 8879 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 8880 && (searched != null && searched.length() > 0) 8881 && (mContentDescription != null && mContentDescription.length() > 0)) { 8882 String searchedLowerCase = searched.toString().toLowerCase(); 8883 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 8884 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 8885 outViews.add(this); 8886 } 8887 } 8888 } 8889 8890 /** 8891 * Find and return all touchable views that are descendants of this view, 8892 * possibly including this view if it is touchable itself. 8893 * 8894 * @return A list of touchable views 8895 */ getTouchables()8896 public ArrayList<View> getTouchables() { 8897 ArrayList<View> result = new ArrayList<View>(); 8898 addTouchables(result); 8899 return result; 8900 } 8901 8902 /** 8903 * Add any touchable views that are descendants of this view (possibly 8904 * including this view if it is touchable itself) to views. 8905 * 8906 * @param views Touchable views found so far 8907 */ addTouchables(ArrayList<View> views)8908 public void addTouchables(ArrayList<View> views) { 8909 final int viewFlags = mViewFlags; 8910 8911 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 8912 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 8913 && (viewFlags & ENABLED_MASK) == ENABLED) { 8914 views.add(this); 8915 } 8916 } 8917 8918 /** 8919 * Returns whether this View is accessibility focused. 8920 * 8921 * @return True if this View is accessibility focused. 8922 */ isAccessibilityFocused()8923 public boolean isAccessibilityFocused() { 8924 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 8925 } 8926 8927 /** 8928 * Call this to try to give accessibility focus to this view. 8929 * 8930 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 8931 * returns false or the view is no visible or the view already has accessibility 8932 * focus. 8933 * 8934 * See also {@link #focusSearch(int)}, which is what you call to say that you 8935 * have focus, and you want your parent to look for the next one. 8936 * 8937 * @return Whether this view actually took accessibility focus. 8938 * 8939 * @hide 8940 */ requestAccessibilityFocus()8941 public boolean requestAccessibilityFocus() { 8942 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 8943 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 8944 return false; 8945 } 8946 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 8947 return false; 8948 } 8949 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 8950 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 8951 ViewRootImpl viewRootImpl = getViewRootImpl(); 8952 if (viewRootImpl != null) { 8953 viewRootImpl.setAccessibilityFocus(this, null); 8954 } 8955 invalidate(); 8956 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 8957 return true; 8958 } 8959 return false; 8960 } 8961 8962 /** 8963 * Call this to try to clear accessibility focus of this view. 8964 * 8965 * See also {@link #focusSearch(int)}, which is what you call to say that you 8966 * have focus, and you want your parent to look for the next one. 8967 * 8968 * @hide 8969 */ clearAccessibilityFocus()8970 public void clearAccessibilityFocus() { 8971 clearAccessibilityFocusNoCallbacks(0); 8972 8973 // Clear the global reference of accessibility focus if this view or 8974 // any of its descendants had accessibility focus. This will NOT send 8975 // an event or update internal state if focus is cleared from a 8976 // descendant view, which may leave views in inconsistent states. 8977 final ViewRootImpl viewRootImpl = getViewRootImpl(); 8978 if (viewRootImpl != null) { 8979 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 8980 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 8981 viewRootImpl.setAccessibilityFocus(null, null); 8982 } 8983 } 8984 } 8985 sendAccessibilityHoverEvent(int eventType)8986 private void sendAccessibilityHoverEvent(int eventType) { 8987 // Since we are not delivering to a client accessibility events from not 8988 // important views (unless the clinet request that) we need to fire the 8989 // event from the deepest view exposed to the client. As a consequence if 8990 // the user crosses a not exposed view the client will see enter and exit 8991 // of the exposed predecessor followed by and enter and exit of that same 8992 // predecessor when entering and exiting the not exposed descendant. This 8993 // is fine since the client has a clear idea which view is hovered at the 8994 // price of a couple more events being sent. This is a simple and 8995 // working solution. 8996 View source = this; 8997 while (true) { 8998 if (source.includeForAccessibility()) { 8999 source.sendAccessibilityEvent(eventType); 9000 return; 9001 } 9002 ViewParent parent = source.getParent(); 9003 if (parent instanceof View) { 9004 source = (View) parent; 9005 } else { 9006 return; 9007 } 9008 } 9009 } 9010 9011 /** 9012 * Clears accessibility focus without calling any callback methods 9013 * normally invoked in {@link #clearAccessibilityFocus()}. This method 9014 * is used separately from that one for clearing accessibility focus when 9015 * giving this focus to another view. 9016 * 9017 * @param action The action, if any, that led to focus being cleared. Set to 9018 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 9019 * the window. 9020 */ clearAccessibilityFocusNoCallbacks(int action)9021 void clearAccessibilityFocusNoCallbacks(int action) { 9022 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 9023 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 9024 invalidate(); 9025 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9026 AccessibilityEvent event = AccessibilityEvent.obtain( 9027 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 9028 event.setAction(action); 9029 if (mAccessibilityDelegate != null) { 9030 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9031 } else { 9032 sendAccessibilityEventUnchecked(event); 9033 } 9034 } 9035 } 9036 } 9037 9038 /** 9039 * Call this to try to give focus to a specific view or to one of its 9040 * descendants. 9041 * 9042 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9043 * false), or if it is focusable and it is not focusable in touch mode 9044 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9045 * 9046 * See also {@link #focusSearch(int)}, which is what you call to say that you 9047 * have focus, and you want your parent to look for the next one. 9048 * 9049 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 9050 * {@link #FOCUS_DOWN} and <code>null</code>. 9051 * 9052 * @return Whether this view or one of its descendants actually took focus. 9053 */ requestFocus()9054 public final boolean requestFocus() { 9055 return requestFocus(View.FOCUS_DOWN); 9056 } 9057 9058 /** 9059 * Call this to try to give focus to a specific view or to one of its 9060 * descendants and give it a hint about what direction focus is heading. 9061 * 9062 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9063 * false), or if it is focusable and it is not focusable in touch mode 9064 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9065 * 9066 * See also {@link #focusSearch(int)}, which is what you call to say that you 9067 * have focus, and you want your parent to look for the next one. 9068 * 9069 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 9070 * <code>null</code> set for the previously focused rectangle. 9071 * 9072 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9073 * @return Whether this view or one of its descendants actually took focus. 9074 */ requestFocus(int direction)9075 public final boolean requestFocus(int direction) { 9076 return requestFocus(direction, null); 9077 } 9078 9079 /** 9080 * Call this to try to give focus to a specific view or to one of its descendants 9081 * and give it hints about the direction and a specific rectangle that the focus 9082 * is coming from. The rectangle can help give larger views a finer grained hint 9083 * about where focus is coming from, and therefore, where to show selection, or 9084 * forward focus change internally. 9085 * 9086 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 9087 * false), or if it is focusable and it is not focusable in touch mode 9088 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 9089 * 9090 * A View will not take focus if it is not visible. 9091 * 9092 * A View will not take focus if one of its parents has 9093 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 9094 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 9095 * 9096 * See also {@link #focusSearch(int)}, which is what you call to say that you 9097 * have focus, and you want your parent to look for the next one. 9098 * 9099 * You may wish to override this method if your custom {@link View} has an internal 9100 * {@link View} that it wishes to forward the request to. 9101 * 9102 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 9103 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 9104 * to give a finer grained hint about where focus is coming from. May be null 9105 * if there is no hint. 9106 * @return Whether this view or one of its descendants actually took focus. 9107 */ requestFocus(int direction, Rect previouslyFocusedRect)9108 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 9109 return requestFocusNoSearch(direction, previouslyFocusedRect); 9110 } 9111 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)9112 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 9113 // need to be focusable 9114 if ((mViewFlags & FOCUSABLE_MASK) != FOCUSABLE || 9115 (mViewFlags & VISIBILITY_MASK) != VISIBLE) { 9116 return false; 9117 } 9118 9119 // need to be focusable in touch mode if in touch mode 9120 if (isInTouchMode() && 9121 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 9122 return false; 9123 } 9124 9125 // need to not have any parents blocking us 9126 if (hasAncestorThatBlocksDescendantFocus()) { 9127 return false; 9128 } 9129 9130 handleFocusGainInternal(direction, previouslyFocusedRect); 9131 return true; 9132 } 9133 9134 /** 9135 * Call this to try to give focus to a specific view or to one of its descendants. This is a 9136 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 9137 * touch mode to request focus when they are touched. 9138 * 9139 * @return Whether this view or one of its descendants actually took focus. 9140 * 9141 * @see #isInTouchMode() 9142 * 9143 */ requestFocusFromTouch()9144 public final boolean requestFocusFromTouch() { 9145 // Leave touch mode if we need to 9146 if (isInTouchMode()) { 9147 ViewRootImpl viewRoot = getViewRootImpl(); 9148 if (viewRoot != null) { 9149 viewRoot.ensureTouchMode(false); 9150 } 9151 } 9152 return requestFocus(View.FOCUS_DOWN); 9153 } 9154 9155 /** 9156 * @return Whether any ancestor of this view blocks descendant focus. 9157 */ hasAncestorThatBlocksDescendantFocus()9158 private boolean hasAncestorThatBlocksDescendantFocus() { 9159 final boolean focusableInTouchMode = isFocusableInTouchMode(); 9160 ViewParent ancestor = mParent; 9161 while (ancestor instanceof ViewGroup) { 9162 final ViewGroup vgAncestor = (ViewGroup) ancestor; 9163 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 9164 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 9165 return true; 9166 } else { 9167 ancestor = vgAncestor.getParent(); 9168 } 9169 } 9170 return false; 9171 } 9172 9173 /** 9174 * Gets the mode for determining whether this View is important for accessibility 9175 * which is if it fires accessibility events and if it is reported to 9176 * accessibility services that query the screen. 9177 * 9178 * @return The mode for determining whether a View is important for accessibility. 9179 * 9180 * @attr ref android.R.styleable#View_importantForAccessibility 9181 * 9182 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9183 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9184 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9185 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9186 */ 9187 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 9188 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 9189 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 9190 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 9191 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 9192 to = "noHideDescendants") 9193 }) getImportantForAccessibility()9194 public int getImportantForAccessibility() { 9195 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9196 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9197 } 9198 9199 /** 9200 * Sets the live region mode for this view. This indicates to accessibility 9201 * services whether they should automatically notify the user about changes 9202 * to the view's content description or text, or to the content descriptions 9203 * or text of the view's children (where applicable). 9204 * <p> 9205 * For example, in a login screen with a TextView that displays an "incorrect 9206 * password" notification, that view should be marked as a live region with 9207 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9208 * <p> 9209 * To disable change notifications for this view, use 9210 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 9211 * mode for most views. 9212 * <p> 9213 * To indicate that the user should be notified of changes, use 9214 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 9215 * <p> 9216 * If the view's changes should interrupt ongoing speech and notify the user 9217 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 9218 * 9219 * @param mode The live region mode for this view, one of: 9220 * <ul> 9221 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 9222 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 9223 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 9224 * </ul> 9225 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9226 */ setAccessibilityLiveRegion(int mode)9227 public void setAccessibilityLiveRegion(int mode) { 9228 if (mode != getAccessibilityLiveRegion()) { 9229 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9230 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 9231 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 9232 notifyViewAccessibilityStateChangedIfNeeded( 9233 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9234 } 9235 } 9236 9237 /** 9238 * Gets the live region mode for this View. 9239 * 9240 * @return The live region mode for the view. 9241 * 9242 * @attr ref android.R.styleable#View_accessibilityLiveRegion 9243 * 9244 * @see #setAccessibilityLiveRegion(int) 9245 */ getAccessibilityLiveRegion()9246 public int getAccessibilityLiveRegion() { 9247 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 9248 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 9249 } 9250 9251 /** 9252 * Sets how to determine whether this view is important for accessibility 9253 * which is if it fires accessibility events and if it is reported to 9254 * accessibility services that query the screen. 9255 * 9256 * @param mode How to determine whether this view is important for accessibility. 9257 * 9258 * @attr ref android.R.styleable#View_importantForAccessibility 9259 * 9260 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 9261 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 9262 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 9263 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 9264 */ setImportantForAccessibility(int mode)9265 public void setImportantForAccessibility(int mode) { 9266 final int oldMode = getImportantForAccessibility(); 9267 if (mode != oldMode) { 9268 final boolean hideDescendants = 9269 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 9270 9271 // If this node or its descendants are no longer important, try to 9272 // clear accessibility focus. 9273 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 9274 final View focusHost = findAccessibilityFocusHost(hideDescendants); 9275 if (focusHost != null) { 9276 focusHost.clearAccessibilityFocus(); 9277 } 9278 } 9279 9280 // If we're moving between AUTO and another state, we might not need 9281 // to send a subtree changed notification. We'll store the computed 9282 // importance, since we'll need to check it later to make sure. 9283 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 9284 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 9285 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 9286 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9287 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 9288 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 9289 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 9290 notifySubtreeAccessibilityStateChangedIfNeeded(); 9291 } else { 9292 notifyViewAccessibilityStateChangedIfNeeded( 9293 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9294 } 9295 } 9296 } 9297 9298 /** 9299 * Returns the view within this view's hierarchy that is hosting 9300 * accessibility focus. 9301 * 9302 * @param searchDescendants whether to search for focus in descendant views 9303 * @return the view hosting accessibility focus, or {@code null} 9304 */ findAccessibilityFocusHost(boolean searchDescendants)9305 private View findAccessibilityFocusHost(boolean searchDescendants) { 9306 if (isAccessibilityFocusedViewOrHost()) { 9307 return this; 9308 } 9309 9310 if (searchDescendants) { 9311 final ViewRootImpl viewRoot = getViewRootImpl(); 9312 if (viewRoot != null) { 9313 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 9314 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 9315 return focusHost; 9316 } 9317 } 9318 } 9319 9320 return null; 9321 } 9322 9323 /** 9324 * Computes whether this view should be exposed for accessibility. In 9325 * general, views that are interactive or provide information are exposed 9326 * while views that serve only as containers are hidden. 9327 * <p> 9328 * If an ancestor of this view has importance 9329 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 9330 * returns <code>false</code>. 9331 * <p> 9332 * Otherwise, the value is computed according to the view's 9333 * {@link #getImportantForAccessibility()} value: 9334 * <ol> 9335 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 9336 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 9337 * </code> 9338 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 9339 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 9340 * view satisfies any of the following: 9341 * <ul> 9342 * <li>Is actionable, e.g. {@link #isClickable()}, 9343 * {@link #isLongClickable()}, or {@link #isFocusable()} 9344 * <li>Has an {@link AccessibilityDelegate} 9345 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 9346 * {@link OnKeyListener}, etc. 9347 * <li>Is an accessibility live region, e.g. 9348 * {@link #getAccessibilityLiveRegion()} is not 9349 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 9350 * </ul> 9351 * </ol> 9352 * 9353 * @return Whether the view is exposed for accessibility. 9354 * @see #setImportantForAccessibility(int) 9355 * @see #getImportantForAccessibility() 9356 */ isImportantForAccessibility()9357 public boolean isImportantForAccessibility() { 9358 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 9359 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 9360 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 9361 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9362 return false; 9363 } 9364 9365 // Check parent mode to ensure we're not hidden. 9366 ViewParent parent = mParent; 9367 while (parent instanceof View) { 9368 if (((View) parent).getImportantForAccessibility() 9369 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 9370 return false; 9371 } 9372 parent = parent.getParent(); 9373 } 9374 9375 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 9376 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 9377 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE; 9378 } 9379 9380 /** 9381 * Gets the parent for accessibility purposes. Note that the parent for 9382 * accessibility is not necessary the immediate parent. It is the first 9383 * predecessor that is important for accessibility. 9384 * 9385 * @return The parent for accessibility purposes. 9386 */ getParentForAccessibility()9387 public ViewParent getParentForAccessibility() { 9388 if (mParent instanceof View) { 9389 View parentView = (View) mParent; 9390 if (parentView.includeForAccessibility()) { 9391 return mParent; 9392 } else { 9393 return mParent.getParentForAccessibility(); 9394 } 9395 } 9396 return null; 9397 } 9398 9399 /** 9400 * Adds the children of this View relevant for accessibility to the given list 9401 * as output. Since some Views are not important for accessibility the added 9402 * child views are not necessarily direct children of this view, rather they are 9403 * the first level of descendants important for accessibility. 9404 * 9405 * @param outChildren The output list that will receive children for accessibility. 9406 */ addChildrenForAccessibility(ArrayList<View> outChildren)9407 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 9408 9409 } 9410 9411 /** 9412 * Whether to regard this view for accessibility. A view is regarded for 9413 * accessibility if it is important for accessibility or the querying 9414 * accessibility service has explicitly requested that view not 9415 * important for accessibility are regarded. 9416 * 9417 * @return Whether to regard the view for accessibility. 9418 * 9419 * @hide 9420 */ includeForAccessibility()9421 public boolean includeForAccessibility() { 9422 if (mAttachInfo != null) { 9423 return (mAttachInfo.mAccessibilityFetchFlags 9424 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 9425 || isImportantForAccessibility(); 9426 } 9427 return false; 9428 } 9429 9430 /** 9431 * Returns whether the View is considered actionable from 9432 * accessibility perspective. Such view are important for 9433 * accessibility. 9434 * 9435 * @return True if the view is actionable for accessibility. 9436 * 9437 * @hide 9438 */ isActionableForAccessibility()9439 public boolean isActionableForAccessibility() { 9440 return (isClickable() || isLongClickable() || isFocusable()); 9441 } 9442 9443 /** 9444 * Returns whether the View has registered callbacks which makes it 9445 * important for accessibility. 9446 * 9447 * @return True if the view is actionable for accessibility. 9448 */ hasListenersForAccessibility()9449 private boolean hasListenersForAccessibility() { 9450 ListenerInfo info = getListenerInfo(); 9451 return mTouchDelegate != null || info.mOnKeyListener != null 9452 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 9453 || info.mOnHoverListener != null || info.mOnDragListener != null; 9454 } 9455 9456 /** 9457 * Notifies that the accessibility state of this view changed. The change 9458 * is local to this view and does not represent structural changes such 9459 * as children and parent. For example, the view became focusable. The 9460 * notification is at at most once every 9461 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 9462 * to avoid unnecessary load to the system. Also once a view has a pending 9463 * notification this method is a NOP until the notification has been sent. 9464 * 9465 * @hide 9466 */ notifyViewAccessibilityStateChangedIfNeeded(int changeType)9467 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 9468 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 9469 return; 9470 } 9471 if (mSendViewStateChangedAccessibilityEvent == null) { 9472 mSendViewStateChangedAccessibilityEvent = 9473 new SendViewStateChangedAccessibilityEvent(); 9474 } 9475 mSendViewStateChangedAccessibilityEvent.runOrPost(changeType); 9476 } 9477 9478 /** 9479 * Notifies that the accessibility state of this view changed. The change 9480 * is *not* local to this view and does represent structural changes such 9481 * as children and parent. For example, the view size changed. The 9482 * notification is at at most once every 9483 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 9484 * to avoid unnecessary load to the system. Also once a view has a pending 9485 * notification this method is a NOP until the notification has been sent. 9486 * 9487 * @hide 9488 */ notifySubtreeAccessibilityStateChangedIfNeeded()9489 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 9490 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 9491 return; 9492 } 9493 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 9494 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 9495 if (mParent != null) { 9496 try { 9497 mParent.notifySubtreeAccessibilityStateChanged( 9498 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 9499 } catch (AbstractMethodError e) { 9500 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 9501 " does not fully implement ViewParent", e); 9502 } 9503 } 9504 } 9505 } 9506 9507 /** 9508 * Change the visibility of the View without triggering any other changes. This is 9509 * important for transitions, where visibility changes should not adjust focus or 9510 * trigger a new layout. This is only used when the visibility has already been changed 9511 * and we need a transient value during an animation. When the animation completes, 9512 * the original visibility value is always restored. 9513 * 9514 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 9515 * @hide 9516 */ setTransitionVisibility(@isibility int visibility)9517 public void setTransitionVisibility(@Visibility int visibility) { 9518 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 9519 } 9520 9521 /** 9522 * Reset the flag indicating the accessibility state of the subtree rooted 9523 * at this view changed. 9524 */ resetSubtreeAccessibilityStateChanged()9525 void resetSubtreeAccessibilityStateChanged() { 9526 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 9527 } 9528 9529 /** 9530 * Report an accessibility action to this view's parents for delegated processing. 9531 * 9532 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 9533 * call this method to delegate an accessibility action to a supporting parent. If the parent 9534 * returns true from its 9535 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 9536 * method this method will return true to signify that the action was consumed.</p> 9537 * 9538 * <p>This method is useful for implementing nested scrolling child views. If 9539 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 9540 * a custom view implementation may invoke this method to allow a parent to consume the 9541 * scroll first. If this method returns true the custom view should skip its own scrolling 9542 * behavior.</p> 9543 * 9544 * @param action Accessibility action to delegate 9545 * @param arguments Optional action arguments 9546 * @return true if the action was consumed by a parent 9547 */ dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments)9548 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 9549 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 9550 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 9551 return true; 9552 } 9553 } 9554 return false; 9555 } 9556 9557 /** 9558 * Performs the specified accessibility action on the view. For 9559 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 9560 * <p> 9561 * If an {@link AccessibilityDelegate} has been specified via calling 9562 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9563 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 9564 * is responsible for handling this call. 9565 * </p> 9566 * 9567 * <p>The default implementation will delegate 9568 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 9569 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 9570 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 9571 * 9572 * @param action The action to perform. 9573 * @param arguments Optional action arguments. 9574 * @return Whether the action was performed. 9575 */ performAccessibilityAction(int action, Bundle arguments)9576 public boolean performAccessibilityAction(int action, Bundle arguments) { 9577 if (mAccessibilityDelegate != null) { 9578 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 9579 } else { 9580 return performAccessibilityActionInternal(action, arguments); 9581 } 9582 } 9583 9584 /** 9585 * @see #performAccessibilityAction(int, Bundle) 9586 * 9587 * Note: Called from the default {@link AccessibilityDelegate}. 9588 * 9589 * @hide 9590 */ performAccessibilityActionInternal(int action, Bundle arguments)9591 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 9592 if (isNestedScrollingEnabled() 9593 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 9594 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 9595 || action == R.id.accessibilityActionScrollUp 9596 || action == R.id.accessibilityActionScrollLeft 9597 || action == R.id.accessibilityActionScrollDown 9598 || action == R.id.accessibilityActionScrollRight)) { 9599 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 9600 return true; 9601 } 9602 } 9603 9604 switch (action) { 9605 case AccessibilityNodeInfo.ACTION_CLICK: { 9606 if (isClickable()) { 9607 performClick(); 9608 return true; 9609 } 9610 } break; 9611 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 9612 if (isLongClickable()) { 9613 performLongClick(); 9614 return true; 9615 } 9616 } break; 9617 case AccessibilityNodeInfo.ACTION_FOCUS: { 9618 if (!hasFocus()) { 9619 // Get out of touch mode since accessibility 9620 // wants to move focus around. 9621 getViewRootImpl().ensureTouchMode(false); 9622 return requestFocus(); 9623 } 9624 } break; 9625 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 9626 if (hasFocus()) { 9627 clearFocus(); 9628 return !isFocused(); 9629 } 9630 } break; 9631 case AccessibilityNodeInfo.ACTION_SELECT: { 9632 if (!isSelected()) { 9633 setSelected(true); 9634 return isSelected(); 9635 } 9636 } break; 9637 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 9638 if (isSelected()) { 9639 setSelected(false); 9640 return !isSelected(); 9641 } 9642 } break; 9643 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 9644 if (!isAccessibilityFocused()) { 9645 return requestAccessibilityFocus(); 9646 } 9647 } break; 9648 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 9649 if (isAccessibilityFocused()) { 9650 clearAccessibilityFocus(); 9651 return true; 9652 } 9653 } break; 9654 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 9655 if (arguments != null) { 9656 final int granularity = arguments.getInt( 9657 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 9658 final boolean extendSelection = arguments.getBoolean( 9659 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 9660 return traverseAtGranularity(granularity, true, extendSelection); 9661 } 9662 } break; 9663 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 9664 if (arguments != null) { 9665 final int granularity = arguments.getInt( 9666 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 9667 final boolean extendSelection = arguments.getBoolean( 9668 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 9669 return traverseAtGranularity(granularity, false, extendSelection); 9670 } 9671 } break; 9672 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 9673 CharSequence text = getIterableTextForAccessibility(); 9674 if (text == null) { 9675 return false; 9676 } 9677 final int start = (arguments != null) ? arguments.getInt( 9678 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 9679 final int end = (arguments != null) ? arguments.getInt( 9680 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 9681 // Only cursor position can be specified (selection length == 0) 9682 if ((getAccessibilitySelectionStart() != start 9683 || getAccessibilitySelectionEnd() != end) 9684 && (start == end)) { 9685 setAccessibilitySelection(start, end); 9686 notifyViewAccessibilityStateChangedIfNeeded( 9687 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9688 return true; 9689 } 9690 } break; 9691 case R.id.accessibilityActionShowOnScreen: { 9692 if (mAttachInfo != null) { 9693 final Rect r = mAttachInfo.mTmpInvalRect; 9694 getDrawingRect(r); 9695 return requestRectangleOnScreen(r, true); 9696 } 9697 } break; 9698 case R.id.accessibilityActionContextClick: { 9699 if (isContextClickable()) { 9700 performContextClick(); 9701 return true; 9702 } 9703 } break; 9704 } 9705 return false; 9706 } 9707 traverseAtGranularity(int granularity, boolean forward, boolean extendSelection)9708 private boolean traverseAtGranularity(int granularity, boolean forward, 9709 boolean extendSelection) { 9710 CharSequence text = getIterableTextForAccessibility(); 9711 if (text == null || text.length() == 0) { 9712 return false; 9713 } 9714 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 9715 if (iterator == null) { 9716 return false; 9717 } 9718 int current = getAccessibilitySelectionEnd(); 9719 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 9720 current = forward ? 0 : text.length(); 9721 } 9722 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 9723 if (range == null) { 9724 return false; 9725 } 9726 final int segmentStart = range[0]; 9727 final int segmentEnd = range[1]; 9728 int selectionStart; 9729 int selectionEnd; 9730 if (extendSelection && isAccessibilitySelectionExtendable()) { 9731 selectionStart = getAccessibilitySelectionStart(); 9732 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 9733 selectionStart = forward ? segmentStart : segmentEnd; 9734 } 9735 selectionEnd = forward ? segmentEnd : segmentStart; 9736 } else { 9737 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 9738 } 9739 setAccessibilitySelection(selectionStart, selectionEnd); 9740 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 9741 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 9742 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 9743 return true; 9744 } 9745 9746 /** 9747 * Gets the text reported for accessibility purposes. 9748 * 9749 * @return The accessibility text. 9750 * 9751 * @hide 9752 */ getIterableTextForAccessibility()9753 public CharSequence getIterableTextForAccessibility() { 9754 return getContentDescription(); 9755 } 9756 9757 /** 9758 * Gets whether accessibility selection can be extended. 9759 * 9760 * @return If selection is extensible. 9761 * 9762 * @hide 9763 */ isAccessibilitySelectionExtendable()9764 public boolean isAccessibilitySelectionExtendable() { 9765 return false; 9766 } 9767 9768 /** 9769 * @hide 9770 */ getAccessibilitySelectionStart()9771 public int getAccessibilitySelectionStart() { 9772 return mAccessibilityCursorPosition; 9773 } 9774 9775 /** 9776 * @hide 9777 */ getAccessibilitySelectionEnd()9778 public int getAccessibilitySelectionEnd() { 9779 return getAccessibilitySelectionStart(); 9780 } 9781 9782 /** 9783 * @hide 9784 */ setAccessibilitySelection(int start, int end)9785 public void setAccessibilitySelection(int start, int end) { 9786 if (start == end && end == mAccessibilityCursorPosition) { 9787 return; 9788 } 9789 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 9790 mAccessibilityCursorPosition = start; 9791 } else { 9792 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 9793 } 9794 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 9795 } 9796 sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex)9797 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 9798 int fromIndex, int toIndex) { 9799 if (mParent == null) { 9800 return; 9801 } 9802 AccessibilityEvent event = AccessibilityEvent.obtain( 9803 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 9804 onInitializeAccessibilityEvent(event); 9805 onPopulateAccessibilityEvent(event); 9806 event.setFromIndex(fromIndex); 9807 event.setToIndex(toIndex); 9808 event.setAction(action); 9809 event.setMovementGranularity(granularity); 9810 mParent.requestSendAccessibilityEvent(this, event); 9811 } 9812 9813 /** 9814 * @hide 9815 */ getIteratorForGranularity(int granularity)9816 public TextSegmentIterator getIteratorForGranularity(int granularity) { 9817 switch (granularity) { 9818 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 9819 CharSequence text = getIterableTextForAccessibility(); 9820 if (text != null && text.length() > 0) { 9821 CharacterTextSegmentIterator iterator = 9822 CharacterTextSegmentIterator.getInstance( 9823 mContext.getResources().getConfiguration().locale); 9824 iterator.initialize(text.toString()); 9825 return iterator; 9826 } 9827 } break; 9828 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 9829 CharSequence text = getIterableTextForAccessibility(); 9830 if (text != null && text.length() > 0) { 9831 WordTextSegmentIterator iterator = 9832 WordTextSegmentIterator.getInstance( 9833 mContext.getResources().getConfiguration().locale); 9834 iterator.initialize(text.toString()); 9835 return iterator; 9836 } 9837 } break; 9838 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 9839 CharSequence text = getIterableTextForAccessibility(); 9840 if (text != null && text.length() > 0) { 9841 ParagraphTextSegmentIterator iterator = 9842 ParagraphTextSegmentIterator.getInstance(); 9843 iterator.initialize(text.toString()); 9844 return iterator; 9845 } 9846 } break; 9847 } 9848 return null; 9849 } 9850 9851 /** 9852 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 9853 * and {@link #onFinishTemporaryDetach()}. 9854 * 9855 * <p>This method always returns {@code true} when called directly or indirectly from 9856 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 9857 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 9858 * <ul> 9859 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 9860 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 9861 * </ul> 9862 * </p> 9863 * 9864 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 9865 * and {@link #onFinishTemporaryDetach()}. 9866 */ isTemporarilyDetached()9867 public final boolean isTemporarilyDetached() { 9868 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 9869 } 9870 9871 /** 9872 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 9873 * a container View. 9874 */ 9875 @CallSuper dispatchStartTemporaryDetach()9876 public void dispatchStartTemporaryDetach() { 9877 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 9878 onStartTemporaryDetach(); 9879 } 9880 9881 /** 9882 * This is called when a container is going to temporarily detach a child, with 9883 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 9884 * It will either be followed by {@link #onFinishTemporaryDetach()} or 9885 * {@link #onDetachedFromWindow()} when the container is done. 9886 */ onStartTemporaryDetach()9887 public void onStartTemporaryDetach() { 9888 removeUnsetPressCallback(); 9889 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 9890 } 9891 9892 /** 9893 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 9894 * a container View. 9895 */ 9896 @CallSuper dispatchFinishTemporaryDetach()9897 public void dispatchFinishTemporaryDetach() { 9898 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 9899 onFinishTemporaryDetach(); 9900 if (hasWindowFocus() && hasFocus()) { 9901 InputMethodManager.getInstance().focusIn(this); 9902 } 9903 } 9904 9905 /** 9906 * Called after {@link #onStartTemporaryDetach} when the container is done 9907 * changing the view. 9908 */ onFinishTemporaryDetach()9909 public void onFinishTemporaryDetach() { 9910 } 9911 9912 /** 9913 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 9914 * for this view's window. Returns null if the view is not currently attached 9915 * to the window. Normally you will not need to use this directly, but 9916 * just use the standard high-level event callbacks like 9917 * {@link #onKeyDown(int, KeyEvent)}. 9918 */ getKeyDispatcherState()9919 public KeyEvent.DispatcherState getKeyDispatcherState() { 9920 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 9921 } 9922 9923 /** 9924 * Dispatch a key event before it is processed by any input method 9925 * associated with the view hierarchy. This can be used to intercept 9926 * key events in special situations before the IME consumes them; a 9927 * typical example would be handling the BACK key to update the application's 9928 * UI instead of allowing the IME to see it and close itself. 9929 * 9930 * @param event The key event to be dispatched. 9931 * @return True if the event was handled, false otherwise. 9932 */ dispatchKeyEventPreIme(KeyEvent event)9933 public boolean dispatchKeyEventPreIme(KeyEvent event) { 9934 return onKeyPreIme(event.getKeyCode(), event); 9935 } 9936 9937 /** 9938 * Dispatch a key event to the next view on the focus path. This path runs 9939 * from the top of the view tree down to the currently focused view. If this 9940 * view has focus, it will dispatch to itself. Otherwise it will dispatch 9941 * the next node down the focus path. This method also fires any key 9942 * listeners. 9943 * 9944 * @param event The key event to be dispatched. 9945 * @return True if the event was handled, false otherwise. 9946 */ dispatchKeyEvent(KeyEvent event)9947 public boolean dispatchKeyEvent(KeyEvent event) { 9948 if (mInputEventConsistencyVerifier != null) { 9949 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 9950 } 9951 9952 // Give any attached key listener a first crack at the event. 9953 //noinspection SimplifiableIfStatement 9954 ListenerInfo li = mListenerInfo; 9955 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 9956 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 9957 return true; 9958 } 9959 9960 if (event.dispatch(this, mAttachInfo != null 9961 ? mAttachInfo.mKeyDispatchState : null, this)) { 9962 return true; 9963 } 9964 9965 if (mInputEventConsistencyVerifier != null) { 9966 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 9967 } 9968 return false; 9969 } 9970 9971 /** 9972 * Dispatches a key shortcut event. 9973 * 9974 * @param event The key event to be dispatched. 9975 * @return True if the event was handled by the view, false otherwise. 9976 */ dispatchKeyShortcutEvent(KeyEvent event)9977 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 9978 return onKeyShortcut(event.getKeyCode(), event); 9979 } 9980 9981 /** 9982 * Pass the touch screen motion event down to the target view, or this 9983 * view if it is the target. 9984 * 9985 * @param event The motion event to be dispatched. 9986 * @return True if the event was handled by the view, false otherwise. 9987 */ dispatchTouchEvent(MotionEvent event)9988 public boolean dispatchTouchEvent(MotionEvent event) { 9989 // If the event should be handled by accessibility focus first. 9990 if (event.isTargetAccessibilityFocus()) { 9991 // We don't have focus or no virtual descendant has it, do not handle the event. 9992 if (!isAccessibilityFocusedViewOrHost()) { 9993 return false; 9994 } 9995 // We have focus and got the event, then use normal event dispatch. 9996 event.setTargetAccessibilityFocus(false); 9997 } 9998 9999 boolean result = false; 10000 10001 if (mInputEventConsistencyVerifier != null) { 10002 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 10003 } 10004 10005 final int actionMasked = event.getActionMasked(); 10006 if (actionMasked == MotionEvent.ACTION_DOWN) { 10007 // Defensive cleanup for new gesture 10008 stopNestedScroll(); 10009 } 10010 10011 if (onFilterTouchEventForSecurity(event)) { 10012 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 10013 result = true; 10014 } 10015 //noinspection SimplifiableIfStatement 10016 ListenerInfo li = mListenerInfo; 10017 if (li != null && li.mOnTouchListener != null 10018 && (mViewFlags & ENABLED_MASK) == ENABLED 10019 && li.mOnTouchListener.onTouch(this, event)) { 10020 result = true; 10021 } 10022 10023 if (!result && onTouchEvent(event)) { 10024 result = true; 10025 } 10026 } 10027 10028 if (!result && mInputEventConsistencyVerifier != null) { 10029 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10030 } 10031 10032 // Clean up after nested scrolls if this is the end of a gesture; 10033 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 10034 // of the gesture. 10035 if (actionMasked == MotionEvent.ACTION_UP || 10036 actionMasked == MotionEvent.ACTION_CANCEL || 10037 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 10038 stopNestedScroll(); 10039 } 10040 10041 return result; 10042 } 10043 isAccessibilityFocusedViewOrHost()10044 boolean isAccessibilityFocusedViewOrHost() { 10045 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 10046 .getAccessibilityFocusedHost() == this); 10047 } 10048 10049 /** 10050 * Filter the touch event to apply security policies. 10051 * 10052 * @param event The motion event to be filtered. 10053 * @return True if the event should be dispatched, false if the event should be dropped. 10054 * 10055 * @see #getFilterTouchesWhenObscured 10056 */ onFilterTouchEventForSecurity(MotionEvent event)10057 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 10058 //noinspection RedundantIfStatement 10059 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 10060 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 10061 // Window is obscured, drop this touch. 10062 return false; 10063 } 10064 return true; 10065 } 10066 10067 /** 10068 * Pass a trackball motion event down to the focused view. 10069 * 10070 * @param event The motion event to be dispatched. 10071 * @return True if the event was handled by the view, false otherwise. 10072 */ dispatchTrackballEvent(MotionEvent event)10073 public boolean dispatchTrackballEvent(MotionEvent event) { 10074 if (mInputEventConsistencyVerifier != null) { 10075 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 10076 } 10077 10078 return onTrackballEvent(event); 10079 } 10080 10081 /** 10082 * Dispatch a generic motion event. 10083 * <p> 10084 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10085 * are delivered to the view under the pointer. All other generic motion events are 10086 * delivered to the focused view. Hover events are handled specially and are delivered 10087 * to {@link #onHoverEvent(MotionEvent)}. 10088 * </p> 10089 * 10090 * @param event The motion event to be dispatched. 10091 * @return True if the event was handled by the view, false otherwise. 10092 */ dispatchGenericMotionEvent(MotionEvent event)10093 public boolean dispatchGenericMotionEvent(MotionEvent event) { 10094 if (mInputEventConsistencyVerifier != null) { 10095 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 10096 } 10097 10098 final int source = event.getSource(); 10099 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 10100 final int action = event.getAction(); 10101 if (action == MotionEvent.ACTION_HOVER_ENTER 10102 || action == MotionEvent.ACTION_HOVER_MOVE 10103 || action == MotionEvent.ACTION_HOVER_EXIT) { 10104 if (dispatchHoverEvent(event)) { 10105 return true; 10106 } 10107 } else if (dispatchGenericPointerEvent(event)) { 10108 return true; 10109 } 10110 } else if (dispatchGenericFocusedEvent(event)) { 10111 return true; 10112 } 10113 10114 if (dispatchGenericMotionEventInternal(event)) { 10115 return true; 10116 } 10117 10118 if (mInputEventConsistencyVerifier != null) { 10119 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10120 } 10121 return false; 10122 } 10123 dispatchGenericMotionEventInternal(MotionEvent event)10124 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 10125 //noinspection SimplifiableIfStatement 10126 ListenerInfo li = mListenerInfo; 10127 if (li != null && li.mOnGenericMotionListener != null 10128 && (mViewFlags & ENABLED_MASK) == ENABLED 10129 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 10130 return true; 10131 } 10132 10133 if (onGenericMotionEvent(event)) { 10134 return true; 10135 } 10136 10137 final int actionButton = event.getActionButton(); 10138 switch (event.getActionMasked()) { 10139 case MotionEvent.ACTION_BUTTON_PRESS: 10140 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 10141 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10142 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10143 if (performContextClick(event.getX(), event.getY())) { 10144 mInContextButtonPress = true; 10145 setPressed(true, event.getX(), event.getY()); 10146 removeTapCallback(); 10147 removeLongPressCallback(); 10148 return true; 10149 } 10150 } 10151 break; 10152 10153 case MotionEvent.ACTION_BUTTON_RELEASE: 10154 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 10155 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 10156 mInContextButtonPress = false; 10157 mIgnoreNextUpEvent = true; 10158 } 10159 break; 10160 } 10161 10162 if (mInputEventConsistencyVerifier != null) { 10163 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 10164 } 10165 return false; 10166 } 10167 10168 /** 10169 * Dispatch a hover event. 10170 * <p> 10171 * Do not call this method directly. 10172 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10173 * </p> 10174 * 10175 * @param event The motion event to be dispatched. 10176 * @return True if the event was handled by the view, false otherwise. 10177 */ dispatchHoverEvent(MotionEvent event)10178 protected boolean dispatchHoverEvent(MotionEvent event) { 10179 ListenerInfo li = mListenerInfo; 10180 //noinspection SimplifiableIfStatement 10181 if (li != null && li.mOnHoverListener != null 10182 && (mViewFlags & ENABLED_MASK) == ENABLED 10183 && li.mOnHoverListener.onHover(this, event)) { 10184 return true; 10185 } 10186 10187 return onHoverEvent(event); 10188 } 10189 10190 /** 10191 * Returns true if the view has a child to which it has recently sent 10192 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 10193 * it does not have a hovered child, then it must be the innermost hovered view. 10194 * @hide 10195 */ hasHoveredChild()10196 protected boolean hasHoveredChild() { 10197 return false; 10198 } 10199 10200 /** 10201 * Dispatch a generic motion event to the view under the first pointer. 10202 * <p> 10203 * Do not call this method directly. 10204 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10205 * </p> 10206 * 10207 * @param event The motion event to be dispatched. 10208 * @return True if the event was handled by the view, false otherwise. 10209 */ dispatchGenericPointerEvent(MotionEvent event)10210 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 10211 return false; 10212 } 10213 10214 /** 10215 * Dispatch a generic motion event to the currently focused view. 10216 * <p> 10217 * Do not call this method directly. 10218 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 10219 * </p> 10220 * 10221 * @param event The motion event to be dispatched. 10222 * @return True if the event was handled by the view, false otherwise. 10223 */ dispatchGenericFocusedEvent(MotionEvent event)10224 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 10225 return false; 10226 } 10227 10228 /** 10229 * Dispatch a pointer event. 10230 * <p> 10231 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 10232 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 10233 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 10234 * and should not be expected to handle other pointing device features. 10235 * </p> 10236 * 10237 * @param event The motion event to be dispatched. 10238 * @return True if the event was handled by the view, false otherwise. 10239 * @hide 10240 */ dispatchPointerEvent(MotionEvent event)10241 public final boolean dispatchPointerEvent(MotionEvent event) { 10242 if (event.isTouchEvent()) { 10243 return dispatchTouchEvent(event); 10244 } else { 10245 return dispatchGenericMotionEvent(event); 10246 } 10247 } 10248 10249 /** 10250 * Called when the window containing this view gains or loses window focus. 10251 * ViewGroups should override to route to their children. 10252 * 10253 * @param hasFocus True if the window containing this view now has focus, 10254 * false otherwise. 10255 */ dispatchWindowFocusChanged(boolean hasFocus)10256 public void dispatchWindowFocusChanged(boolean hasFocus) { 10257 onWindowFocusChanged(hasFocus); 10258 } 10259 10260 /** 10261 * Called when the window containing this view gains or loses focus. Note 10262 * that this is separate from view focus: to receive key events, both 10263 * your view and its window must have focus. If a window is displayed 10264 * on top of yours that takes input focus, then your own window will lose 10265 * focus but the view focus will remain unchanged. 10266 * 10267 * @param hasWindowFocus True if the window containing this view now has 10268 * focus, false otherwise. 10269 */ onWindowFocusChanged(boolean hasWindowFocus)10270 public void onWindowFocusChanged(boolean hasWindowFocus) { 10271 InputMethodManager imm = InputMethodManager.peekInstance(); 10272 if (!hasWindowFocus) { 10273 if (isPressed()) { 10274 setPressed(false); 10275 } 10276 if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10277 imm.focusOut(this); 10278 } 10279 removeLongPressCallback(); 10280 removeTapCallback(); 10281 onFocusLost(); 10282 } else if (imm != null && (mPrivateFlags & PFLAG_FOCUSED) != 0) { 10283 imm.focusIn(this); 10284 } 10285 refreshDrawableState(); 10286 } 10287 10288 /** 10289 * Returns true if this view is in a window that currently has window focus. 10290 * Note that this is not the same as the view itself having focus. 10291 * 10292 * @return True if this view is in a window that currently has window focus. 10293 */ hasWindowFocus()10294 public boolean hasWindowFocus() { 10295 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 10296 } 10297 10298 /** 10299 * Dispatch a view visibility change down the view hierarchy. 10300 * ViewGroups should override to route to their children. 10301 * @param changedView The view whose visibility changed. Could be 'this' or 10302 * an ancestor view. 10303 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 10304 * {@link #INVISIBLE} or {@link #GONE}. 10305 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)10306 protected void dispatchVisibilityChanged(@NonNull View changedView, 10307 @Visibility int visibility) { 10308 onVisibilityChanged(changedView, visibility); 10309 } 10310 10311 /** 10312 * Called when the visibility of the view or an ancestor of the view has 10313 * changed. 10314 * 10315 * @param changedView The view whose visibility changed. May be 10316 * {@code this} or an ancestor view. 10317 * @param visibility The new visibility, one of {@link #VISIBLE}, 10318 * {@link #INVISIBLE} or {@link #GONE}. 10319 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)10320 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 10321 } 10322 10323 /** 10324 * Dispatch a hint about whether this view is displayed. For instance, when 10325 * a View moves out of the screen, it might receives a display hint indicating 10326 * the view is not displayed. Applications should not <em>rely</em> on this hint 10327 * as there is no guarantee that they will receive one. 10328 * 10329 * @param hint A hint about whether or not this view is displayed: 10330 * {@link #VISIBLE} or {@link #INVISIBLE}. 10331 */ dispatchDisplayHint(@isibility int hint)10332 public void dispatchDisplayHint(@Visibility int hint) { 10333 onDisplayHint(hint); 10334 } 10335 10336 /** 10337 * Gives this view a hint about whether is displayed or not. For instance, when 10338 * a View moves out of the screen, it might receives a display hint indicating 10339 * the view is not displayed. Applications should not <em>rely</em> on this hint 10340 * as there is no guarantee that they will receive one. 10341 * 10342 * @param hint A hint about whether or not this view is displayed: 10343 * {@link #VISIBLE} or {@link #INVISIBLE}. 10344 */ onDisplayHint(@isibility int hint)10345 protected void onDisplayHint(@Visibility int hint) { 10346 } 10347 10348 /** 10349 * Dispatch a window visibility change down the view hierarchy. 10350 * ViewGroups should override to route to their children. 10351 * 10352 * @param visibility The new visibility of the window. 10353 * 10354 * @see #onWindowVisibilityChanged(int) 10355 */ dispatchWindowVisibilityChanged(@isibility int visibility)10356 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 10357 onWindowVisibilityChanged(visibility); 10358 } 10359 10360 /** 10361 * Called when the window containing has change its visibility 10362 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 10363 * that this tells you whether or not your window is being made visible 10364 * to the window manager; this does <em>not</em> tell you whether or not 10365 * your window is obscured by other windows on the screen, even if it 10366 * is itself visible. 10367 * 10368 * @param visibility The new visibility of the window. 10369 */ onWindowVisibilityChanged(@isibility int visibility)10370 protected void onWindowVisibilityChanged(@Visibility int visibility) { 10371 if (visibility == VISIBLE) { 10372 initialAwakenScrollBars(); 10373 } 10374 } 10375 10376 /** 10377 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 10378 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 10379 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 10380 * 10381 * @param isVisible true if this view's visibility to the user is uninterrupted by its 10382 * ancestors or by window visibility 10383 * @return true if this view is visible to the user, not counting clipping or overlapping 10384 */ dispatchVisibilityAggregated(boolean isVisible)10385 boolean dispatchVisibilityAggregated(boolean isVisible) { 10386 final boolean thisVisible = getVisibility() == VISIBLE; 10387 // If we're not visible but something is telling us we are, ignore it. 10388 if (thisVisible || !isVisible) { 10389 onVisibilityAggregated(isVisible); 10390 } 10391 return thisVisible && isVisible; 10392 } 10393 10394 /** 10395 * Called when the user-visibility of this View is potentially affected by a change 10396 * to this view itself, an ancestor view or the window this view is attached to. 10397 * 10398 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 10399 * and this view's window is also visible 10400 */ 10401 @CallSuper onVisibilityAggregated(boolean isVisible)10402 public void onVisibilityAggregated(boolean isVisible) { 10403 if (isVisible && mAttachInfo != null) { 10404 initialAwakenScrollBars(); 10405 } 10406 10407 final Drawable dr = mBackground; 10408 if (dr != null && isVisible != dr.isVisible()) { 10409 dr.setVisible(isVisible, false); 10410 } 10411 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 10412 if (fg != null && isVisible != fg.isVisible()) { 10413 fg.setVisible(isVisible, false); 10414 } 10415 } 10416 10417 /** 10418 * Returns the current visibility of the window this view is attached to 10419 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 10420 * 10421 * @return Returns the current visibility of the view's window. 10422 */ 10423 @Visibility getWindowVisibility()10424 public int getWindowVisibility() { 10425 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 10426 } 10427 10428 /** 10429 * Retrieve the overall visible display size in which the window this view is 10430 * attached to has been positioned in. This takes into account screen 10431 * decorations above the window, for both cases where the window itself 10432 * is being position inside of them or the window is being placed under 10433 * then and covered insets are used for the window to position its content 10434 * inside. In effect, this tells you the available area where content can 10435 * be placed and remain visible to users. 10436 * 10437 * <p>This function requires an IPC back to the window manager to retrieve 10438 * the requested information, so should not be used in performance critical 10439 * code like drawing. 10440 * 10441 * @param outRect Filled in with the visible display frame. If the view 10442 * is not attached to a window, this is simply the raw display size. 10443 */ getWindowVisibleDisplayFrame(Rect outRect)10444 public void getWindowVisibleDisplayFrame(Rect outRect) { 10445 if (mAttachInfo != null) { 10446 try { 10447 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 10448 } catch (RemoteException e) { 10449 return; 10450 } 10451 // XXX This is really broken, and probably all needs to be done 10452 // in the window manager, and we need to know more about whether 10453 // we want the area behind or in front of the IME. 10454 final Rect insets = mAttachInfo.mVisibleInsets; 10455 outRect.left += insets.left; 10456 outRect.top += insets.top; 10457 outRect.right -= insets.right; 10458 outRect.bottom -= insets.bottom; 10459 return; 10460 } 10461 // The view is not attached to a display so we don't have a context. 10462 // Make a best guess about the display size. 10463 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 10464 d.getRectSize(outRect); 10465 } 10466 10467 /** 10468 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 10469 * is currently in without any insets. 10470 * 10471 * @hide 10472 */ getWindowDisplayFrame(Rect outRect)10473 public void getWindowDisplayFrame(Rect outRect) { 10474 if (mAttachInfo != null) { 10475 try { 10476 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 10477 } catch (RemoteException e) { 10478 return; 10479 } 10480 return; 10481 } 10482 // The view is not attached to a display so we don't have a context. 10483 // Make a best guess about the display size. 10484 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 10485 d.getRectSize(outRect); 10486 } 10487 10488 /** 10489 * Dispatch a notification about a resource configuration change down 10490 * the view hierarchy. 10491 * ViewGroups should override to route to their children. 10492 * 10493 * @param newConfig The new resource configuration. 10494 * 10495 * @see #onConfigurationChanged(android.content.res.Configuration) 10496 */ dispatchConfigurationChanged(Configuration newConfig)10497 public void dispatchConfigurationChanged(Configuration newConfig) { 10498 onConfigurationChanged(newConfig); 10499 } 10500 10501 /** 10502 * Called when the current configuration of the resources being used 10503 * by the application have changed. You can use this to decide when 10504 * to reload resources that can changed based on orientation and other 10505 * configuration characteristics. You only need to use this if you are 10506 * not relying on the normal {@link android.app.Activity} mechanism of 10507 * recreating the activity instance upon a configuration change. 10508 * 10509 * @param newConfig The new resource configuration. 10510 */ onConfigurationChanged(Configuration newConfig)10511 protected void onConfigurationChanged(Configuration newConfig) { 10512 } 10513 10514 /** 10515 * Private function to aggregate all per-view attributes in to the view 10516 * root. 10517 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)10518 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 10519 performCollectViewAttributes(attachInfo, visibility); 10520 } 10521 performCollectViewAttributes(AttachInfo attachInfo, int visibility)10522 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 10523 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 10524 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 10525 attachInfo.mKeepScreenOn = true; 10526 } 10527 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 10528 ListenerInfo li = mListenerInfo; 10529 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 10530 attachInfo.mHasSystemUiListeners = true; 10531 } 10532 } 10533 } 10534 needGlobalAttributesUpdate(boolean force)10535 void needGlobalAttributesUpdate(boolean force) { 10536 final AttachInfo ai = mAttachInfo; 10537 if (ai != null && !ai.mRecomputeGlobalAttributes) { 10538 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 10539 || ai.mHasSystemUiListeners) { 10540 ai.mRecomputeGlobalAttributes = true; 10541 } 10542 } 10543 } 10544 10545 /** 10546 * Returns whether the device is currently in touch mode. Touch mode is entered 10547 * once the user begins interacting with the device by touch, and affects various 10548 * things like whether focus is always visible to the user. 10549 * 10550 * @return Whether the device is in touch mode. 10551 */ 10552 @ViewDebug.ExportedProperty isInTouchMode()10553 public boolean isInTouchMode() { 10554 if (mAttachInfo != null) { 10555 return mAttachInfo.mInTouchMode; 10556 } else { 10557 return ViewRootImpl.isInTouchMode(); 10558 } 10559 } 10560 10561 /** 10562 * Returns the context the view is running in, through which it can 10563 * access the current theme, resources, etc. 10564 * 10565 * @return The view's Context. 10566 */ 10567 @ViewDebug.CapturedViewProperty getContext()10568 public final Context getContext() { 10569 return mContext; 10570 } 10571 10572 /** 10573 * Handle a key event before it is processed by any input method 10574 * associated with the view hierarchy. This can be used to intercept 10575 * key events in special situations before the IME consumes them; a 10576 * typical example would be handling the BACK key to update the application's 10577 * UI instead of allowing the IME to see it and close itself. 10578 * 10579 * @param keyCode The value in event.getKeyCode(). 10580 * @param event Description of the key event. 10581 * @return If you handled the event, return true. If you want to allow the 10582 * event to be handled by the next receiver, return false. 10583 */ onKeyPreIme(int keyCode, KeyEvent event)10584 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 10585 return false; 10586 } 10587 10588 /** 10589 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 10590 * KeyEvent.Callback.onKeyDown()}: perform press of the view 10591 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 10592 * is released, if the view is enabled and clickable. 10593 * <p> 10594 * Key presses in software keyboards will generally NOT trigger this 10595 * listener, although some may elect to do so in some situations. Do not 10596 * rely on this to catch software key presses. 10597 * 10598 * @param keyCode a key code that represents the button pressed, from 10599 * {@link android.view.KeyEvent} 10600 * @param event the KeyEvent object that defines the button action 10601 */ onKeyDown(int keyCode, KeyEvent event)10602 public boolean onKeyDown(int keyCode, KeyEvent event) { 10603 if (KeyEvent.isConfirmKey(keyCode)) { 10604 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10605 return true; 10606 } 10607 10608 // Long clickable items don't necessarily have to be clickable. 10609 if (((mViewFlags & CLICKABLE) == CLICKABLE 10610 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 10611 && (event.getRepeatCount() == 0)) { 10612 // For the purposes of menu anchoring and drawable hotspots, 10613 // key events are considered to be at the center of the view. 10614 final float x = getWidth() / 2f; 10615 final float y = getHeight() / 2f; 10616 setPressed(true, x, y); 10617 checkForLongClick(0, x, y); 10618 return true; 10619 } 10620 } 10621 10622 return false; 10623 } 10624 10625 /** 10626 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 10627 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 10628 * the event). 10629 * <p>Key presses in software keyboards will generally NOT trigger this listener, 10630 * although some may elect to do so in some situations. Do not rely on this to 10631 * catch software key presses. 10632 */ onKeyLongPress(int keyCode, KeyEvent event)10633 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 10634 return false; 10635 } 10636 10637 /** 10638 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 10639 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 10640 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 10641 * or {@link KeyEvent#KEYCODE_SPACE} is released. 10642 * <p>Key presses in software keyboards will generally NOT trigger this listener, 10643 * although some may elect to do so in some situations. Do not rely on this to 10644 * catch software key presses. 10645 * 10646 * @param keyCode A key code that represents the button pressed, from 10647 * {@link android.view.KeyEvent}. 10648 * @param event The KeyEvent object that defines the button action. 10649 */ onKeyUp(int keyCode, KeyEvent event)10650 public boolean onKeyUp(int keyCode, KeyEvent event) { 10651 if (KeyEvent.isConfirmKey(keyCode)) { 10652 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10653 return true; 10654 } 10655 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 10656 setPressed(false); 10657 10658 if (!mHasPerformedLongPress) { 10659 // This is a tap, so remove the longpress check 10660 removeLongPressCallback(); 10661 return performClick(); 10662 } 10663 } 10664 } 10665 return false; 10666 } 10667 10668 /** 10669 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 10670 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 10671 * the event). 10672 * <p>Key presses in software keyboards will generally NOT trigger this listener, 10673 * although some may elect to do so in some situations. Do not rely on this to 10674 * catch software key presses. 10675 * 10676 * @param keyCode A key code that represents the button pressed, from 10677 * {@link android.view.KeyEvent}. 10678 * @param repeatCount The number of times the action was made. 10679 * @param event The KeyEvent object that defines the button action. 10680 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)10681 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 10682 return false; 10683 } 10684 10685 /** 10686 * Called on the focused view when a key shortcut event is not handled. 10687 * Override this method to implement local key shortcuts for the View. 10688 * Key shortcuts can also be implemented by setting the 10689 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 10690 * 10691 * @param keyCode The value in event.getKeyCode(). 10692 * @param event Description of the key event. 10693 * @return If you handled the event, return true. If you want to allow the 10694 * event to be handled by the next receiver, return false. 10695 */ onKeyShortcut(int keyCode, KeyEvent event)10696 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 10697 return false; 10698 } 10699 10700 /** 10701 * Check whether the called view is a text editor, in which case it 10702 * would make sense to automatically display a soft input window for 10703 * it. Subclasses should override this if they implement 10704 * {@link #onCreateInputConnection(EditorInfo)} to return true if 10705 * a call on that method would return a non-null InputConnection, and 10706 * they are really a first-class editor that the user would normally 10707 * start typing on when the go into a window containing your view. 10708 * 10709 * <p>The default implementation always returns false. This does 10710 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 10711 * will not be called or the user can not otherwise perform edits on your 10712 * view; it is just a hint to the system that this is not the primary 10713 * purpose of this view. 10714 * 10715 * @return Returns true if this view is a text editor, else false. 10716 */ onCheckIsTextEditor()10717 public boolean onCheckIsTextEditor() { 10718 return false; 10719 } 10720 10721 /** 10722 * Create a new InputConnection for an InputMethod to interact 10723 * with the view. The default implementation returns null, since it doesn't 10724 * support input methods. You can override this to implement such support. 10725 * This is only needed for views that take focus and text input. 10726 * 10727 * <p>When implementing this, you probably also want to implement 10728 * {@link #onCheckIsTextEditor()} to indicate you will return a 10729 * non-null InputConnection.</p> 10730 * 10731 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 10732 * object correctly and in its entirety, so that the connected IME can rely 10733 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 10734 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 10735 * must be filled in with the correct cursor position for IMEs to work correctly 10736 * with your application.</p> 10737 * 10738 * @param outAttrs Fill in with attribute information about the connection. 10739 */ onCreateInputConnection(EditorInfo outAttrs)10740 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 10741 return null; 10742 } 10743 10744 /** 10745 * Called by the {@link android.view.inputmethod.InputMethodManager} 10746 * when a view who is not the current 10747 * input connection target is trying to make a call on the manager. The 10748 * default implementation returns false; you can override this to return 10749 * true for certain views if you are performing InputConnection proxying 10750 * to them. 10751 * @param view The View that is making the InputMethodManager call. 10752 * @return Return true to allow the call, false to reject. 10753 */ checkInputConnectionProxy(View view)10754 public boolean checkInputConnectionProxy(View view) { 10755 return false; 10756 } 10757 10758 /** 10759 * Show the context menu for this view. It is not safe to hold on to the 10760 * menu after returning from this method. 10761 * 10762 * You should normally not overload this method. Overload 10763 * {@link #onCreateContextMenu(ContextMenu)} or define an 10764 * {@link OnCreateContextMenuListener} to add items to the context menu. 10765 * 10766 * @param menu The context menu to populate 10767 */ createContextMenu(ContextMenu menu)10768 public void createContextMenu(ContextMenu menu) { 10769 ContextMenuInfo menuInfo = getContextMenuInfo(); 10770 10771 // Sets the current menu info so all items added to menu will have 10772 // my extra info set. 10773 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 10774 10775 onCreateContextMenu(menu); 10776 ListenerInfo li = mListenerInfo; 10777 if (li != null && li.mOnCreateContextMenuListener != null) { 10778 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 10779 } 10780 10781 // Clear the extra information so subsequent items that aren't mine don't 10782 // have my extra info. 10783 ((MenuBuilder)menu).setCurrentMenuInfo(null); 10784 10785 if (mParent != null) { 10786 mParent.createContextMenu(menu); 10787 } 10788 } 10789 10790 /** 10791 * Views should implement this if they have extra information to associate 10792 * with the context menu. The return result is supplied as a parameter to 10793 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 10794 * callback. 10795 * 10796 * @return Extra information about the item for which the context menu 10797 * should be shown. This information will vary across different 10798 * subclasses of View. 10799 */ getContextMenuInfo()10800 protected ContextMenuInfo getContextMenuInfo() { 10801 return null; 10802 } 10803 10804 /** 10805 * Views should implement this if the view itself is going to add items to 10806 * the context menu. 10807 * 10808 * @param menu the context menu to populate 10809 */ onCreateContextMenu(ContextMenu menu)10810 protected void onCreateContextMenu(ContextMenu menu) { 10811 } 10812 10813 /** 10814 * Implement this method to handle trackball motion events. The 10815 * <em>relative</em> movement of the trackball since the last event 10816 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 10817 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 10818 * that a movement of 1 corresponds to the user pressing one DPAD key (so 10819 * they will often be fractional values, representing the more fine-grained 10820 * movement information available from a trackball). 10821 * 10822 * @param event The motion event. 10823 * @return True if the event was handled, false otherwise. 10824 */ onTrackballEvent(MotionEvent event)10825 public boolean onTrackballEvent(MotionEvent event) { 10826 return false; 10827 } 10828 10829 /** 10830 * Implement this method to handle generic motion events. 10831 * <p> 10832 * Generic motion events describe joystick movements, mouse hovers, track pad 10833 * touches, scroll wheel movements and other input events. The 10834 * {@link MotionEvent#getSource() source} of the motion event specifies 10835 * the class of input that was received. Implementations of this method 10836 * must examine the bits in the source before processing the event. 10837 * The following code example shows how this is done. 10838 * </p><p> 10839 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 10840 * are delivered to the view under the pointer. All other generic motion events are 10841 * delivered to the focused view. 10842 * </p> 10843 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 10844 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 10845 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 10846 * // process the joystick movement... 10847 * return true; 10848 * } 10849 * } 10850 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 10851 * switch (event.getAction()) { 10852 * case MotionEvent.ACTION_HOVER_MOVE: 10853 * // process the mouse hover movement... 10854 * return true; 10855 * case MotionEvent.ACTION_SCROLL: 10856 * // process the scroll wheel movement... 10857 * return true; 10858 * } 10859 * } 10860 * return super.onGenericMotionEvent(event); 10861 * }</pre> 10862 * 10863 * @param event The generic motion event being processed. 10864 * @return True if the event was handled, false otherwise. 10865 */ onGenericMotionEvent(MotionEvent event)10866 public boolean onGenericMotionEvent(MotionEvent event) { 10867 return false; 10868 } 10869 10870 /** 10871 * Implement this method to handle hover events. 10872 * <p> 10873 * This method is called whenever a pointer is hovering into, over, or out of the 10874 * bounds of a view and the view is not currently being touched. 10875 * Hover events are represented as pointer events with action 10876 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 10877 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 10878 * </p> 10879 * <ul> 10880 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 10881 * when the pointer enters the bounds of the view.</li> 10882 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 10883 * when the pointer has already entered the bounds of the view and has moved.</li> 10884 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 10885 * when the pointer has exited the bounds of the view or when the pointer is 10886 * about to go down due to a button click, tap, or similar user action that 10887 * causes the view to be touched.</li> 10888 * </ul> 10889 * <p> 10890 * The view should implement this method to return true to indicate that it is 10891 * handling the hover event, such as by changing its drawable state. 10892 * </p><p> 10893 * The default implementation calls {@link #setHovered} to update the hovered state 10894 * of the view when a hover enter or hover exit event is received, if the view 10895 * is enabled and is clickable. The default implementation also sends hover 10896 * accessibility events. 10897 * </p> 10898 * 10899 * @param event The motion event that describes the hover. 10900 * @return True if the view handled the hover event. 10901 * 10902 * @see #isHovered 10903 * @see #setHovered 10904 * @see #onHoverChanged 10905 */ onHoverEvent(MotionEvent event)10906 public boolean onHoverEvent(MotionEvent event) { 10907 // The root view may receive hover (or touch) events that are outside the bounds of 10908 // the window. This code ensures that we only send accessibility events for 10909 // hovers that are actually within the bounds of the root view. 10910 final int action = event.getActionMasked(); 10911 if (!mSendingHoverAccessibilityEvents) { 10912 if ((action == MotionEvent.ACTION_HOVER_ENTER 10913 || action == MotionEvent.ACTION_HOVER_MOVE) 10914 && !hasHoveredChild() 10915 && pointInView(event.getX(), event.getY())) { 10916 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 10917 mSendingHoverAccessibilityEvents = true; 10918 } 10919 } else { 10920 if (action == MotionEvent.ACTION_HOVER_EXIT 10921 || (action == MotionEvent.ACTION_MOVE 10922 && !pointInView(event.getX(), event.getY()))) { 10923 mSendingHoverAccessibilityEvents = false; 10924 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 10925 } 10926 } 10927 10928 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 10929 && event.isFromSource(InputDevice.SOURCE_MOUSE) 10930 && isOnScrollbar(event.getX(), event.getY())) { 10931 awakenScrollBars(); 10932 } 10933 if (isHoverable()) { 10934 switch (action) { 10935 case MotionEvent.ACTION_HOVER_ENTER: 10936 setHovered(true); 10937 break; 10938 case MotionEvent.ACTION_HOVER_EXIT: 10939 setHovered(false); 10940 break; 10941 } 10942 10943 // Dispatch the event to onGenericMotionEvent before returning true. 10944 // This is to provide compatibility with existing applications that 10945 // handled HOVER_MOVE events in onGenericMotionEvent and that would 10946 // break because of the new default handling for hoverable views 10947 // in onHoverEvent. 10948 // Note that onGenericMotionEvent will be called by default when 10949 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 10950 dispatchGenericMotionEventInternal(event); 10951 // The event was already handled by calling setHovered(), so always 10952 // return true. 10953 return true; 10954 } 10955 10956 return false; 10957 } 10958 10959 /** 10960 * Returns true if the view should handle {@link #onHoverEvent} 10961 * by calling {@link #setHovered} to change its hovered state. 10962 * 10963 * @return True if the view is hoverable. 10964 */ isHoverable()10965 private boolean isHoverable() { 10966 final int viewFlags = mViewFlags; 10967 if ((viewFlags & ENABLED_MASK) == DISABLED) { 10968 return false; 10969 } 10970 10971 return (viewFlags & CLICKABLE) == CLICKABLE 10972 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 10973 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 10974 } 10975 10976 /** 10977 * Returns true if the view is currently hovered. 10978 * 10979 * @return True if the view is currently hovered. 10980 * 10981 * @see #setHovered 10982 * @see #onHoverChanged 10983 */ 10984 @ViewDebug.ExportedProperty isHovered()10985 public boolean isHovered() { 10986 return (mPrivateFlags & PFLAG_HOVERED) != 0; 10987 } 10988 10989 /** 10990 * Sets whether the view is currently hovered. 10991 * <p> 10992 * Calling this method also changes the drawable state of the view. This 10993 * enables the view to react to hover by using different drawable resources 10994 * to change its appearance. 10995 * </p><p> 10996 * The {@link #onHoverChanged} method is called when the hovered state changes. 10997 * </p> 10998 * 10999 * @param hovered True if the view is hovered. 11000 * 11001 * @see #isHovered 11002 * @see #onHoverChanged 11003 */ setHovered(boolean hovered)11004 public void setHovered(boolean hovered) { 11005 if (hovered) { 11006 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 11007 mPrivateFlags |= PFLAG_HOVERED; 11008 refreshDrawableState(); 11009 onHoverChanged(true); 11010 } 11011 } else { 11012 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 11013 mPrivateFlags &= ~PFLAG_HOVERED; 11014 refreshDrawableState(); 11015 onHoverChanged(false); 11016 } 11017 } 11018 } 11019 11020 /** 11021 * Implement this method to handle hover state changes. 11022 * <p> 11023 * This method is called whenever the hover state changes as a result of a 11024 * call to {@link #setHovered}. 11025 * </p> 11026 * 11027 * @param hovered The current hover state, as returned by {@link #isHovered}. 11028 * 11029 * @see #isHovered 11030 * @see #setHovered 11031 */ onHoverChanged(boolean hovered)11032 public void onHoverChanged(boolean hovered) { 11033 } 11034 11035 /** 11036 * Handles scroll bar dragging by mouse input. 11037 * 11038 * @hide 11039 * @param event The motion event. 11040 * 11041 * @return true if the event was handled as a scroll bar dragging, false otherwise. 11042 */ handleScrollBarDragging(MotionEvent event)11043 protected boolean handleScrollBarDragging(MotionEvent event) { 11044 if (mScrollCache == null) { 11045 return false; 11046 } 11047 final float x = event.getX(); 11048 final float y = event.getY(); 11049 final int action = event.getAction(); 11050 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 11051 && action != MotionEvent.ACTION_DOWN) 11052 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 11053 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 11054 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11055 return false; 11056 } 11057 11058 switch (action) { 11059 case MotionEvent.ACTION_MOVE: 11060 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 11061 return false; 11062 } 11063 if (mScrollCache.mScrollBarDraggingState 11064 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 11065 final Rect bounds = mScrollCache.mScrollBarBounds; 11066 getVerticalScrollBarBounds(bounds); 11067 final int range = computeVerticalScrollRange(); 11068 final int offset = computeVerticalScrollOffset(); 11069 final int extent = computeVerticalScrollExtent(); 11070 11071 final int thumbLength = ScrollBarUtils.getThumbLength( 11072 bounds.height(), bounds.width(), extent, range); 11073 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11074 bounds.height(), thumbLength, extent, range, offset); 11075 11076 final float diff = y - mScrollCache.mScrollBarDraggingPos; 11077 final float maxThumbOffset = bounds.height() - thumbLength; 11078 final float newThumbOffset = 11079 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11080 final int height = getHeight(); 11081 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11082 && height > 0 && extent > 0) { 11083 final int newY = Math.round((range - extent) 11084 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 11085 if (newY != getScrollY()) { 11086 mScrollCache.mScrollBarDraggingPos = y; 11087 setScrollY(newY); 11088 } 11089 } 11090 return true; 11091 } 11092 if (mScrollCache.mScrollBarDraggingState 11093 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 11094 final Rect bounds = mScrollCache.mScrollBarBounds; 11095 getHorizontalScrollBarBounds(bounds); 11096 final int range = computeHorizontalScrollRange(); 11097 final int offset = computeHorizontalScrollOffset(); 11098 final int extent = computeHorizontalScrollExtent(); 11099 11100 final int thumbLength = ScrollBarUtils.getThumbLength( 11101 bounds.width(), bounds.height(), extent, range); 11102 final int thumbOffset = ScrollBarUtils.getThumbOffset( 11103 bounds.width(), thumbLength, extent, range, offset); 11104 11105 final float diff = x - mScrollCache.mScrollBarDraggingPos; 11106 final float maxThumbOffset = bounds.width() - thumbLength; 11107 final float newThumbOffset = 11108 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 11109 final int width = getWidth(); 11110 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 11111 && width > 0 && extent > 0) { 11112 final int newX = Math.round((range - extent) 11113 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 11114 if (newX != getScrollX()) { 11115 mScrollCache.mScrollBarDraggingPos = x; 11116 setScrollX(newX); 11117 } 11118 } 11119 return true; 11120 } 11121 case MotionEvent.ACTION_DOWN: 11122 if (mScrollCache.state == ScrollabilityCache.OFF) { 11123 return false; 11124 } 11125 if (isOnVerticalScrollbarThumb(x, y)) { 11126 mScrollCache.mScrollBarDraggingState = 11127 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 11128 mScrollCache.mScrollBarDraggingPos = y; 11129 return true; 11130 } 11131 if (isOnHorizontalScrollbarThumb(x, y)) { 11132 mScrollCache.mScrollBarDraggingState = 11133 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 11134 mScrollCache.mScrollBarDraggingPos = x; 11135 return true; 11136 } 11137 } 11138 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 11139 return false; 11140 } 11141 11142 /** 11143 * Implement this method to handle touch screen motion events. 11144 * <p> 11145 * If this method is used to detect click actions, it is recommended that 11146 * the actions be performed by implementing and calling 11147 * {@link #performClick()}. This will ensure consistent system behavior, 11148 * including: 11149 * <ul> 11150 * <li>obeying click sound preferences 11151 * <li>dispatching OnClickListener calls 11152 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 11153 * accessibility features are enabled 11154 * </ul> 11155 * 11156 * @param event The motion event. 11157 * @return True if the event was handled, false otherwise. 11158 */ onTouchEvent(MotionEvent event)11159 public boolean onTouchEvent(MotionEvent event) { 11160 final float x = event.getX(); 11161 final float y = event.getY(); 11162 final int viewFlags = mViewFlags; 11163 final int action = event.getAction(); 11164 11165 if ((viewFlags & ENABLED_MASK) == DISABLED) { 11166 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 11167 setPressed(false); 11168 } 11169 // A disabled view that is clickable still consumes the touch 11170 // events, it just doesn't respond to them. 11171 return (((viewFlags & CLICKABLE) == CLICKABLE 11172 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 11173 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE); 11174 } 11175 if (mTouchDelegate != null) { 11176 if (mTouchDelegate.onTouchEvent(event)) { 11177 return true; 11178 } 11179 } 11180 11181 if (((viewFlags & CLICKABLE) == CLICKABLE || 11182 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) || 11183 (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) { 11184 switch (action) { 11185 case MotionEvent.ACTION_UP: 11186 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 11187 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 11188 // take focus if we don't have it already and we should in 11189 // touch mode. 11190 boolean focusTaken = false; 11191 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 11192 focusTaken = requestFocus(); 11193 } 11194 11195 if (prepressed) { 11196 // The button is being released before we actually 11197 // showed it as pressed. Make it show the pressed 11198 // state now (before scheduling the click) to ensure 11199 // the user sees it. 11200 setPressed(true, x, y); 11201 } 11202 11203 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 11204 // This is a tap, so remove the longpress check 11205 removeLongPressCallback(); 11206 11207 // Only perform take click actions if we were in the pressed state 11208 if (!focusTaken) { 11209 // Use a Runnable and post this rather than calling 11210 // performClick directly. This lets other visual state 11211 // of the view update before click actions start. 11212 if (mPerformClick == null) { 11213 mPerformClick = new PerformClick(); 11214 } 11215 if (!post(mPerformClick)) { 11216 performClick(); 11217 } 11218 } 11219 } 11220 11221 if (mUnsetPressedState == null) { 11222 mUnsetPressedState = new UnsetPressedState(); 11223 } 11224 11225 if (prepressed) { 11226 postDelayed(mUnsetPressedState, 11227 ViewConfiguration.getPressedStateDuration()); 11228 } else if (!post(mUnsetPressedState)) { 11229 // If the post failed, unpress right now 11230 mUnsetPressedState.run(); 11231 } 11232 11233 removeTapCallback(); 11234 } 11235 mIgnoreNextUpEvent = false; 11236 break; 11237 11238 case MotionEvent.ACTION_DOWN: 11239 mHasPerformedLongPress = false; 11240 11241 if (performButtonActionOnTouchDown(event)) { 11242 break; 11243 } 11244 11245 // Walk up the hierarchy to determine if we're inside a scrolling container. 11246 boolean isInScrollingContainer = isInScrollingContainer(); 11247 11248 // For views inside a scrolling container, delay the pressed feedback for 11249 // a short period in case this is a scroll. 11250 if (isInScrollingContainer) { 11251 mPrivateFlags |= PFLAG_PREPRESSED; 11252 if (mPendingCheckForTap == null) { 11253 mPendingCheckForTap = new CheckForTap(); 11254 } 11255 mPendingCheckForTap.x = event.getX(); 11256 mPendingCheckForTap.y = event.getY(); 11257 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 11258 } else { 11259 // Not inside a scrolling container, so show the feedback right away 11260 setPressed(true, x, y); 11261 checkForLongClick(0, x, y); 11262 } 11263 break; 11264 11265 case MotionEvent.ACTION_CANCEL: 11266 setPressed(false); 11267 removeTapCallback(); 11268 removeLongPressCallback(); 11269 mInContextButtonPress = false; 11270 mHasPerformedLongPress = false; 11271 mIgnoreNextUpEvent = false; 11272 break; 11273 11274 case MotionEvent.ACTION_MOVE: 11275 drawableHotspotChanged(x, y); 11276 11277 // Be lenient about moving outside of buttons 11278 if (!pointInView(x, y, mTouchSlop)) { 11279 // Outside button 11280 removeTapCallback(); 11281 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 11282 // Remove any future long press/tap checks 11283 removeLongPressCallback(); 11284 11285 setPressed(false); 11286 } 11287 } 11288 break; 11289 } 11290 11291 return true; 11292 } 11293 11294 return false; 11295 } 11296 11297 /** 11298 * @hide 11299 */ isInScrollingContainer()11300 public boolean isInScrollingContainer() { 11301 ViewParent p = getParent(); 11302 while (p != null && p instanceof ViewGroup) { 11303 if (((ViewGroup) p).shouldDelayChildPressedState()) { 11304 return true; 11305 } 11306 p = p.getParent(); 11307 } 11308 return false; 11309 } 11310 11311 /** 11312 * Remove the longpress detection timer. 11313 */ removeLongPressCallback()11314 private void removeLongPressCallback() { 11315 if (mPendingCheckForLongPress != null) { 11316 removeCallbacks(mPendingCheckForLongPress); 11317 } 11318 } 11319 11320 /** 11321 * Remove the pending click action 11322 */ removePerformClickCallback()11323 private void removePerformClickCallback() { 11324 if (mPerformClick != null) { 11325 removeCallbacks(mPerformClick); 11326 } 11327 } 11328 11329 /** 11330 * Remove the prepress detection timer. 11331 */ removeUnsetPressCallback()11332 private void removeUnsetPressCallback() { 11333 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 11334 setPressed(false); 11335 removeCallbacks(mUnsetPressedState); 11336 } 11337 } 11338 11339 /** 11340 * Remove the tap detection timer. 11341 */ removeTapCallback()11342 private void removeTapCallback() { 11343 if (mPendingCheckForTap != null) { 11344 mPrivateFlags &= ~PFLAG_PREPRESSED; 11345 removeCallbacks(mPendingCheckForTap); 11346 } 11347 } 11348 11349 /** 11350 * Cancels a pending long press. Your subclass can use this if you 11351 * want the context menu to come up if the user presses and holds 11352 * at the same place, but you don't want it to come up if they press 11353 * and then move around enough to cause scrolling. 11354 */ cancelLongPress()11355 public void cancelLongPress() { 11356 removeLongPressCallback(); 11357 11358 /* 11359 * The prepressed state handled by the tap callback is a display 11360 * construct, but the tap callback will post a long press callback 11361 * less its own timeout. Remove it here. 11362 */ 11363 removeTapCallback(); 11364 } 11365 11366 /** 11367 * Remove the pending callback for sending a 11368 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 11369 */ removeSendViewScrolledAccessibilityEventCallback()11370 private void removeSendViewScrolledAccessibilityEventCallback() { 11371 if (mSendViewScrolledAccessibilityEvent != null) { 11372 removeCallbacks(mSendViewScrolledAccessibilityEvent); 11373 mSendViewScrolledAccessibilityEvent.mIsPending = false; 11374 } 11375 } 11376 11377 /** 11378 * Sets the TouchDelegate for this View. 11379 */ setTouchDelegate(TouchDelegate delegate)11380 public void setTouchDelegate(TouchDelegate delegate) { 11381 mTouchDelegate = delegate; 11382 } 11383 11384 /** 11385 * Gets the TouchDelegate for this View. 11386 */ getTouchDelegate()11387 public TouchDelegate getTouchDelegate() { 11388 return mTouchDelegate; 11389 } 11390 11391 /** 11392 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 11393 * 11394 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 11395 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 11396 * available. This method should only be called for touch events. 11397 * 11398 * <p class="note">This api is not intended for most applications. Buffered dispatch 11399 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 11400 * streams will not improve your input latency. Side effects include: increased latency, 11401 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 11402 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 11403 * you.</p> 11404 */ requestUnbufferedDispatch(MotionEvent event)11405 public final void requestUnbufferedDispatch(MotionEvent event) { 11406 final int action = event.getAction(); 11407 if (mAttachInfo == null 11408 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 11409 || !event.isTouchEvent()) { 11410 return; 11411 } 11412 mAttachInfo.mUnbufferedDispatchRequested = true; 11413 } 11414 11415 /** 11416 * Set flags controlling behavior of this view. 11417 * 11418 * @param flags Constant indicating the value which should be set 11419 * @param mask Constant indicating the bit range that should be changed 11420 */ setFlags(int flags, int mask)11421 void setFlags(int flags, int mask) { 11422 final boolean accessibilityEnabled = 11423 AccessibilityManager.getInstance(mContext).isEnabled(); 11424 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 11425 11426 int old = mViewFlags; 11427 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 11428 11429 int changed = mViewFlags ^ old; 11430 if (changed == 0) { 11431 return; 11432 } 11433 int privateFlags = mPrivateFlags; 11434 11435 /* Check if the FOCUSABLE bit has changed */ 11436 if (((changed & FOCUSABLE_MASK) != 0) && 11437 ((privateFlags & PFLAG_HAS_BOUNDS) !=0)) { 11438 if (((old & FOCUSABLE_MASK) == FOCUSABLE) 11439 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 11440 /* Give up focus if we are no longer focusable */ 11441 clearFocus(); 11442 } else if (((old & FOCUSABLE_MASK) == NOT_FOCUSABLE) 11443 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 11444 /* 11445 * Tell the view system that we are now available to take focus 11446 * if no one else already has it. 11447 */ 11448 if (mParent != null) mParent.focusableViewAvailable(this); 11449 } 11450 } 11451 11452 final int newVisibility = flags & VISIBILITY_MASK; 11453 if (newVisibility == VISIBLE) { 11454 if ((changed & VISIBILITY_MASK) != 0) { 11455 /* 11456 * If this view is becoming visible, invalidate it in case it changed while 11457 * it was not visible. Marking it drawn ensures that the invalidation will 11458 * go through. 11459 */ 11460 mPrivateFlags |= PFLAG_DRAWN; 11461 invalidate(true); 11462 11463 needGlobalAttributesUpdate(true); 11464 11465 // a view becoming visible is worth notifying the parent 11466 // about in case nothing has focus. even if this specific view 11467 // isn't focusable, it may contain something that is, so let 11468 // the root view try to give this focus if nothing else does. 11469 if ((mParent != null) && (mBottom > mTop) && (mRight > mLeft)) { 11470 mParent.focusableViewAvailable(this); 11471 } 11472 } 11473 } 11474 11475 /* Check if the GONE bit has changed */ 11476 if ((changed & GONE) != 0) { 11477 needGlobalAttributesUpdate(false); 11478 requestLayout(); 11479 11480 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 11481 if (hasFocus()) clearFocus(); 11482 clearAccessibilityFocus(); 11483 destroyDrawingCache(); 11484 if (mParent instanceof View) { 11485 // GONE views noop invalidation, so invalidate the parent 11486 ((View) mParent).invalidate(true); 11487 } 11488 // Mark the view drawn to ensure that it gets invalidated properly the next 11489 // time it is visible and gets invalidated 11490 mPrivateFlags |= PFLAG_DRAWN; 11491 } 11492 if (mAttachInfo != null) { 11493 mAttachInfo.mViewVisibilityChanged = true; 11494 } 11495 } 11496 11497 /* Check if the VISIBLE bit has changed */ 11498 if ((changed & INVISIBLE) != 0) { 11499 needGlobalAttributesUpdate(false); 11500 /* 11501 * If this view is becoming invisible, set the DRAWN flag so that 11502 * the next invalidate() will not be skipped. 11503 */ 11504 mPrivateFlags |= PFLAG_DRAWN; 11505 11506 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 11507 // root view becoming invisible shouldn't clear focus and accessibility focus 11508 if (getRootView() != this) { 11509 if (hasFocus()) clearFocus(); 11510 clearAccessibilityFocus(); 11511 } 11512 } 11513 if (mAttachInfo != null) { 11514 mAttachInfo.mViewVisibilityChanged = true; 11515 } 11516 } 11517 11518 if ((changed & VISIBILITY_MASK) != 0) { 11519 // If the view is invisible, cleanup its display list to free up resources 11520 if (newVisibility != VISIBLE && mAttachInfo != null) { 11521 cleanupDraw(); 11522 } 11523 11524 if (mParent instanceof ViewGroup) { 11525 ((ViewGroup) mParent).onChildVisibilityChanged(this, 11526 (changed & VISIBILITY_MASK), newVisibility); 11527 ((View) mParent).invalidate(true); 11528 } else if (mParent != null) { 11529 mParent.invalidateChild(this, null); 11530 } 11531 11532 if (mAttachInfo != null) { 11533 dispatchVisibilityChanged(this, newVisibility); 11534 11535 // Aggregated visibility changes are dispatched to attached views 11536 // in visible windows where the parent is currently shown/drawn 11537 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 11538 // discounting clipping or overlapping. This makes it a good place 11539 // to change animation states. 11540 if (mParent != null && getWindowVisibility() == VISIBLE && 11541 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 11542 dispatchVisibilityAggregated(newVisibility == VISIBLE); 11543 } 11544 notifySubtreeAccessibilityStateChangedIfNeeded(); 11545 } 11546 } 11547 11548 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 11549 destroyDrawingCache(); 11550 } 11551 11552 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 11553 destroyDrawingCache(); 11554 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 11555 invalidateParentCaches(); 11556 } 11557 11558 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 11559 destroyDrawingCache(); 11560 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 11561 } 11562 11563 if ((changed & DRAW_MASK) != 0) { 11564 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 11565 if (mBackground != null 11566 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 11567 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 11568 } else { 11569 mPrivateFlags |= PFLAG_SKIP_DRAW; 11570 } 11571 } else { 11572 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 11573 } 11574 requestLayout(); 11575 invalidate(true); 11576 } 11577 11578 if ((changed & KEEP_SCREEN_ON) != 0) { 11579 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 11580 mParent.recomputeViewAttributes(this); 11581 } 11582 } 11583 11584 if (accessibilityEnabled) { 11585 if ((changed & FOCUSABLE_MASK) != 0 || (changed & VISIBILITY_MASK) != 0 11586 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 11587 || (changed & CONTEXT_CLICKABLE) != 0) { 11588 if (oldIncludeForAccessibility != includeForAccessibility()) { 11589 notifySubtreeAccessibilityStateChangedIfNeeded(); 11590 } else { 11591 notifyViewAccessibilityStateChangedIfNeeded( 11592 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11593 } 11594 } else if ((changed & ENABLED_MASK) != 0) { 11595 notifyViewAccessibilityStateChangedIfNeeded( 11596 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11597 } 11598 } 11599 } 11600 11601 /** 11602 * Change the view's z order in the tree, so it's on top of other sibling 11603 * views. This ordering change may affect layout, if the parent container 11604 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 11605 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 11606 * method should be followed by calls to {@link #requestLayout()} and 11607 * {@link View#invalidate()} on the view's parent to force the parent to redraw 11608 * with the new child ordering. 11609 * 11610 * @see ViewGroup#bringChildToFront(View) 11611 */ bringToFront()11612 public void bringToFront() { 11613 if (mParent != null) { 11614 mParent.bringChildToFront(this); 11615 } 11616 } 11617 11618 /** 11619 * This is called in response to an internal scroll in this view (i.e., the 11620 * view scrolled its own contents). This is typically as a result of 11621 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 11622 * called. 11623 * 11624 * @param l Current horizontal scroll origin. 11625 * @param t Current vertical scroll origin. 11626 * @param oldl Previous horizontal scroll origin. 11627 * @param oldt Previous vertical scroll origin. 11628 */ onScrollChanged(int l, int t, int oldl, int oldt)11629 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 11630 notifySubtreeAccessibilityStateChangedIfNeeded(); 11631 11632 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 11633 postSendViewScrolledAccessibilityEventCallback(); 11634 } 11635 11636 mBackgroundSizeChanged = true; 11637 if (mForegroundInfo != null) { 11638 mForegroundInfo.mBoundsChanged = true; 11639 } 11640 11641 final AttachInfo ai = mAttachInfo; 11642 if (ai != null) { 11643 ai.mViewScrollChanged = true; 11644 } 11645 11646 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 11647 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 11648 } 11649 } 11650 11651 /** 11652 * Interface definition for a callback to be invoked when the scroll 11653 * X or Y positions of a view change. 11654 * <p> 11655 * <b>Note:</b> Some views handle scrolling independently from View and may 11656 * have their own separate listeners for scroll-type events. For example, 11657 * {@link android.widget.ListView ListView} allows clients to register an 11658 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 11659 * to listen for changes in list scroll position. 11660 * 11661 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 11662 */ 11663 public interface OnScrollChangeListener { 11664 /** 11665 * Called when the scroll position of a view changes. 11666 * 11667 * @param v The view whose scroll position has changed. 11668 * @param scrollX Current horizontal scroll origin. 11669 * @param scrollY Current vertical scroll origin. 11670 * @param oldScrollX Previous horizontal scroll origin. 11671 * @param oldScrollY Previous vertical scroll origin. 11672 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)11673 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 11674 } 11675 11676 /** 11677 * Interface definition for a callback to be invoked when the layout bounds of a view 11678 * changes due to layout processing. 11679 */ 11680 public interface OnLayoutChangeListener { 11681 /** 11682 * Called when the layout bounds of a view changes due to layout processing. 11683 * 11684 * @param v The view whose bounds have changed. 11685 * @param left The new value of the view's left property. 11686 * @param top The new value of the view's top property. 11687 * @param right The new value of the view's right property. 11688 * @param bottom The new value of the view's bottom property. 11689 * @param oldLeft The previous value of the view's left property. 11690 * @param oldTop The previous value of the view's top property. 11691 * @param oldRight The previous value of the view's right property. 11692 * @param oldBottom The previous value of the view's bottom property. 11693 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)11694 void onLayoutChange(View v, int left, int top, int right, int bottom, 11695 int oldLeft, int oldTop, int oldRight, int oldBottom); 11696 } 11697 11698 /** 11699 * This is called during layout when the size of this view has changed. If 11700 * you were just added to the view hierarchy, you're called with the old 11701 * values of 0. 11702 * 11703 * @param w Current width of this view. 11704 * @param h Current height of this view. 11705 * @param oldw Old width of this view. 11706 * @param oldh Old height of this view. 11707 */ onSizeChanged(int w, int h, int oldw, int oldh)11708 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 11709 } 11710 11711 /** 11712 * Called by draw to draw the child views. This may be overridden 11713 * by derived classes to gain control just before its children are drawn 11714 * (but after its own view has been drawn). 11715 * @param canvas the canvas on which to draw the view 11716 */ dispatchDraw(Canvas canvas)11717 protected void dispatchDraw(Canvas canvas) { 11718 11719 } 11720 11721 /** 11722 * Gets the parent of this view. Note that the parent is a 11723 * ViewParent and not necessarily a View. 11724 * 11725 * @return Parent of this view. 11726 */ getParent()11727 public final ViewParent getParent() { 11728 return mParent; 11729 } 11730 11731 /** 11732 * Set the horizontal scrolled position of your view. This will cause a call to 11733 * {@link #onScrollChanged(int, int, int, int)} and the view will be 11734 * invalidated. 11735 * @param value the x position to scroll to 11736 */ setScrollX(int value)11737 public void setScrollX(int value) { 11738 scrollTo(value, mScrollY); 11739 } 11740 11741 /** 11742 * Set the vertical scrolled position of your view. This will cause a call to 11743 * {@link #onScrollChanged(int, int, int, int)} and the view will be 11744 * invalidated. 11745 * @param value the y position to scroll to 11746 */ setScrollY(int value)11747 public void setScrollY(int value) { 11748 scrollTo(mScrollX, value); 11749 } 11750 11751 /** 11752 * Return the scrolled left position of this view. This is the left edge of 11753 * the displayed part of your view. You do not need to draw any pixels 11754 * farther left, since those are outside of the frame of your view on 11755 * screen. 11756 * 11757 * @return The left edge of the displayed part of your view, in pixels. 11758 */ getScrollX()11759 public final int getScrollX() { 11760 return mScrollX; 11761 } 11762 11763 /** 11764 * Return the scrolled top position of this view. This is the top edge of 11765 * the displayed part of your view. You do not need to draw any pixels above 11766 * it, since those are outside of the frame of your view on screen. 11767 * 11768 * @return The top edge of the displayed part of your view, in pixels. 11769 */ getScrollY()11770 public final int getScrollY() { 11771 return mScrollY; 11772 } 11773 11774 /** 11775 * Return the width of the your view. 11776 * 11777 * @return The width of your view, in pixels. 11778 */ 11779 @ViewDebug.ExportedProperty(category = "layout") getWidth()11780 public final int getWidth() { 11781 return mRight - mLeft; 11782 } 11783 11784 /** 11785 * Return the height of your view. 11786 * 11787 * @return The height of your view, in pixels. 11788 */ 11789 @ViewDebug.ExportedProperty(category = "layout") getHeight()11790 public final int getHeight() { 11791 return mBottom - mTop; 11792 } 11793 11794 /** 11795 * Return the visible drawing bounds of your view. Fills in the output 11796 * rectangle with the values from getScrollX(), getScrollY(), 11797 * getWidth(), and getHeight(). These bounds do not account for any 11798 * transformation properties currently set on the view, such as 11799 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 11800 * 11801 * @param outRect The (scrolled) drawing bounds of the view. 11802 */ getDrawingRect(Rect outRect)11803 public void getDrawingRect(Rect outRect) { 11804 outRect.left = mScrollX; 11805 outRect.top = mScrollY; 11806 outRect.right = mScrollX + (mRight - mLeft); 11807 outRect.bottom = mScrollY + (mBottom - mTop); 11808 } 11809 11810 /** 11811 * Like {@link #getMeasuredWidthAndState()}, but only returns the 11812 * raw width component (that is the result is masked by 11813 * {@link #MEASURED_SIZE_MASK}). 11814 * 11815 * @return The raw measured width of this view. 11816 */ getMeasuredWidth()11817 public final int getMeasuredWidth() { 11818 return mMeasuredWidth & MEASURED_SIZE_MASK; 11819 } 11820 11821 /** 11822 * Return the full width measurement information for this view as computed 11823 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 11824 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 11825 * This should be used during measurement and layout calculations only. Use 11826 * {@link #getWidth()} to see how wide a view is after layout. 11827 * 11828 * @return The measured width of this view as a bit mask. 11829 */ 11830 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 11831 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 11832 name = "MEASURED_STATE_TOO_SMALL"), 11833 }) getMeasuredWidthAndState()11834 public final int getMeasuredWidthAndState() { 11835 return mMeasuredWidth; 11836 } 11837 11838 /** 11839 * Like {@link #getMeasuredHeightAndState()}, but only returns the 11840 * raw width component (that is the result is masked by 11841 * {@link #MEASURED_SIZE_MASK}). 11842 * 11843 * @return The raw measured height of this view. 11844 */ getMeasuredHeight()11845 public final int getMeasuredHeight() { 11846 return mMeasuredHeight & MEASURED_SIZE_MASK; 11847 } 11848 11849 /** 11850 * Return the full height measurement information for this view as computed 11851 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 11852 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 11853 * This should be used during measurement and layout calculations only. Use 11854 * {@link #getHeight()} to see how wide a view is after layout. 11855 * 11856 * @return The measured width of this view as a bit mask. 11857 */ 11858 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 11859 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 11860 name = "MEASURED_STATE_TOO_SMALL"), 11861 }) getMeasuredHeightAndState()11862 public final int getMeasuredHeightAndState() { 11863 return mMeasuredHeight; 11864 } 11865 11866 /** 11867 * Return only the state bits of {@link #getMeasuredWidthAndState()} 11868 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 11869 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 11870 * and the height component is at the shifted bits 11871 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 11872 */ getMeasuredState()11873 public final int getMeasuredState() { 11874 return (mMeasuredWidth&MEASURED_STATE_MASK) 11875 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 11876 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 11877 } 11878 11879 /** 11880 * The transform matrix of this view, which is calculated based on the current 11881 * rotation, scale, and pivot properties. 11882 * 11883 * @see #getRotation() 11884 * @see #getScaleX() 11885 * @see #getScaleY() 11886 * @see #getPivotX() 11887 * @see #getPivotY() 11888 * @return The current transform matrix for the view 11889 */ getMatrix()11890 public Matrix getMatrix() { 11891 ensureTransformationInfo(); 11892 final Matrix matrix = mTransformationInfo.mMatrix; 11893 mRenderNode.getMatrix(matrix); 11894 return matrix; 11895 } 11896 11897 /** 11898 * Returns true if the transform matrix is the identity matrix. 11899 * Recomputes the matrix if necessary. 11900 * 11901 * @return True if the transform matrix is the identity matrix, false otherwise. 11902 */ hasIdentityMatrix()11903 final boolean hasIdentityMatrix() { 11904 return mRenderNode.hasIdentityMatrix(); 11905 } 11906 ensureTransformationInfo()11907 void ensureTransformationInfo() { 11908 if (mTransformationInfo == null) { 11909 mTransformationInfo = new TransformationInfo(); 11910 } 11911 } 11912 11913 /** 11914 * Utility method to retrieve the inverse of the current mMatrix property. 11915 * We cache the matrix to avoid recalculating it when transform properties 11916 * have not changed. 11917 * 11918 * @return The inverse of the current matrix of this view. 11919 * @hide 11920 */ getInverseMatrix()11921 public final Matrix getInverseMatrix() { 11922 ensureTransformationInfo(); 11923 if (mTransformationInfo.mInverseMatrix == null) { 11924 mTransformationInfo.mInverseMatrix = new Matrix(); 11925 } 11926 final Matrix matrix = mTransformationInfo.mInverseMatrix; 11927 mRenderNode.getInverseMatrix(matrix); 11928 return matrix; 11929 } 11930 11931 /** 11932 * Gets the distance along the Z axis from the camera to this view. 11933 * 11934 * @see #setCameraDistance(float) 11935 * 11936 * @return The distance along the Z axis. 11937 */ getCameraDistance()11938 public float getCameraDistance() { 11939 final float dpi = mResources.getDisplayMetrics().densityDpi; 11940 return -(mRenderNode.getCameraDistance() * dpi); 11941 } 11942 11943 /** 11944 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 11945 * views are drawn) from the camera to this view. The camera's distance 11946 * affects 3D transformations, for instance rotations around the X and Y 11947 * axis. If the rotationX or rotationY properties are changed and this view is 11948 * large (more than half the size of the screen), it is recommended to always 11949 * use a camera distance that's greater than the height (X axis rotation) or 11950 * the width (Y axis rotation) of this view.</p> 11951 * 11952 * <p>The distance of the camera from the view plane can have an affect on the 11953 * perspective distortion of the view when it is rotated around the x or y axis. 11954 * For example, a large distance will result in a large viewing angle, and there 11955 * will not be much perspective distortion of the view as it rotates. A short 11956 * distance may cause much more perspective distortion upon rotation, and can 11957 * also result in some drawing artifacts if the rotated view ends up partially 11958 * behind the camera (which is why the recommendation is to use a distance at 11959 * least as far as the size of the view, if the view is to be rotated.)</p> 11960 * 11961 * <p>The distance is expressed in "depth pixels." The default distance depends 11962 * on the screen density. For instance, on a medium density display, the 11963 * default distance is 1280. On a high density display, the default distance 11964 * is 1920.</p> 11965 * 11966 * <p>If you want to specify a distance that leads to visually consistent 11967 * results across various densities, use the following formula:</p> 11968 * <pre> 11969 * float scale = context.getResources().getDisplayMetrics().density; 11970 * view.setCameraDistance(distance * scale); 11971 * </pre> 11972 * 11973 * <p>The density scale factor of a high density display is 1.5, 11974 * and 1920 = 1280 * 1.5.</p> 11975 * 11976 * @param distance The distance in "depth pixels", if negative the opposite 11977 * value is used 11978 * 11979 * @see #setRotationX(float) 11980 * @see #setRotationY(float) 11981 */ setCameraDistance(float distance)11982 public void setCameraDistance(float distance) { 11983 final float dpi = mResources.getDisplayMetrics().densityDpi; 11984 11985 invalidateViewProperty(true, false); 11986 mRenderNode.setCameraDistance(-Math.abs(distance) / dpi); 11987 invalidateViewProperty(false, false); 11988 11989 invalidateParentIfNeededAndWasQuickRejected(); 11990 } 11991 11992 /** 11993 * The degrees that the view is rotated around the pivot point. 11994 * 11995 * @see #setRotation(float) 11996 * @see #getPivotX() 11997 * @see #getPivotY() 11998 * 11999 * @return The degrees of rotation. 12000 */ 12001 @ViewDebug.ExportedProperty(category = "drawing") getRotation()12002 public float getRotation() { 12003 return mRenderNode.getRotation(); 12004 } 12005 12006 /** 12007 * Sets the degrees that the view is rotated around the pivot point. Increasing values 12008 * result in clockwise rotation. 12009 * 12010 * @param rotation The degrees of rotation. 12011 * 12012 * @see #getRotation() 12013 * @see #getPivotX() 12014 * @see #getPivotY() 12015 * @see #setRotationX(float) 12016 * @see #setRotationY(float) 12017 * 12018 * @attr ref android.R.styleable#View_rotation 12019 */ setRotation(float rotation)12020 public void setRotation(float rotation) { 12021 if (rotation != getRotation()) { 12022 // Double-invalidation is necessary to capture view's old and new areas 12023 invalidateViewProperty(true, false); 12024 mRenderNode.setRotation(rotation); 12025 invalidateViewProperty(false, true); 12026 12027 invalidateParentIfNeededAndWasQuickRejected(); 12028 notifySubtreeAccessibilityStateChangedIfNeeded(); 12029 } 12030 } 12031 12032 /** 12033 * The degrees that the view is rotated around the vertical axis through the pivot point. 12034 * 12035 * @see #getPivotX() 12036 * @see #getPivotY() 12037 * @see #setRotationY(float) 12038 * 12039 * @return The degrees of Y rotation. 12040 */ 12041 @ViewDebug.ExportedProperty(category = "drawing") getRotationY()12042 public float getRotationY() { 12043 return mRenderNode.getRotationY(); 12044 } 12045 12046 /** 12047 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 12048 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 12049 * down the y axis. 12050 * 12051 * When rotating large views, it is recommended to adjust the camera distance 12052 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12053 * 12054 * @param rotationY The degrees of Y rotation. 12055 * 12056 * @see #getRotationY() 12057 * @see #getPivotX() 12058 * @see #getPivotY() 12059 * @see #setRotation(float) 12060 * @see #setRotationX(float) 12061 * @see #setCameraDistance(float) 12062 * 12063 * @attr ref android.R.styleable#View_rotationY 12064 */ setRotationY(float rotationY)12065 public void setRotationY(float rotationY) { 12066 if (rotationY != getRotationY()) { 12067 invalidateViewProperty(true, false); 12068 mRenderNode.setRotationY(rotationY); 12069 invalidateViewProperty(false, true); 12070 12071 invalidateParentIfNeededAndWasQuickRejected(); 12072 notifySubtreeAccessibilityStateChangedIfNeeded(); 12073 } 12074 } 12075 12076 /** 12077 * The degrees that the view is rotated around the horizontal axis through the pivot point. 12078 * 12079 * @see #getPivotX() 12080 * @see #getPivotY() 12081 * @see #setRotationX(float) 12082 * 12083 * @return The degrees of X rotation. 12084 */ 12085 @ViewDebug.ExportedProperty(category = "drawing") getRotationX()12086 public float getRotationX() { 12087 return mRenderNode.getRotationX(); 12088 } 12089 12090 /** 12091 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 12092 * Increasing values result in clockwise rotation from the viewpoint of looking down the 12093 * x axis. 12094 * 12095 * When rotating large views, it is recommended to adjust the camera distance 12096 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 12097 * 12098 * @param rotationX The degrees of X rotation. 12099 * 12100 * @see #getRotationX() 12101 * @see #getPivotX() 12102 * @see #getPivotY() 12103 * @see #setRotation(float) 12104 * @see #setRotationY(float) 12105 * @see #setCameraDistance(float) 12106 * 12107 * @attr ref android.R.styleable#View_rotationX 12108 */ setRotationX(float rotationX)12109 public void setRotationX(float rotationX) { 12110 if (rotationX != getRotationX()) { 12111 invalidateViewProperty(true, false); 12112 mRenderNode.setRotationX(rotationX); 12113 invalidateViewProperty(false, true); 12114 12115 invalidateParentIfNeededAndWasQuickRejected(); 12116 notifySubtreeAccessibilityStateChangedIfNeeded(); 12117 } 12118 } 12119 12120 /** 12121 * The amount that the view is scaled in x around the pivot point, as a proportion of 12122 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 12123 * 12124 * <p>By default, this is 1.0f. 12125 * 12126 * @see #getPivotX() 12127 * @see #getPivotY() 12128 * @return The scaling factor. 12129 */ 12130 @ViewDebug.ExportedProperty(category = "drawing") getScaleX()12131 public float getScaleX() { 12132 return mRenderNode.getScaleX(); 12133 } 12134 12135 /** 12136 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 12137 * the view's unscaled width. A value of 1 means that no scaling is applied. 12138 * 12139 * @param scaleX The scaling factor. 12140 * @see #getPivotX() 12141 * @see #getPivotY() 12142 * 12143 * @attr ref android.R.styleable#View_scaleX 12144 */ setScaleX(float scaleX)12145 public void setScaleX(float scaleX) { 12146 if (scaleX != getScaleX()) { 12147 invalidateViewProperty(true, false); 12148 mRenderNode.setScaleX(scaleX); 12149 invalidateViewProperty(false, true); 12150 12151 invalidateParentIfNeededAndWasQuickRejected(); 12152 notifySubtreeAccessibilityStateChangedIfNeeded(); 12153 } 12154 } 12155 12156 /** 12157 * The amount that the view is scaled in y around the pivot point, as a proportion of 12158 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 12159 * 12160 * <p>By default, this is 1.0f. 12161 * 12162 * @see #getPivotX() 12163 * @see #getPivotY() 12164 * @return The scaling factor. 12165 */ 12166 @ViewDebug.ExportedProperty(category = "drawing") getScaleY()12167 public float getScaleY() { 12168 return mRenderNode.getScaleY(); 12169 } 12170 12171 /** 12172 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 12173 * the view's unscaled width. A value of 1 means that no scaling is applied. 12174 * 12175 * @param scaleY The scaling factor. 12176 * @see #getPivotX() 12177 * @see #getPivotY() 12178 * 12179 * @attr ref android.R.styleable#View_scaleY 12180 */ setScaleY(float scaleY)12181 public void setScaleY(float scaleY) { 12182 if (scaleY != getScaleY()) { 12183 invalidateViewProperty(true, false); 12184 mRenderNode.setScaleY(scaleY); 12185 invalidateViewProperty(false, true); 12186 12187 invalidateParentIfNeededAndWasQuickRejected(); 12188 notifySubtreeAccessibilityStateChangedIfNeeded(); 12189 } 12190 } 12191 12192 /** 12193 * The x location of the point around which the view is {@link #setRotation(float) rotated} 12194 * and {@link #setScaleX(float) scaled}. 12195 * 12196 * @see #getRotation() 12197 * @see #getScaleX() 12198 * @see #getScaleY() 12199 * @see #getPivotY() 12200 * @return The x location of the pivot point. 12201 * 12202 * @attr ref android.R.styleable#View_transformPivotX 12203 */ 12204 @ViewDebug.ExportedProperty(category = "drawing") getPivotX()12205 public float getPivotX() { 12206 return mRenderNode.getPivotX(); 12207 } 12208 12209 /** 12210 * Sets the x location of the point around which the view is 12211 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 12212 * By default, the pivot point is centered on the object. 12213 * Setting this property disables this behavior and causes the view to use only the 12214 * explicitly set pivotX and pivotY values. 12215 * 12216 * @param pivotX The x location of the pivot point. 12217 * @see #getRotation() 12218 * @see #getScaleX() 12219 * @see #getScaleY() 12220 * @see #getPivotY() 12221 * 12222 * @attr ref android.R.styleable#View_transformPivotX 12223 */ setPivotX(float pivotX)12224 public void setPivotX(float pivotX) { 12225 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 12226 invalidateViewProperty(true, false); 12227 mRenderNode.setPivotX(pivotX); 12228 invalidateViewProperty(false, true); 12229 12230 invalidateParentIfNeededAndWasQuickRejected(); 12231 } 12232 } 12233 12234 /** 12235 * The y location of the point around which the view is {@link #setRotation(float) rotated} 12236 * and {@link #setScaleY(float) scaled}. 12237 * 12238 * @see #getRotation() 12239 * @see #getScaleX() 12240 * @see #getScaleY() 12241 * @see #getPivotY() 12242 * @return The y location of the pivot point. 12243 * 12244 * @attr ref android.R.styleable#View_transformPivotY 12245 */ 12246 @ViewDebug.ExportedProperty(category = "drawing") getPivotY()12247 public float getPivotY() { 12248 return mRenderNode.getPivotY(); 12249 } 12250 12251 /** 12252 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 12253 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 12254 * Setting this property disables this behavior and causes the view to use only the 12255 * explicitly set pivotX and pivotY values. 12256 * 12257 * @param pivotY The y location of the pivot point. 12258 * @see #getRotation() 12259 * @see #getScaleX() 12260 * @see #getScaleY() 12261 * @see #getPivotY() 12262 * 12263 * @attr ref android.R.styleable#View_transformPivotY 12264 */ setPivotY(float pivotY)12265 public void setPivotY(float pivotY) { 12266 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 12267 invalidateViewProperty(true, false); 12268 mRenderNode.setPivotY(pivotY); 12269 invalidateViewProperty(false, true); 12270 12271 invalidateParentIfNeededAndWasQuickRejected(); 12272 } 12273 } 12274 12275 /** 12276 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 12277 * completely transparent and 1 means the view is completely opaque. 12278 * 12279 * <p>By default this is 1.0f. 12280 * @return The opacity of the view. 12281 */ 12282 @ViewDebug.ExportedProperty(category = "drawing") getAlpha()12283 public float getAlpha() { 12284 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 12285 } 12286 12287 /** 12288 * Sets the behavior for overlapping rendering for this view (see {@link 12289 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 12290 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 12291 * providing the value which is then used internally. That is, when {@link 12292 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 12293 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 12294 * instead. 12295 * 12296 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 12297 * instead of that returned by {@link #hasOverlappingRendering()}. 12298 * 12299 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 12300 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)12301 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 12302 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 12303 if (hasOverlappingRendering) { 12304 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12305 } else { 12306 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 12307 } 12308 } 12309 12310 /** 12311 * Returns the value for overlapping rendering that is used internally. This is either 12312 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 12313 * the return value of {@link #hasOverlappingRendering()}, otherwise. 12314 * 12315 * @return The value for overlapping rendering being used internally. 12316 */ getHasOverlappingRendering()12317 public final boolean getHasOverlappingRendering() { 12318 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 12319 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 12320 hasOverlappingRendering(); 12321 } 12322 12323 /** 12324 * Returns whether this View has content which overlaps. 12325 * 12326 * <p>This function, intended to be overridden by specific View types, is an optimization when 12327 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 12328 * an offscreen buffer and then composited into place, which can be expensive. If the view has 12329 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 12330 * directly. An example of overlapping rendering is a TextView with a background image, such as 12331 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 12332 * ImageView with only the foreground image. The default implementation returns true; subclasses 12333 * should override if they have cases which can be optimized.</p> 12334 * 12335 * <p>The current implementation of the saveLayer and saveLayerAlpha methods in {@link Canvas} 12336 * necessitates that a View return true if it uses the methods internally without passing the 12337 * {@link Canvas#CLIP_TO_LAYER_SAVE_FLAG}.</p> 12338 * 12339 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 12340 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 12341 * 12342 * @return true if the content in this view might overlap, false otherwise. 12343 */ 12344 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()12345 public boolean hasOverlappingRendering() { 12346 return true; 12347 } 12348 12349 /** 12350 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 12351 * completely transparent and 1 means the view is completely opaque. 12352 * 12353 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 12354 * can have significant performance implications, especially for large views. It is best to use 12355 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 12356 * 12357 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 12358 * strongly recommended for performance reasons to either override 12359 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 12360 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 12361 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 12362 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 12363 * of rendering cost, even for simple or small views. Starting with 12364 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 12365 * applied to the view at the rendering level.</p> 12366 * 12367 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 12368 * responsible for applying the opacity itself.</p> 12369 * 12370 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 12371 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 12372 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 12373 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 12374 * 12375 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 12376 * value will clip a View to its bounds, unless the View returns <code>false</code> from 12377 * {@link #hasOverlappingRendering}.</p> 12378 * 12379 * @param alpha The opacity of the view. 12380 * 12381 * @see #hasOverlappingRendering() 12382 * @see #setLayerType(int, android.graphics.Paint) 12383 * 12384 * @attr ref android.R.styleable#View_alpha 12385 */ setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)12386 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 12387 ensureTransformationInfo(); 12388 if (mTransformationInfo.mAlpha != alpha) { 12389 // Report visibility changes, which can affect children, to accessibility 12390 if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) { 12391 notifySubtreeAccessibilityStateChangedIfNeeded(); 12392 } 12393 mTransformationInfo.mAlpha = alpha; 12394 if (onSetAlpha((int) (alpha * 255))) { 12395 mPrivateFlags |= PFLAG_ALPHA_SET; 12396 // subclass is handling alpha - don't optimize rendering cache invalidation 12397 invalidateParentCaches(); 12398 invalidate(true); 12399 } else { 12400 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12401 invalidateViewProperty(true, false); 12402 mRenderNode.setAlpha(getFinalAlpha()); 12403 } 12404 } 12405 } 12406 12407 /** 12408 * Faster version of setAlpha() which performs the same steps except there are 12409 * no calls to invalidate(). The caller of this function should perform proper invalidation 12410 * on the parent and this object. The return value indicates whether the subclass handles 12411 * alpha (the return value for onSetAlpha()). 12412 * 12413 * @param alpha The new value for the alpha property 12414 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 12415 * the new value for the alpha property is different from the old value 12416 */ setAlphaNoInvalidation(float alpha)12417 boolean setAlphaNoInvalidation(float alpha) { 12418 ensureTransformationInfo(); 12419 if (mTransformationInfo.mAlpha != alpha) { 12420 mTransformationInfo.mAlpha = alpha; 12421 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 12422 if (subclassHandlesAlpha) { 12423 mPrivateFlags |= PFLAG_ALPHA_SET; 12424 return true; 12425 } else { 12426 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12427 mRenderNode.setAlpha(getFinalAlpha()); 12428 } 12429 } 12430 return false; 12431 } 12432 12433 /** 12434 * This property is hidden and intended only for use by the Fade transition, which 12435 * animates it to produce a visual translucency that does not side-effect (or get 12436 * affected by) the real alpha property. This value is composited with the other 12437 * alpha value (and the AlphaAnimation value, when that is present) to produce 12438 * a final visual translucency result, which is what is passed into the DisplayList. 12439 * 12440 * @hide 12441 */ setTransitionAlpha(float alpha)12442 public void setTransitionAlpha(float alpha) { 12443 ensureTransformationInfo(); 12444 if (mTransformationInfo.mTransitionAlpha != alpha) { 12445 mTransformationInfo.mTransitionAlpha = alpha; 12446 mPrivateFlags &= ~PFLAG_ALPHA_SET; 12447 invalidateViewProperty(true, false); 12448 mRenderNode.setAlpha(getFinalAlpha()); 12449 } 12450 } 12451 12452 /** 12453 * Calculates the visual alpha of this view, which is a combination of the actual 12454 * alpha value and the transitionAlpha value (if set). 12455 */ getFinalAlpha()12456 private float getFinalAlpha() { 12457 if (mTransformationInfo != null) { 12458 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 12459 } 12460 return 1; 12461 } 12462 12463 /** 12464 * This property is hidden and intended only for use by the Fade transition, which 12465 * animates it to produce a visual translucency that does not side-effect (or get 12466 * affected by) the real alpha property. This value is composited with the other 12467 * alpha value (and the AlphaAnimation value, when that is present) to produce 12468 * a final visual translucency result, which is what is passed into the DisplayList. 12469 * 12470 * @hide 12471 */ 12472 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()12473 public float getTransitionAlpha() { 12474 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 12475 } 12476 12477 /** 12478 * Top position of this view relative to its parent. 12479 * 12480 * @return The top of this view, in pixels. 12481 */ 12482 @ViewDebug.CapturedViewProperty getTop()12483 public final int getTop() { 12484 return mTop; 12485 } 12486 12487 /** 12488 * Sets the top position of this view relative to its parent. This method is meant to be called 12489 * by the layout system and should not generally be called otherwise, because the property 12490 * may be changed at any time by the layout. 12491 * 12492 * @param top The top of this view, in pixels. 12493 */ setTop(int top)12494 public final void setTop(int top) { 12495 if (top != mTop) { 12496 final boolean matrixIsIdentity = hasIdentityMatrix(); 12497 if (matrixIsIdentity) { 12498 if (mAttachInfo != null) { 12499 int minTop; 12500 int yLoc; 12501 if (top < mTop) { 12502 minTop = top; 12503 yLoc = top - mTop; 12504 } else { 12505 minTop = mTop; 12506 yLoc = 0; 12507 } 12508 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 12509 } 12510 } else { 12511 // Double-invalidation is necessary to capture view's old and new areas 12512 invalidate(true); 12513 } 12514 12515 int width = mRight - mLeft; 12516 int oldHeight = mBottom - mTop; 12517 12518 mTop = top; 12519 mRenderNode.setTop(mTop); 12520 12521 sizeChange(width, mBottom - mTop, width, oldHeight); 12522 12523 if (!matrixIsIdentity) { 12524 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 12525 invalidate(true); 12526 } 12527 mBackgroundSizeChanged = true; 12528 if (mForegroundInfo != null) { 12529 mForegroundInfo.mBoundsChanged = true; 12530 } 12531 invalidateParentIfNeeded(); 12532 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 12533 // View was rejected last time it was drawn by its parent; this may have changed 12534 invalidateParentIfNeeded(); 12535 } 12536 } 12537 } 12538 12539 /** 12540 * Bottom position of this view relative to its parent. 12541 * 12542 * @return The bottom of this view, in pixels. 12543 */ 12544 @ViewDebug.CapturedViewProperty getBottom()12545 public final int getBottom() { 12546 return mBottom; 12547 } 12548 12549 /** 12550 * True if this view has changed since the last time being drawn. 12551 * 12552 * @return The dirty state of this view. 12553 */ isDirty()12554 public boolean isDirty() { 12555 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 12556 } 12557 12558 /** 12559 * Sets the bottom position of this view relative to its parent. This method is meant to be 12560 * called by the layout system and should not generally be called otherwise, because the 12561 * property may be changed at any time by the layout. 12562 * 12563 * @param bottom The bottom of this view, in pixels. 12564 */ setBottom(int bottom)12565 public final void setBottom(int bottom) { 12566 if (bottom != mBottom) { 12567 final boolean matrixIsIdentity = hasIdentityMatrix(); 12568 if (matrixIsIdentity) { 12569 if (mAttachInfo != null) { 12570 int maxBottom; 12571 if (bottom < mBottom) { 12572 maxBottom = mBottom; 12573 } else { 12574 maxBottom = bottom; 12575 } 12576 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 12577 } 12578 } else { 12579 // Double-invalidation is necessary to capture view's old and new areas 12580 invalidate(true); 12581 } 12582 12583 int width = mRight - mLeft; 12584 int oldHeight = mBottom - mTop; 12585 12586 mBottom = bottom; 12587 mRenderNode.setBottom(mBottom); 12588 12589 sizeChange(width, mBottom - mTop, width, oldHeight); 12590 12591 if (!matrixIsIdentity) { 12592 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 12593 invalidate(true); 12594 } 12595 mBackgroundSizeChanged = true; 12596 if (mForegroundInfo != null) { 12597 mForegroundInfo.mBoundsChanged = true; 12598 } 12599 invalidateParentIfNeeded(); 12600 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 12601 // View was rejected last time it was drawn by its parent; this may have changed 12602 invalidateParentIfNeeded(); 12603 } 12604 } 12605 } 12606 12607 /** 12608 * Left position of this view relative to its parent. 12609 * 12610 * @return The left edge of this view, in pixels. 12611 */ 12612 @ViewDebug.CapturedViewProperty getLeft()12613 public final int getLeft() { 12614 return mLeft; 12615 } 12616 12617 /** 12618 * Sets the left position of this view relative to its parent. This method is meant to be called 12619 * by the layout system and should not generally be called otherwise, because the property 12620 * may be changed at any time by the layout. 12621 * 12622 * @param left The left of this view, in pixels. 12623 */ setLeft(int left)12624 public final void setLeft(int left) { 12625 if (left != mLeft) { 12626 final boolean matrixIsIdentity = hasIdentityMatrix(); 12627 if (matrixIsIdentity) { 12628 if (mAttachInfo != null) { 12629 int minLeft; 12630 int xLoc; 12631 if (left < mLeft) { 12632 minLeft = left; 12633 xLoc = left - mLeft; 12634 } else { 12635 minLeft = mLeft; 12636 xLoc = 0; 12637 } 12638 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 12639 } 12640 } else { 12641 // Double-invalidation is necessary to capture view's old and new areas 12642 invalidate(true); 12643 } 12644 12645 int oldWidth = mRight - mLeft; 12646 int height = mBottom - mTop; 12647 12648 mLeft = left; 12649 mRenderNode.setLeft(left); 12650 12651 sizeChange(mRight - mLeft, height, oldWidth, height); 12652 12653 if (!matrixIsIdentity) { 12654 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 12655 invalidate(true); 12656 } 12657 mBackgroundSizeChanged = true; 12658 if (mForegroundInfo != null) { 12659 mForegroundInfo.mBoundsChanged = true; 12660 } 12661 invalidateParentIfNeeded(); 12662 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 12663 // View was rejected last time it was drawn by its parent; this may have changed 12664 invalidateParentIfNeeded(); 12665 } 12666 } 12667 } 12668 12669 /** 12670 * Right position of this view relative to its parent. 12671 * 12672 * @return The right edge of this view, in pixels. 12673 */ 12674 @ViewDebug.CapturedViewProperty getRight()12675 public final int getRight() { 12676 return mRight; 12677 } 12678 12679 /** 12680 * Sets the right position of this view relative to its parent. This method is meant to be called 12681 * by the layout system and should not generally be called otherwise, because the property 12682 * may be changed at any time by the layout. 12683 * 12684 * @param right The right of this view, in pixels. 12685 */ setRight(int right)12686 public final void setRight(int right) { 12687 if (right != mRight) { 12688 final boolean matrixIsIdentity = hasIdentityMatrix(); 12689 if (matrixIsIdentity) { 12690 if (mAttachInfo != null) { 12691 int maxRight; 12692 if (right < mRight) { 12693 maxRight = mRight; 12694 } else { 12695 maxRight = right; 12696 } 12697 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 12698 } 12699 } else { 12700 // Double-invalidation is necessary to capture view's old and new areas 12701 invalidate(true); 12702 } 12703 12704 int oldWidth = mRight - mLeft; 12705 int height = mBottom - mTop; 12706 12707 mRight = right; 12708 mRenderNode.setRight(mRight); 12709 12710 sizeChange(mRight - mLeft, height, oldWidth, height); 12711 12712 if (!matrixIsIdentity) { 12713 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 12714 invalidate(true); 12715 } 12716 mBackgroundSizeChanged = true; 12717 if (mForegroundInfo != null) { 12718 mForegroundInfo.mBoundsChanged = true; 12719 } 12720 invalidateParentIfNeeded(); 12721 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 12722 // View was rejected last time it was drawn by its parent; this may have changed 12723 invalidateParentIfNeeded(); 12724 } 12725 } 12726 } 12727 12728 /** 12729 * The visual x position of this view, in pixels. This is equivalent to the 12730 * {@link #setTranslationX(float) translationX} property plus the current 12731 * {@link #getLeft() left} property. 12732 * 12733 * @return The visual x position of this view, in pixels. 12734 */ 12735 @ViewDebug.ExportedProperty(category = "drawing") getX()12736 public float getX() { 12737 return mLeft + getTranslationX(); 12738 } 12739 12740 /** 12741 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 12742 * {@link #setTranslationX(float) translationX} property to be the difference between 12743 * the x value passed in and the current {@link #getLeft() left} property. 12744 * 12745 * @param x The visual x position of this view, in pixels. 12746 */ setX(float x)12747 public void setX(float x) { 12748 setTranslationX(x - mLeft); 12749 } 12750 12751 /** 12752 * The visual y position of this view, in pixels. This is equivalent to the 12753 * {@link #setTranslationY(float) translationY} property plus the current 12754 * {@link #getTop() top} property. 12755 * 12756 * @return The visual y position of this view, in pixels. 12757 */ 12758 @ViewDebug.ExportedProperty(category = "drawing") getY()12759 public float getY() { 12760 return mTop + getTranslationY(); 12761 } 12762 12763 /** 12764 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 12765 * {@link #setTranslationY(float) translationY} property to be the difference between 12766 * the y value passed in and the current {@link #getTop() top} property. 12767 * 12768 * @param y The visual y position of this view, in pixels. 12769 */ setY(float y)12770 public void setY(float y) { 12771 setTranslationY(y - mTop); 12772 } 12773 12774 /** 12775 * The visual z position of this view, in pixels. This is equivalent to the 12776 * {@link #setTranslationZ(float) translationZ} property plus the current 12777 * {@link #getElevation() elevation} property. 12778 * 12779 * @return The visual z position of this view, in pixels. 12780 */ 12781 @ViewDebug.ExportedProperty(category = "drawing") getZ()12782 public float getZ() { 12783 return getElevation() + getTranslationZ(); 12784 } 12785 12786 /** 12787 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 12788 * {@link #setTranslationZ(float) translationZ} property to be the difference between 12789 * the x value passed in and the current {@link #getElevation() elevation} property. 12790 * 12791 * @param z The visual z position of this view, in pixels. 12792 */ setZ(float z)12793 public void setZ(float z) { 12794 setTranslationZ(z - getElevation()); 12795 } 12796 12797 /** 12798 * The base elevation of this view relative to its parent, in pixels. 12799 * 12800 * @return The base depth position of the view, in pixels. 12801 */ 12802 @ViewDebug.ExportedProperty(category = "drawing") getElevation()12803 public float getElevation() { 12804 return mRenderNode.getElevation(); 12805 } 12806 12807 /** 12808 * Sets the base elevation of this view, in pixels. 12809 * 12810 * @attr ref android.R.styleable#View_elevation 12811 */ setElevation(float elevation)12812 public void setElevation(float elevation) { 12813 if (elevation != getElevation()) { 12814 invalidateViewProperty(true, false); 12815 mRenderNode.setElevation(elevation); 12816 invalidateViewProperty(false, true); 12817 12818 invalidateParentIfNeededAndWasQuickRejected(); 12819 } 12820 } 12821 12822 /** 12823 * The horizontal location of this view relative to its {@link #getLeft() left} position. 12824 * This position is post-layout, in addition to wherever the object's 12825 * layout placed it. 12826 * 12827 * @return The horizontal position of this view relative to its left position, in pixels. 12828 */ 12829 @ViewDebug.ExportedProperty(category = "drawing") getTranslationX()12830 public float getTranslationX() { 12831 return mRenderNode.getTranslationX(); 12832 } 12833 12834 /** 12835 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 12836 * This effectively positions the object post-layout, in addition to wherever the object's 12837 * layout placed it. 12838 * 12839 * @param translationX The horizontal position of this view relative to its left position, 12840 * in pixels. 12841 * 12842 * @attr ref android.R.styleable#View_translationX 12843 */ setTranslationX(float translationX)12844 public void setTranslationX(float translationX) { 12845 if (translationX != getTranslationX()) { 12846 invalidateViewProperty(true, false); 12847 mRenderNode.setTranslationX(translationX); 12848 invalidateViewProperty(false, true); 12849 12850 invalidateParentIfNeededAndWasQuickRejected(); 12851 notifySubtreeAccessibilityStateChangedIfNeeded(); 12852 } 12853 } 12854 12855 /** 12856 * The vertical location of this view relative to its {@link #getTop() top} position. 12857 * This position is post-layout, in addition to wherever the object's 12858 * layout placed it. 12859 * 12860 * @return The vertical position of this view relative to its top position, 12861 * in pixels. 12862 */ 12863 @ViewDebug.ExportedProperty(category = "drawing") getTranslationY()12864 public float getTranslationY() { 12865 return mRenderNode.getTranslationY(); 12866 } 12867 12868 /** 12869 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 12870 * This effectively positions the object post-layout, in addition to wherever the object's 12871 * layout placed it. 12872 * 12873 * @param translationY The vertical position of this view relative to its top position, 12874 * in pixels. 12875 * 12876 * @attr ref android.R.styleable#View_translationY 12877 */ setTranslationY(float translationY)12878 public void setTranslationY(float translationY) { 12879 if (translationY != getTranslationY()) { 12880 invalidateViewProperty(true, false); 12881 mRenderNode.setTranslationY(translationY); 12882 invalidateViewProperty(false, true); 12883 12884 invalidateParentIfNeededAndWasQuickRejected(); 12885 notifySubtreeAccessibilityStateChangedIfNeeded(); 12886 } 12887 } 12888 12889 /** 12890 * The depth location of this view relative to its {@link #getElevation() elevation}. 12891 * 12892 * @return The depth of this view relative to its elevation. 12893 */ 12894 @ViewDebug.ExportedProperty(category = "drawing") getTranslationZ()12895 public float getTranslationZ() { 12896 return mRenderNode.getTranslationZ(); 12897 } 12898 12899 /** 12900 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 12901 * 12902 * @attr ref android.R.styleable#View_translationZ 12903 */ setTranslationZ(float translationZ)12904 public void setTranslationZ(float translationZ) { 12905 if (translationZ != getTranslationZ()) { 12906 invalidateViewProperty(true, false); 12907 mRenderNode.setTranslationZ(translationZ); 12908 invalidateViewProperty(false, true); 12909 12910 invalidateParentIfNeededAndWasQuickRejected(); 12911 } 12912 } 12913 12914 /** @hide */ setAnimationMatrix(Matrix matrix)12915 public void setAnimationMatrix(Matrix matrix) { 12916 invalidateViewProperty(true, false); 12917 mRenderNode.setAnimationMatrix(matrix); 12918 invalidateViewProperty(false, true); 12919 12920 invalidateParentIfNeededAndWasQuickRejected(); 12921 } 12922 12923 /** 12924 * Returns the current StateListAnimator if exists. 12925 * 12926 * @return StateListAnimator or null if it does not exists 12927 * @see #setStateListAnimator(android.animation.StateListAnimator) 12928 */ getStateListAnimator()12929 public StateListAnimator getStateListAnimator() { 12930 return mStateListAnimator; 12931 } 12932 12933 /** 12934 * Attaches the provided StateListAnimator to this View. 12935 * <p> 12936 * Any previously attached StateListAnimator will be detached. 12937 * 12938 * @param stateListAnimator The StateListAnimator to update the view 12939 * @see android.animation.StateListAnimator 12940 */ setStateListAnimator(StateListAnimator stateListAnimator)12941 public void setStateListAnimator(StateListAnimator stateListAnimator) { 12942 if (mStateListAnimator == stateListAnimator) { 12943 return; 12944 } 12945 if (mStateListAnimator != null) { 12946 mStateListAnimator.setTarget(null); 12947 } 12948 mStateListAnimator = stateListAnimator; 12949 if (stateListAnimator != null) { 12950 stateListAnimator.setTarget(this); 12951 if (isAttachedToWindow()) { 12952 stateListAnimator.setState(getDrawableState()); 12953 } 12954 } 12955 } 12956 12957 /** 12958 * Returns whether the Outline should be used to clip the contents of the View. 12959 * <p> 12960 * Note that this flag will only be respected if the View's Outline returns true from 12961 * {@link Outline#canClip()}. 12962 * 12963 * @see #setOutlineProvider(ViewOutlineProvider) 12964 * @see #setClipToOutline(boolean) 12965 */ getClipToOutline()12966 public final boolean getClipToOutline() { 12967 return mRenderNode.getClipToOutline(); 12968 } 12969 12970 /** 12971 * Sets whether the View's Outline should be used to clip the contents of the View. 12972 * <p> 12973 * Only a single non-rectangular clip can be applied on a View at any time. 12974 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 12975 * circular reveal} animation take priority over Outline clipping, and 12976 * child Outline clipping takes priority over Outline clipping done by a 12977 * parent. 12978 * <p> 12979 * Note that this flag will only be respected if the View's Outline returns true from 12980 * {@link Outline#canClip()}. 12981 * 12982 * @see #setOutlineProvider(ViewOutlineProvider) 12983 * @see #getClipToOutline() 12984 */ setClipToOutline(boolean clipToOutline)12985 public void setClipToOutline(boolean clipToOutline) { 12986 damageInParent(); 12987 if (getClipToOutline() != clipToOutline) { 12988 mRenderNode.setClipToOutline(clipToOutline); 12989 } 12990 } 12991 12992 // correspond to the enum values of View_outlineProvider 12993 private static final int PROVIDER_BACKGROUND = 0; 12994 private static final int PROVIDER_NONE = 1; 12995 private static final int PROVIDER_BOUNDS = 2; 12996 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)12997 private void setOutlineProviderFromAttribute(int providerInt) { 12998 switch (providerInt) { 12999 case PROVIDER_BACKGROUND: 13000 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 13001 break; 13002 case PROVIDER_NONE: 13003 setOutlineProvider(null); 13004 break; 13005 case PROVIDER_BOUNDS: 13006 setOutlineProvider(ViewOutlineProvider.BOUNDS); 13007 break; 13008 case PROVIDER_PADDED_BOUNDS: 13009 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 13010 break; 13011 } 13012 } 13013 13014 /** 13015 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 13016 * the shape of the shadow it casts, and enables outline clipping. 13017 * <p> 13018 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 13019 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 13020 * outline provider with this method allows this behavior to be overridden. 13021 * <p> 13022 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 13023 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 13024 * <p> 13025 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 13026 * 13027 * @see #setClipToOutline(boolean) 13028 * @see #getClipToOutline() 13029 * @see #getOutlineProvider() 13030 */ setOutlineProvider(ViewOutlineProvider provider)13031 public void setOutlineProvider(ViewOutlineProvider provider) { 13032 mOutlineProvider = provider; 13033 invalidateOutline(); 13034 } 13035 13036 /** 13037 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 13038 * that defines the shape of the shadow it casts, and enables outline clipping. 13039 * 13040 * @see #setOutlineProvider(ViewOutlineProvider) 13041 */ getOutlineProvider()13042 public ViewOutlineProvider getOutlineProvider() { 13043 return mOutlineProvider; 13044 } 13045 13046 /** 13047 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 13048 * 13049 * @see #setOutlineProvider(ViewOutlineProvider) 13050 */ invalidateOutline()13051 public void invalidateOutline() { 13052 rebuildOutline(); 13053 13054 notifySubtreeAccessibilityStateChangedIfNeeded(); 13055 invalidateViewProperty(false, false); 13056 } 13057 13058 /** 13059 * Internal version of {@link #invalidateOutline()} which invalidates the 13060 * outline without invalidating the view itself. This is intended to be called from 13061 * within methods in the View class itself which are the result of the view being 13062 * invalidated already. For example, when we are drawing the background of a View, 13063 * we invalidate the outline in case it changed in the meantime, but we do not 13064 * need to invalidate the view because we're already drawing the background as part 13065 * of drawing the view in response to an earlier invalidation of the view. 13066 */ rebuildOutline()13067 private void rebuildOutline() { 13068 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 13069 if (mAttachInfo == null) return; 13070 13071 if (mOutlineProvider == null) { 13072 // no provider, remove outline 13073 mRenderNode.setOutline(null); 13074 } else { 13075 final Outline outline = mAttachInfo.mTmpOutline; 13076 outline.setEmpty(); 13077 outline.setAlpha(1.0f); 13078 13079 mOutlineProvider.getOutline(this, outline); 13080 mRenderNode.setOutline(outline); 13081 } 13082 } 13083 13084 /** 13085 * HierarchyViewer only 13086 * 13087 * @hide 13088 */ 13089 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()13090 public boolean hasShadow() { 13091 return mRenderNode.hasShadow(); 13092 } 13093 13094 13095 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)13096 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 13097 mRenderNode.setRevealClip(shouldClip, x, y, radius); 13098 invalidateViewProperty(false, false); 13099 } 13100 13101 /** 13102 * Hit rectangle in parent's coordinates 13103 * 13104 * @param outRect The hit rectangle of the view. 13105 */ getHitRect(Rect outRect)13106 public void getHitRect(Rect outRect) { 13107 if (hasIdentityMatrix() || mAttachInfo == null) { 13108 outRect.set(mLeft, mTop, mRight, mBottom); 13109 } else { 13110 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 13111 tmpRect.set(0, 0, getWidth(), getHeight()); 13112 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 13113 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 13114 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 13115 } 13116 } 13117 13118 /** 13119 * Determines whether the given point, in local coordinates is inside the view. 13120 */ pointInView(float localX, float localY)13121 /*package*/ final boolean pointInView(float localX, float localY) { 13122 return pointInView(localX, localY, 0); 13123 } 13124 13125 /** 13126 * Utility method to determine whether the given point, in local coordinates, 13127 * is inside the view, where the area of the view is expanded by the slop factor. 13128 * This method is called while processing touch-move events to determine if the event 13129 * is still within the view. 13130 * 13131 * @hide 13132 */ pointInView(float localX, float localY, float slop)13133 public boolean pointInView(float localX, float localY, float slop) { 13134 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 13135 localY < ((mBottom - mTop) + slop); 13136 } 13137 13138 /** 13139 * When a view has focus and the user navigates away from it, the next view is searched for 13140 * starting from the rectangle filled in by this method. 13141 * 13142 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 13143 * of the view. However, if your view maintains some idea of internal selection, 13144 * such as a cursor, or a selected row or column, you should override this method and 13145 * fill in a more specific rectangle. 13146 * 13147 * @param r The rectangle to fill in, in this view's coordinates. 13148 */ getFocusedRect(Rect r)13149 public void getFocusedRect(Rect r) { 13150 getDrawingRect(r); 13151 } 13152 13153 /** 13154 * If some part of this view is not clipped by any of its parents, then 13155 * return that area in r in global (root) coordinates. To convert r to local 13156 * coordinates (without taking possible View rotations into account), offset 13157 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 13158 * If the view is completely clipped or translated out, return false. 13159 * 13160 * @param r If true is returned, r holds the global coordinates of the 13161 * visible portion of this view. 13162 * @param globalOffset If true is returned, globalOffset holds the dx,dy 13163 * between this view and its root. globalOffet may be null. 13164 * @return true if r is non-empty (i.e. part of the view is visible at the 13165 * root level. 13166 */ getGlobalVisibleRect(Rect r, Point globalOffset)13167 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 13168 int width = mRight - mLeft; 13169 int height = mBottom - mTop; 13170 if (width > 0 && height > 0) { 13171 r.set(0, 0, width, height); 13172 if (globalOffset != null) { 13173 globalOffset.set(-mScrollX, -mScrollY); 13174 } 13175 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 13176 } 13177 return false; 13178 } 13179 getGlobalVisibleRect(Rect r)13180 public final boolean getGlobalVisibleRect(Rect r) { 13181 return getGlobalVisibleRect(r, null); 13182 } 13183 getLocalVisibleRect(Rect r)13184 public final boolean getLocalVisibleRect(Rect r) { 13185 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 13186 if (getGlobalVisibleRect(r, offset)) { 13187 r.offset(-offset.x, -offset.y); // make r local 13188 return true; 13189 } 13190 return false; 13191 } 13192 13193 /** 13194 * Offset this view's vertical location by the specified number of pixels. 13195 * 13196 * @param offset the number of pixels to offset the view by 13197 */ offsetTopAndBottom(int offset)13198 public void offsetTopAndBottom(int offset) { 13199 if (offset != 0) { 13200 final boolean matrixIsIdentity = hasIdentityMatrix(); 13201 if (matrixIsIdentity) { 13202 if (isHardwareAccelerated()) { 13203 invalidateViewProperty(false, false); 13204 } else { 13205 final ViewParent p = mParent; 13206 if (p != null && mAttachInfo != null) { 13207 final Rect r = mAttachInfo.mTmpInvalRect; 13208 int minTop; 13209 int maxBottom; 13210 int yLoc; 13211 if (offset < 0) { 13212 minTop = mTop + offset; 13213 maxBottom = mBottom; 13214 yLoc = offset; 13215 } else { 13216 minTop = mTop; 13217 maxBottom = mBottom + offset; 13218 yLoc = 0; 13219 } 13220 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 13221 p.invalidateChild(this, r); 13222 } 13223 } 13224 } else { 13225 invalidateViewProperty(false, false); 13226 } 13227 13228 mTop += offset; 13229 mBottom += offset; 13230 mRenderNode.offsetTopAndBottom(offset); 13231 if (isHardwareAccelerated()) { 13232 invalidateViewProperty(false, false); 13233 invalidateParentIfNeededAndWasQuickRejected(); 13234 } else { 13235 if (!matrixIsIdentity) { 13236 invalidateViewProperty(false, true); 13237 } 13238 invalidateParentIfNeeded(); 13239 } 13240 notifySubtreeAccessibilityStateChangedIfNeeded(); 13241 } 13242 } 13243 13244 /** 13245 * Offset this view's horizontal location by the specified amount of pixels. 13246 * 13247 * @param offset the number of pixels to offset the view by 13248 */ offsetLeftAndRight(int offset)13249 public void offsetLeftAndRight(int offset) { 13250 if (offset != 0) { 13251 final boolean matrixIsIdentity = hasIdentityMatrix(); 13252 if (matrixIsIdentity) { 13253 if (isHardwareAccelerated()) { 13254 invalidateViewProperty(false, false); 13255 } else { 13256 final ViewParent p = mParent; 13257 if (p != null && mAttachInfo != null) { 13258 final Rect r = mAttachInfo.mTmpInvalRect; 13259 int minLeft; 13260 int maxRight; 13261 if (offset < 0) { 13262 minLeft = mLeft + offset; 13263 maxRight = mRight; 13264 } else { 13265 minLeft = mLeft; 13266 maxRight = mRight + offset; 13267 } 13268 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 13269 p.invalidateChild(this, r); 13270 } 13271 } 13272 } else { 13273 invalidateViewProperty(false, false); 13274 } 13275 13276 mLeft += offset; 13277 mRight += offset; 13278 mRenderNode.offsetLeftAndRight(offset); 13279 if (isHardwareAccelerated()) { 13280 invalidateViewProperty(false, false); 13281 invalidateParentIfNeededAndWasQuickRejected(); 13282 } else { 13283 if (!matrixIsIdentity) { 13284 invalidateViewProperty(false, true); 13285 } 13286 invalidateParentIfNeeded(); 13287 } 13288 notifySubtreeAccessibilityStateChangedIfNeeded(); 13289 } 13290 } 13291 13292 /** 13293 * Get the LayoutParams associated with this view. All views should have 13294 * layout parameters. These supply parameters to the <i>parent</i> of this 13295 * view specifying how it should be arranged. There are many subclasses of 13296 * ViewGroup.LayoutParams, and these correspond to the different subclasses 13297 * of ViewGroup that are responsible for arranging their children. 13298 * 13299 * This method may return null if this View is not attached to a parent 13300 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 13301 * was not invoked successfully. When a View is attached to a parent 13302 * ViewGroup, this method must not return null. 13303 * 13304 * @return The LayoutParams associated with this view, or null if no 13305 * parameters have been set yet 13306 */ 13307 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()13308 public ViewGroup.LayoutParams getLayoutParams() { 13309 return mLayoutParams; 13310 } 13311 13312 /** 13313 * Set the layout parameters associated with this view. These supply 13314 * parameters to the <i>parent</i> of this view specifying how it should be 13315 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 13316 * correspond to the different subclasses of ViewGroup that are responsible 13317 * for arranging their children. 13318 * 13319 * @param params The layout parameters for this view, cannot be null 13320 */ setLayoutParams(ViewGroup.LayoutParams params)13321 public void setLayoutParams(ViewGroup.LayoutParams params) { 13322 if (params == null) { 13323 throw new NullPointerException("Layout parameters cannot be null"); 13324 } 13325 mLayoutParams = params; 13326 resolveLayoutParams(); 13327 if (mParent instanceof ViewGroup) { 13328 ((ViewGroup) mParent).onSetLayoutParams(this, params); 13329 } 13330 requestLayout(); 13331 } 13332 13333 /** 13334 * Resolve the layout parameters depending on the resolved layout direction 13335 * 13336 * @hide 13337 */ resolveLayoutParams()13338 public void resolveLayoutParams() { 13339 if (mLayoutParams != null) { 13340 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 13341 } 13342 } 13343 13344 /** 13345 * Set the scrolled position of your view. This will cause a call to 13346 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13347 * invalidated. 13348 * @param x the x position to scroll to 13349 * @param y the y position to scroll to 13350 */ scrollTo(int x, int y)13351 public void scrollTo(int x, int y) { 13352 if (mScrollX != x || mScrollY != y) { 13353 int oldX = mScrollX; 13354 int oldY = mScrollY; 13355 mScrollX = x; 13356 mScrollY = y; 13357 invalidateParentCaches(); 13358 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 13359 if (!awakenScrollBars()) { 13360 postInvalidateOnAnimation(); 13361 } 13362 } 13363 } 13364 13365 /** 13366 * Move the scrolled position of your view. This will cause a call to 13367 * {@link #onScrollChanged(int, int, int, int)} and the view will be 13368 * invalidated. 13369 * @param x the amount of pixels to scroll by horizontally 13370 * @param y the amount of pixels to scroll by vertically 13371 */ scrollBy(int x, int y)13372 public void scrollBy(int x, int y) { 13373 scrollTo(mScrollX + x, mScrollY + y); 13374 } 13375 13376 /** 13377 * <p>Trigger the scrollbars to draw. When invoked this method starts an 13378 * animation to fade the scrollbars out after a default delay. If a subclass 13379 * provides animated scrolling, the start delay should equal the duration 13380 * of the scrolling animation.</p> 13381 * 13382 * <p>The animation starts only if at least one of the scrollbars is 13383 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 13384 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13385 * this method returns true, and false otherwise. If the animation is 13386 * started, this method calls {@link #invalidate()}; in that case the 13387 * caller should not call {@link #invalidate()}.</p> 13388 * 13389 * <p>This method should be invoked every time a subclass directly updates 13390 * the scroll parameters.</p> 13391 * 13392 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 13393 * and {@link #scrollTo(int, int)}.</p> 13394 * 13395 * @return true if the animation is played, false otherwise 13396 * 13397 * @see #awakenScrollBars(int) 13398 * @see #scrollBy(int, int) 13399 * @see #scrollTo(int, int) 13400 * @see #isHorizontalScrollBarEnabled() 13401 * @see #isVerticalScrollBarEnabled() 13402 * @see #setHorizontalScrollBarEnabled(boolean) 13403 * @see #setVerticalScrollBarEnabled(boolean) 13404 */ awakenScrollBars()13405 protected boolean awakenScrollBars() { 13406 return mScrollCache != null && 13407 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 13408 } 13409 13410 /** 13411 * Trigger the scrollbars to draw. 13412 * This method differs from awakenScrollBars() only in its default duration. 13413 * initialAwakenScrollBars() will show the scroll bars for longer than 13414 * usual to give the user more of a chance to notice them. 13415 * 13416 * @return true if the animation is played, false otherwise. 13417 */ initialAwakenScrollBars()13418 private boolean initialAwakenScrollBars() { 13419 return mScrollCache != null && 13420 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 13421 } 13422 13423 /** 13424 * <p> 13425 * Trigger the scrollbars to draw. When invoked this method starts an 13426 * animation to fade the scrollbars out after a fixed delay. If a subclass 13427 * provides animated scrolling, the start delay should equal the duration of 13428 * the scrolling animation. 13429 * </p> 13430 * 13431 * <p> 13432 * The animation starts only if at least one of the scrollbars is enabled, 13433 * as specified by {@link #isHorizontalScrollBarEnabled()} and 13434 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13435 * this method returns true, and false otherwise. If the animation is 13436 * started, this method calls {@link #invalidate()}; in that case the caller 13437 * should not call {@link #invalidate()}. 13438 * </p> 13439 * 13440 * <p> 13441 * This method should be invoked every time a subclass directly updates the 13442 * scroll parameters. 13443 * </p> 13444 * 13445 * @param startDelay the delay, in milliseconds, after which the animation 13446 * should start; when the delay is 0, the animation starts 13447 * immediately 13448 * @return true if the animation is played, false otherwise 13449 * 13450 * @see #scrollBy(int, int) 13451 * @see #scrollTo(int, int) 13452 * @see #isHorizontalScrollBarEnabled() 13453 * @see #isVerticalScrollBarEnabled() 13454 * @see #setHorizontalScrollBarEnabled(boolean) 13455 * @see #setVerticalScrollBarEnabled(boolean) 13456 */ awakenScrollBars(int startDelay)13457 protected boolean awakenScrollBars(int startDelay) { 13458 return awakenScrollBars(startDelay, true); 13459 } 13460 13461 /** 13462 * <p> 13463 * Trigger the scrollbars to draw. When invoked this method starts an 13464 * animation to fade the scrollbars out after a fixed delay. If a subclass 13465 * provides animated scrolling, the start delay should equal the duration of 13466 * the scrolling animation. 13467 * </p> 13468 * 13469 * <p> 13470 * The animation starts only if at least one of the scrollbars is enabled, 13471 * as specified by {@link #isHorizontalScrollBarEnabled()} and 13472 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 13473 * this method returns true, and false otherwise. If the animation is 13474 * started, this method calls {@link #invalidate()} if the invalidate parameter 13475 * is set to true; in that case the caller 13476 * should not call {@link #invalidate()}. 13477 * </p> 13478 * 13479 * <p> 13480 * This method should be invoked every time a subclass directly updates the 13481 * scroll parameters. 13482 * </p> 13483 * 13484 * @param startDelay the delay, in milliseconds, after which the animation 13485 * should start; when the delay is 0, the animation starts 13486 * immediately 13487 * 13488 * @param invalidate Whether this method should call invalidate 13489 * 13490 * @return true if the animation is played, false otherwise 13491 * 13492 * @see #scrollBy(int, int) 13493 * @see #scrollTo(int, int) 13494 * @see #isHorizontalScrollBarEnabled() 13495 * @see #isVerticalScrollBarEnabled() 13496 * @see #setHorizontalScrollBarEnabled(boolean) 13497 * @see #setVerticalScrollBarEnabled(boolean) 13498 */ awakenScrollBars(int startDelay, boolean invalidate)13499 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 13500 final ScrollabilityCache scrollCache = mScrollCache; 13501 13502 if (scrollCache == null || !scrollCache.fadeScrollBars) { 13503 return false; 13504 } 13505 13506 if (scrollCache.scrollBar == null) { 13507 scrollCache.scrollBar = new ScrollBarDrawable(); 13508 scrollCache.scrollBar.setState(getDrawableState()); 13509 scrollCache.scrollBar.setCallback(this); 13510 } 13511 13512 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 13513 13514 if (invalidate) { 13515 // Invalidate to show the scrollbars 13516 postInvalidateOnAnimation(); 13517 } 13518 13519 if (scrollCache.state == ScrollabilityCache.OFF) { 13520 // FIXME: this is copied from WindowManagerService. 13521 // We should get this value from the system when it 13522 // is possible to do so. 13523 final int KEY_REPEAT_FIRST_DELAY = 750; 13524 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 13525 } 13526 13527 // Tell mScrollCache when we should start fading. This may 13528 // extend the fade start time if one was already scheduled 13529 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 13530 scrollCache.fadeStartTime = fadeStartTime; 13531 scrollCache.state = ScrollabilityCache.ON; 13532 13533 // Schedule our fader to run, unscheduling any old ones first 13534 if (mAttachInfo != null) { 13535 mAttachInfo.mHandler.removeCallbacks(scrollCache); 13536 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 13537 } 13538 13539 return true; 13540 } 13541 13542 return false; 13543 } 13544 13545 /** 13546 * Do not invalidate views which are not visible and which are not running an animation. They 13547 * will not get drawn and they should not set dirty flags as if they will be drawn 13548 */ skipInvalidate()13549 private boolean skipInvalidate() { 13550 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 13551 (!(mParent instanceof ViewGroup) || 13552 !((ViewGroup) mParent).isViewTransitioning(this)); 13553 } 13554 13555 /** 13556 * Mark the area defined by dirty as needing to be drawn. If the view is 13557 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 13558 * point in the future. 13559 * <p> 13560 * This must be called from a UI thread. To call from a non-UI thread, call 13561 * {@link #postInvalidate()}. 13562 * <p> 13563 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 13564 * {@code dirty}. 13565 * 13566 * @param dirty the rectangle representing the bounds of the dirty region 13567 */ invalidate(Rect dirty)13568 public void invalidate(Rect dirty) { 13569 final int scrollX = mScrollX; 13570 final int scrollY = mScrollY; 13571 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 13572 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 13573 } 13574 13575 /** 13576 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 13577 * coordinates of the dirty rect are relative to the view. If the view is 13578 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 13579 * point in the future. 13580 * <p> 13581 * This must be called from a UI thread. To call from a non-UI thread, call 13582 * {@link #postInvalidate()}. 13583 * 13584 * @param l the left position of the dirty region 13585 * @param t the top position of the dirty region 13586 * @param r the right position of the dirty region 13587 * @param b the bottom position of the dirty region 13588 */ invalidate(int l, int t, int r, int b)13589 public void invalidate(int l, int t, int r, int b) { 13590 final int scrollX = mScrollX; 13591 final int scrollY = mScrollY; 13592 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 13593 } 13594 13595 /** 13596 * Invalidate the whole view. If the view is visible, 13597 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 13598 * the future. 13599 * <p> 13600 * This must be called from a UI thread. To call from a non-UI thread, call 13601 * {@link #postInvalidate()}. 13602 */ invalidate()13603 public void invalidate() { 13604 invalidate(true); 13605 } 13606 13607 /** 13608 * This is where the invalidate() work actually happens. A full invalidate() 13609 * causes the drawing cache to be invalidated, but this function can be 13610 * called with invalidateCache set to false to skip that invalidation step 13611 * for cases that do not need it (for example, a component that remains at 13612 * the same dimensions with the same content). 13613 * 13614 * @param invalidateCache Whether the drawing cache for this view should be 13615 * invalidated as well. This is usually true for a full 13616 * invalidate, but may be set to false if the View's contents or 13617 * dimensions have not changed. 13618 */ invalidate(boolean invalidateCache)13619 void invalidate(boolean invalidateCache) { 13620 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 13621 } 13622 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)13623 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 13624 boolean fullInvalidate) { 13625 if (mGhostView != null) { 13626 mGhostView.invalidate(true); 13627 return; 13628 } 13629 13630 if (skipInvalidate()) { 13631 return; 13632 } 13633 13634 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 13635 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 13636 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 13637 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 13638 if (fullInvalidate) { 13639 mLastIsOpaque = isOpaque(); 13640 mPrivateFlags &= ~PFLAG_DRAWN; 13641 } 13642 13643 mPrivateFlags |= PFLAG_DIRTY; 13644 13645 if (invalidateCache) { 13646 mPrivateFlags |= PFLAG_INVALIDATED; 13647 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 13648 } 13649 13650 // Propagate the damage rectangle to the parent view. 13651 final AttachInfo ai = mAttachInfo; 13652 final ViewParent p = mParent; 13653 if (p != null && ai != null && l < r && t < b) { 13654 final Rect damage = ai.mTmpInvalRect; 13655 damage.set(l, t, r, b); 13656 p.invalidateChild(this, damage); 13657 } 13658 13659 // Damage the entire projection receiver, if necessary. 13660 if (mBackground != null && mBackground.isProjected()) { 13661 final View receiver = getProjectionReceiver(); 13662 if (receiver != null) { 13663 receiver.damageInParent(); 13664 } 13665 } 13666 13667 // Damage the entire IsolatedZVolume receiving this view's shadow. 13668 if (isHardwareAccelerated() && getZ() != 0) { 13669 damageShadowReceiver(); 13670 } 13671 } 13672 } 13673 13674 /** 13675 * @return this view's projection receiver, or {@code null} if none exists 13676 */ getProjectionReceiver()13677 private View getProjectionReceiver() { 13678 ViewParent p = getParent(); 13679 while (p != null && p instanceof View) { 13680 final View v = (View) p; 13681 if (v.isProjectionReceiver()) { 13682 return v; 13683 } 13684 p = p.getParent(); 13685 } 13686 13687 return null; 13688 } 13689 13690 /** 13691 * @return whether the view is a projection receiver 13692 */ isProjectionReceiver()13693 private boolean isProjectionReceiver() { 13694 return mBackground != null; 13695 } 13696 13697 /** 13698 * Damage area of the screen that can be covered by this View's shadow. 13699 * 13700 * This method will guarantee that any changes to shadows cast by a View 13701 * are damaged on the screen for future redraw. 13702 */ damageShadowReceiver()13703 private void damageShadowReceiver() { 13704 final AttachInfo ai = mAttachInfo; 13705 if (ai != null) { 13706 ViewParent p = getParent(); 13707 if (p != null && p instanceof ViewGroup) { 13708 final ViewGroup vg = (ViewGroup) p; 13709 vg.damageInParent(); 13710 } 13711 } 13712 } 13713 13714 /** 13715 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 13716 * set any flags or handle all of the cases handled by the default invalidation methods. 13717 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 13718 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 13719 * walk up the hierarchy, transforming the dirty rect as necessary. 13720 * 13721 * The method also handles normal invalidation logic if display list properties are not 13722 * being used in this view. The invalidateParent and forceRedraw flags are used by that 13723 * backup approach, to handle these cases used in the various property-setting methods. 13724 * 13725 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 13726 * are not being used in this view 13727 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 13728 * list properties are not being used in this view 13729 */ invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)13730 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 13731 if (!isHardwareAccelerated() 13732 || !mRenderNode.isValid() 13733 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 13734 if (invalidateParent) { 13735 invalidateParentCaches(); 13736 } 13737 if (forceRedraw) { 13738 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 13739 } 13740 invalidate(false); 13741 } else { 13742 damageInParent(); 13743 } 13744 if (isHardwareAccelerated() && invalidateParent && getZ() != 0) { 13745 damageShadowReceiver(); 13746 } 13747 } 13748 13749 /** 13750 * Tells the parent view to damage this view's bounds. 13751 * 13752 * @hide 13753 */ damageInParent()13754 protected void damageInParent() { 13755 final AttachInfo ai = mAttachInfo; 13756 final ViewParent p = mParent; 13757 if (p != null && ai != null) { 13758 final Rect r = ai.mTmpInvalRect; 13759 r.set(0, 0, mRight - mLeft, mBottom - mTop); 13760 if (mParent instanceof ViewGroup) { 13761 ((ViewGroup) mParent).damageChild(this, r); 13762 } else { 13763 mParent.invalidateChild(this, r); 13764 } 13765 } 13766 } 13767 13768 /** 13769 * Utility method to transform a given Rect by the current matrix of this view. 13770 */ transformRect(final Rect rect)13771 void transformRect(final Rect rect) { 13772 if (!getMatrix().isIdentity()) { 13773 RectF boundingRect = mAttachInfo.mTmpTransformRect; 13774 boundingRect.set(rect); 13775 getMatrix().mapRect(boundingRect); 13776 rect.set((int) Math.floor(boundingRect.left), 13777 (int) Math.floor(boundingRect.top), 13778 (int) Math.ceil(boundingRect.right), 13779 (int) Math.ceil(boundingRect.bottom)); 13780 } 13781 } 13782 13783 /** 13784 * Used to indicate that the parent of this view should clear its caches. This functionality 13785 * is used to force the parent to rebuild its display list (when hardware-accelerated), 13786 * which is necessary when various parent-managed properties of the view change, such as 13787 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 13788 * clears the parent caches and does not causes an invalidate event. 13789 * 13790 * @hide 13791 */ invalidateParentCaches()13792 protected void invalidateParentCaches() { 13793 if (mParent instanceof View) { 13794 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 13795 } 13796 } 13797 13798 /** 13799 * Used to indicate that the parent of this view should be invalidated. This functionality 13800 * is used to force the parent to rebuild its display list (when hardware-accelerated), 13801 * which is necessary when various parent-managed properties of the view change, such as 13802 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 13803 * an invalidation event to the parent. 13804 * 13805 * @hide 13806 */ invalidateParentIfNeeded()13807 protected void invalidateParentIfNeeded() { 13808 if (isHardwareAccelerated() && mParent instanceof View) { 13809 ((View) mParent).invalidate(true); 13810 } 13811 } 13812 13813 /** 13814 * @hide 13815 */ invalidateParentIfNeededAndWasQuickRejected()13816 protected void invalidateParentIfNeededAndWasQuickRejected() { 13817 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 13818 // View was rejected last time it was drawn by its parent; this may have changed 13819 invalidateParentIfNeeded(); 13820 } 13821 } 13822 13823 /** 13824 * Indicates whether this View is opaque. An opaque View guarantees that it will 13825 * draw all the pixels overlapping its bounds using a fully opaque color. 13826 * 13827 * Subclasses of View should override this method whenever possible to indicate 13828 * whether an instance is opaque. Opaque Views are treated in a special way by 13829 * the View hierarchy, possibly allowing it to perform optimizations during 13830 * invalidate/draw passes. 13831 * 13832 * @return True if this View is guaranteed to be fully opaque, false otherwise. 13833 */ 13834 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()13835 public boolean isOpaque() { 13836 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 13837 getFinalAlpha() >= 1.0f; 13838 } 13839 13840 /** 13841 * @hide 13842 */ computeOpaqueFlags()13843 protected void computeOpaqueFlags() { 13844 // Opaque if: 13845 // - Has a background 13846 // - Background is opaque 13847 // - Doesn't have scrollbars or scrollbars overlay 13848 13849 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 13850 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 13851 } else { 13852 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 13853 } 13854 13855 final int flags = mViewFlags; 13856 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 13857 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 13858 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 13859 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 13860 } else { 13861 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 13862 } 13863 } 13864 13865 /** 13866 * @hide 13867 */ hasOpaqueScrollbars()13868 protected boolean hasOpaqueScrollbars() { 13869 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 13870 } 13871 13872 /** 13873 * @return A handler associated with the thread running the View. This 13874 * handler can be used to pump events in the UI events queue. 13875 */ getHandler()13876 public Handler getHandler() { 13877 final AttachInfo attachInfo = mAttachInfo; 13878 if (attachInfo != null) { 13879 return attachInfo.mHandler; 13880 } 13881 return null; 13882 } 13883 13884 /** 13885 * Returns the queue of runnable for this view. 13886 * 13887 * @return the queue of runnables for this view 13888 */ getRunQueue()13889 private HandlerActionQueue getRunQueue() { 13890 if (mRunQueue == null) { 13891 mRunQueue = new HandlerActionQueue(); 13892 } 13893 return mRunQueue; 13894 } 13895 13896 /** 13897 * Gets the view root associated with the View. 13898 * @return The view root, or null if none. 13899 * @hide 13900 */ getViewRootImpl()13901 public ViewRootImpl getViewRootImpl() { 13902 if (mAttachInfo != null) { 13903 return mAttachInfo.mViewRootImpl; 13904 } 13905 return null; 13906 } 13907 13908 /** 13909 * @hide 13910 */ getHardwareRenderer()13911 public ThreadedRenderer getHardwareRenderer() { 13912 return mAttachInfo != null ? mAttachInfo.mHardwareRenderer : null; 13913 } 13914 13915 /** 13916 * <p>Causes the Runnable to be added to the message queue. 13917 * The runnable will be run on the user interface thread.</p> 13918 * 13919 * @param action The Runnable that will be executed. 13920 * 13921 * @return Returns true if the Runnable was successfully placed in to the 13922 * message queue. Returns false on failure, usually because the 13923 * looper processing the message queue is exiting. 13924 * 13925 * @see #postDelayed 13926 * @see #removeCallbacks 13927 */ post(Runnable action)13928 public boolean post(Runnable action) { 13929 final AttachInfo attachInfo = mAttachInfo; 13930 if (attachInfo != null) { 13931 return attachInfo.mHandler.post(action); 13932 } 13933 13934 // Postpone the runnable until we know on which thread it needs to run. 13935 // Assume that the runnable will be successfully placed after attach. 13936 getRunQueue().post(action); 13937 return true; 13938 } 13939 13940 /** 13941 * <p>Causes the Runnable to be added to the message queue, to be run 13942 * after the specified amount of time elapses. 13943 * The runnable will be run on the user interface thread.</p> 13944 * 13945 * @param action The Runnable that will be executed. 13946 * @param delayMillis The delay (in milliseconds) until the Runnable 13947 * will be executed. 13948 * 13949 * @return true if the Runnable was successfully placed in to the 13950 * message queue. Returns false on failure, usually because the 13951 * looper processing the message queue is exiting. Note that a 13952 * result of true does not mean the Runnable will be processed -- 13953 * if the looper is quit before the delivery time of the message 13954 * occurs then the message will be dropped. 13955 * 13956 * @see #post 13957 * @see #removeCallbacks 13958 */ postDelayed(Runnable action, long delayMillis)13959 public boolean postDelayed(Runnable action, long delayMillis) { 13960 final AttachInfo attachInfo = mAttachInfo; 13961 if (attachInfo != null) { 13962 return attachInfo.mHandler.postDelayed(action, delayMillis); 13963 } 13964 13965 // Postpone the runnable until we know on which thread it needs to run. 13966 // Assume that the runnable will be successfully placed after attach. 13967 getRunQueue().postDelayed(action, delayMillis); 13968 return true; 13969 } 13970 13971 /** 13972 * <p>Causes the Runnable to execute on the next animation time step. 13973 * The runnable will be run on the user interface thread.</p> 13974 * 13975 * @param action The Runnable that will be executed. 13976 * 13977 * @see #postOnAnimationDelayed 13978 * @see #removeCallbacks 13979 */ postOnAnimation(Runnable action)13980 public void postOnAnimation(Runnable action) { 13981 final AttachInfo attachInfo = mAttachInfo; 13982 if (attachInfo != null) { 13983 attachInfo.mViewRootImpl.mChoreographer.postCallback( 13984 Choreographer.CALLBACK_ANIMATION, action, null); 13985 } else { 13986 // Postpone the runnable until we know 13987 // on which thread it needs to run. 13988 getRunQueue().post(action); 13989 } 13990 } 13991 13992 /** 13993 * <p>Causes the Runnable to execute on the next animation time step, 13994 * after the specified amount of time elapses. 13995 * The runnable will be run on the user interface thread.</p> 13996 * 13997 * @param action The Runnable that will be executed. 13998 * @param delayMillis The delay (in milliseconds) until the Runnable 13999 * will be executed. 14000 * 14001 * @see #postOnAnimation 14002 * @see #removeCallbacks 14003 */ postOnAnimationDelayed(Runnable action, long delayMillis)14004 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 14005 final AttachInfo attachInfo = mAttachInfo; 14006 if (attachInfo != null) { 14007 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 14008 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 14009 } else { 14010 // Postpone the runnable until we know 14011 // on which thread it needs to run. 14012 getRunQueue().postDelayed(action, delayMillis); 14013 } 14014 } 14015 14016 /** 14017 * <p>Removes the specified Runnable from the message queue.</p> 14018 * 14019 * @param action The Runnable to remove from the message handling queue 14020 * 14021 * @return true if this view could ask the Handler to remove the Runnable, 14022 * false otherwise. When the returned value is true, the Runnable 14023 * may or may not have been actually removed from the message queue 14024 * (for instance, if the Runnable was not in the queue already.) 14025 * 14026 * @see #post 14027 * @see #postDelayed 14028 * @see #postOnAnimation 14029 * @see #postOnAnimationDelayed 14030 */ removeCallbacks(Runnable action)14031 public boolean removeCallbacks(Runnable action) { 14032 if (action != null) { 14033 final AttachInfo attachInfo = mAttachInfo; 14034 if (attachInfo != null) { 14035 attachInfo.mHandler.removeCallbacks(action); 14036 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 14037 Choreographer.CALLBACK_ANIMATION, action, null); 14038 } 14039 getRunQueue().removeCallbacks(action); 14040 } 14041 return true; 14042 } 14043 14044 /** 14045 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 14046 * Use this to invalidate the View from a non-UI thread.</p> 14047 * 14048 * <p>This method can be invoked from outside of the UI thread 14049 * only when this View is attached to a window.</p> 14050 * 14051 * @see #invalidate() 14052 * @see #postInvalidateDelayed(long) 14053 */ postInvalidate()14054 public void postInvalidate() { 14055 postInvalidateDelayed(0); 14056 } 14057 14058 /** 14059 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14060 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 14061 * 14062 * <p>This method can be invoked from outside of the UI thread 14063 * only when this View is attached to a window.</p> 14064 * 14065 * @param left The left coordinate of the rectangle to invalidate. 14066 * @param top The top coordinate of the rectangle to invalidate. 14067 * @param right The right coordinate of the rectangle to invalidate. 14068 * @param bottom The bottom coordinate of the rectangle to invalidate. 14069 * 14070 * @see #invalidate(int, int, int, int) 14071 * @see #invalidate(Rect) 14072 * @see #postInvalidateDelayed(long, int, int, int, int) 14073 */ postInvalidate(int left, int top, int right, int bottom)14074 public void postInvalidate(int left, int top, int right, int bottom) { 14075 postInvalidateDelayed(0, left, top, right, bottom); 14076 } 14077 14078 /** 14079 * <p>Cause an invalidate to happen on a subsequent cycle through the event 14080 * loop. Waits for the specified amount of time.</p> 14081 * 14082 * <p>This method can be invoked from outside of the UI thread 14083 * only when this View is attached to a window.</p> 14084 * 14085 * @param delayMilliseconds the duration in milliseconds to delay the 14086 * invalidation by 14087 * 14088 * @see #invalidate() 14089 * @see #postInvalidate() 14090 */ postInvalidateDelayed(long delayMilliseconds)14091 public void postInvalidateDelayed(long delayMilliseconds) { 14092 // We try only with the AttachInfo because there's no point in invalidating 14093 // if we are not attached to our window 14094 final AttachInfo attachInfo = mAttachInfo; 14095 if (attachInfo != null) { 14096 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 14097 } 14098 } 14099 14100 /** 14101 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 14102 * through the event loop. Waits for the specified amount of time.</p> 14103 * 14104 * <p>This method can be invoked from outside of the UI thread 14105 * only when this View is attached to a window.</p> 14106 * 14107 * @param delayMilliseconds the duration in milliseconds to delay the 14108 * invalidation by 14109 * @param left The left coordinate of the rectangle to invalidate. 14110 * @param top The top coordinate of the rectangle to invalidate. 14111 * @param right The right coordinate of the rectangle to invalidate. 14112 * @param bottom The bottom coordinate of the rectangle to invalidate. 14113 * 14114 * @see #invalidate(int, int, int, int) 14115 * @see #invalidate(Rect) 14116 * @see #postInvalidate(int, int, int, int) 14117 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)14118 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 14119 int right, int bottom) { 14120 14121 // We try only with the AttachInfo because there's no point in invalidating 14122 // if we are not attached to our window 14123 final AttachInfo attachInfo = mAttachInfo; 14124 if (attachInfo != null) { 14125 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14126 info.target = this; 14127 info.left = left; 14128 info.top = top; 14129 info.right = right; 14130 info.bottom = bottom; 14131 14132 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 14133 } 14134 } 14135 14136 /** 14137 * <p>Cause an invalidate to happen on the next animation time step, typically the 14138 * next display frame.</p> 14139 * 14140 * <p>This method can be invoked from outside of the UI thread 14141 * only when this View is attached to a window.</p> 14142 * 14143 * @see #invalidate() 14144 */ postInvalidateOnAnimation()14145 public void postInvalidateOnAnimation() { 14146 // We try only with the AttachInfo because there's no point in invalidating 14147 // if we are not attached to our window 14148 final AttachInfo attachInfo = mAttachInfo; 14149 if (attachInfo != null) { 14150 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 14151 } 14152 } 14153 14154 /** 14155 * <p>Cause an invalidate of the specified area to happen on the next animation 14156 * time step, typically the next display frame.</p> 14157 * 14158 * <p>This method can be invoked from outside of the UI thread 14159 * only when this View is attached to a window.</p> 14160 * 14161 * @param left The left coordinate of the rectangle to invalidate. 14162 * @param top The top coordinate of the rectangle to invalidate. 14163 * @param right The right coordinate of the rectangle to invalidate. 14164 * @param bottom The bottom coordinate of the rectangle to invalidate. 14165 * 14166 * @see #invalidate(int, int, int, int) 14167 * @see #invalidate(Rect) 14168 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)14169 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 14170 // We try only with the AttachInfo because there's no point in invalidating 14171 // if we are not attached to our window 14172 final AttachInfo attachInfo = mAttachInfo; 14173 if (attachInfo != null) { 14174 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 14175 info.target = this; 14176 info.left = left; 14177 info.top = top; 14178 info.right = right; 14179 info.bottom = bottom; 14180 14181 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 14182 } 14183 } 14184 14185 /** 14186 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 14187 * This event is sent at most once every 14188 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 14189 */ postSendViewScrolledAccessibilityEventCallback()14190 private void postSendViewScrolledAccessibilityEventCallback() { 14191 if (mSendViewScrolledAccessibilityEvent == null) { 14192 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 14193 } 14194 if (!mSendViewScrolledAccessibilityEvent.mIsPending) { 14195 mSendViewScrolledAccessibilityEvent.mIsPending = true; 14196 postDelayed(mSendViewScrolledAccessibilityEvent, 14197 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 14198 } 14199 } 14200 14201 /** 14202 * Called by a parent to request that a child update its values for mScrollX 14203 * and mScrollY if necessary. This will typically be done if the child is 14204 * animating a scroll using a {@link android.widget.Scroller Scroller} 14205 * object. 14206 */ computeScroll()14207 public void computeScroll() { 14208 } 14209 14210 /** 14211 * <p>Indicate whether the horizontal edges are faded when the view is 14212 * scrolled horizontally.</p> 14213 * 14214 * @return true if the horizontal edges should are faded on scroll, false 14215 * otherwise 14216 * 14217 * @see #setHorizontalFadingEdgeEnabled(boolean) 14218 * 14219 * @attr ref android.R.styleable#View_requiresFadingEdge 14220 */ isHorizontalFadingEdgeEnabled()14221 public boolean isHorizontalFadingEdgeEnabled() { 14222 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 14223 } 14224 14225 /** 14226 * <p>Define whether the horizontal edges should be faded when this view 14227 * is scrolled horizontally.</p> 14228 * 14229 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 14230 * be faded when the view is scrolled 14231 * horizontally 14232 * 14233 * @see #isHorizontalFadingEdgeEnabled() 14234 * 14235 * @attr ref android.R.styleable#View_requiresFadingEdge 14236 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)14237 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 14238 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 14239 if (horizontalFadingEdgeEnabled) { 14240 initScrollCache(); 14241 } 14242 14243 mViewFlags ^= FADING_EDGE_HORIZONTAL; 14244 } 14245 } 14246 14247 /** 14248 * <p>Indicate whether the vertical edges are faded when the view is 14249 * scrolled horizontally.</p> 14250 * 14251 * @return true if the vertical edges should are faded on scroll, false 14252 * otherwise 14253 * 14254 * @see #setVerticalFadingEdgeEnabled(boolean) 14255 * 14256 * @attr ref android.R.styleable#View_requiresFadingEdge 14257 */ isVerticalFadingEdgeEnabled()14258 public boolean isVerticalFadingEdgeEnabled() { 14259 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 14260 } 14261 14262 /** 14263 * <p>Define whether the vertical edges should be faded when this view 14264 * is scrolled vertically.</p> 14265 * 14266 * @param verticalFadingEdgeEnabled true if the vertical edges should 14267 * be faded when the view is scrolled 14268 * vertically 14269 * 14270 * @see #isVerticalFadingEdgeEnabled() 14271 * 14272 * @attr ref android.R.styleable#View_requiresFadingEdge 14273 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)14274 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 14275 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 14276 if (verticalFadingEdgeEnabled) { 14277 initScrollCache(); 14278 } 14279 14280 mViewFlags ^= FADING_EDGE_VERTICAL; 14281 } 14282 } 14283 14284 /** 14285 * Returns the strength, or intensity, of the top faded edge. The strength is 14286 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14287 * returns 0.0 or 1.0 but no value in between. 14288 * 14289 * Subclasses should override this method to provide a smoother fade transition 14290 * when scrolling occurs. 14291 * 14292 * @return the intensity of the top fade as a float between 0.0f and 1.0f 14293 */ getTopFadingEdgeStrength()14294 protected float getTopFadingEdgeStrength() { 14295 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 14296 } 14297 14298 /** 14299 * Returns the strength, or intensity, of the bottom faded edge. The strength is 14300 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14301 * returns 0.0 or 1.0 but no value in between. 14302 * 14303 * Subclasses should override this method to provide a smoother fade transition 14304 * when scrolling occurs. 14305 * 14306 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 14307 */ getBottomFadingEdgeStrength()14308 protected float getBottomFadingEdgeStrength() { 14309 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 14310 computeVerticalScrollRange() ? 1.0f : 0.0f; 14311 } 14312 14313 /** 14314 * Returns the strength, or intensity, of the left faded edge. The strength is 14315 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14316 * returns 0.0 or 1.0 but no value in between. 14317 * 14318 * Subclasses should override this method to provide a smoother fade transition 14319 * when scrolling occurs. 14320 * 14321 * @return the intensity of the left fade as a float between 0.0f and 1.0f 14322 */ getLeftFadingEdgeStrength()14323 protected float getLeftFadingEdgeStrength() { 14324 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 14325 } 14326 14327 /** 14328 * Returns the strength, or intensity, of the right faded edge. The strength is 14329 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 14330 * returns 0.0 or 1.0 but no value in between. 14331 * 14332 * Subclasses should override this method to provide a smoother fade transition 14333 * when scrolling occurs. 14334 * 14335 * @return the intensity of the right fade as a float between 0.0f and 1.0f 14336 */ getRightFadingEdgeStrength()14337 protected float getRightFadingEdgeStrength() { 14338 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 14339 computeHorizontalScrollRange() ? 1.0f : 0.0f; 14340 } 14341 14342 /** 14343 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 14344 * scrollbar is not drawn by default.</p> 14345 * 14346 * @return true if the horizontal scrollbar should be painted, false 14347 * otherwise 14348 * 14349 * @see #setHorizontalScrollBarEnabled(boolean) 14350 */ isHorizontalScrollBarEnabled()14351 public boolean isHorizontalScrollBarEnabled() { 14352 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 14353 } 14354 14355 /** 14356 * <p>Define whether the horizontal scrollbar should be drawn or not. The 14357 * scrollbar is not drawn by default.</p> 14358 * 14359 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 14360 * be painted 14361 * 14362 * @see #isHorizontalScrollBarEnabled() 14363 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)14364 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 14365 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 14366 mViewFlags ^= SCROLLBARS_HORIZONTAL; 14367 computeOpaqueFlags(); 14368 resolvePadding(); 14369 } 14370 } 14371 14372 /** 14373 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 14374 * scrollbar is not drawn by default.</p> 14375 * 14376 * @return true if the vertical scrollbar should be painted, false 14377 * otherwise 14378 * 14379 * @see #setVerticalScrollBarEnabled(boolean) 14380 */ isVerticalScrollBarEnabled()14381 public boolean isVerticalScrollBarEnabled() { 14382 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 14383 } 14384 14385 /** 14386 * <p>Define whether the vertical scrollbar should be drawn or not. The 14387 * scrollbar is not drawn by default.</p> 14388 * 14389 * @param verticalScrollBarEnabled true if the vertical scrollbar should 14390 * be painted 14391 * 14392 * @see #isVerticalScrollBarEnabled() 14393 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)14394 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 14395 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 14396 mViewFlags ^= SCROLLBARS_VERTICAL; 14397 computeOpaqueFlags(); 14398 resolvePadding(); 14399 } 14400 } 14401 14402 /** 14403 * @hide 14404 */ recomputePadding()14405 protected void recomputePadding() { 14406 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 14407 } 14408 14409 /** 14410 * Define whether scrollbars will fade when the view is not scrolling. 14411 * 14412 * @param fadeScrollbars whether to enable fading 14413 * 14414 * @attr ref android.R.styleable#View_fadeScrollbars 14415 */ setScrollbarFadingEnabled(boolean fadeScrollbars)14416 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 14417 initScrollCache(); 14418 final ScrollabilityCache scrollabilityCache = mScrollCache; 14419 scrollabilityCache.fadeScrollBars = fadeScrollbars; 14420 if (fadeScrollbars) { 14421 scrollabilityCache.state = ScrollabilityCache.OFF; 14422 } else { 14423 scrollabilityCache.state = ScrollabilityCache.ON; 14424 } 14425 } 14426 14427 /** 14428 * 14429 * Returns true if scrollbars will fade when this view is not scrolling 14430 * 14431 * @return true if scrollbar fading is enabled 14432 * 14433 * @attr ref android.R.styleable#View_fadeScrollbars 14434 */ isScrollbarFadingEnabled()14435 public boolean isScrollbarFadingEnabled() { 14436 return mScrollCache != null && mScrollCache.fadeScrollBars; 14437 } 14438 14439 /** 14440 * 14441 * Returns the delay before scrollbars fade. 14442 * 14443 * @return the delay before scrollbars fade 14444 * 14445 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 14446 */ getScrollBarDefaultDelayBeforeFade()14447 public int getScrollBarDefaultDelayBeforeFade() { 14448 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 14449 mScrollCache.scrollBarDefaultDelayBeforeFade; 14450 } 14451 14452 /** 14453 * Define the delay before scrollbars fade. 14454 * 14455 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 14456 * 14457 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 14458 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)14459 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 14460 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 14461 } 14462 14463 /** 14464 * 14465 * Returns the scrollbar fade duration. 14466 * 14467 * @return the scrollbar fade duration 14468 * 14469 * @attr ref android.R.styleable#View_scrollbarFadeDuration 14470 */ getScrollBarFadeDuration()14471 public int getScrollBarFadeDuration() { 14472 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 14473 mScrollCache.scrollBarFadeDuration; 14474 } 14475 14476 /** 14477 * Define the scrollbar fade duration. 14478 * 14479 * @param scrollBarFadeDuration - the scrollbar fade duration 14480 * 14481 * @attr ref android.R.styleable#View_scrollbarFadeDuration 14482 */ setScrollBarFadeDuration(int scrollBarFadeDuration)14483 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 14484 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 14485 } 14486 14487 /** 14488 * 14489 * Returns the scrollbar size. 14490 * 14491 * @return the scrollbar size 14492 * 14493 * @attr ref android.R.styleable#View_scrollbarSize 14494 */ getScrollBarSize()14495 public int getScrollBarSize() { 14496 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 14497 mScrollCache.scrollBarSize; 14498 } 14499 14500 /** 14501 * Define the scrollbar size. 14502 * 14503 * @param scrollBarSize - the scrollbar size 14504 * 14505 * @attr ref android.R.styleable#View_scrollbarSize 14506 */ setScrollBarSize(int scrollBarSize)14507 public void setScrollBarSize(int scrollBarSize) { 14508 getScrollCache().scrollBarSize = scrollBarSize; 14509 } 14510 14511 /** 14512 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 14513 * inset. When inset, they add to the padding of the view. And the scrollbars 14514 * can be drawn inside the padding area or on the edge of the view. For example, 14515 * if a view has a background drawable and you want to draw the scrollbars 14516 * inside the padding specified by the drawable, you can use 14517 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 14518 * appear at the edge of the view, ignoring the padding, then you can use 14519 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 14520 * @param style the style of the scrollbars. Should be one of 14521 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 14522 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 14523 * @see #SCROLLBARS_INSIDE_OVERLAY 14524 * @see #SCROLLBARS_INSIDE_INSET 14525 * @see #SCROLLBARS_OUTSIDE_OVERLAY 14526 * @see #SCROLLBARS_OUTSIDE_INSET 14527 * 14528 * @attr ref android.R.styleable#View_scrollbarStyle 14529 */ setScrollBarStyle(@crollBarStyle int style)14530 public void setScrollBarStyle(@ScrollBarStyle int style) { 14531 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 14532 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 14533 computeOpaqueFlags(); 14534 resolvePadding(); 14535 } 14536 } 14537 14538 /** 14539 * <p>Returns the current scrollbar style.</p> 14540 * @return the current scrollbar style 14541 * @see #SCROLLBARS_INSIDE_OVERLAY 14542 * @see #SCROLLBARS_INSIDE_INSET 14543 * @see #SCROLLBARS_OUTSIDE_OVERLAY 14544 * @see #SCROLLBARS_OUTSIDE_INSET 14545 * 14546 * @attr ref android.R.styleable#View_scrollbarStyle 14547 */ 14548 @ViewDebug.ExportedProperty(mapping = { 14549 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 14550 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 14551 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 14552 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 14553 }) 14554 @ScrollBarStyle getScrollBarStyle()14555 public int getScrollBarStyle() { 14556 return mViewFlags & SCROLLBARS_STYLE_MASK; 14557 } 14558 14559 /** 14560 * <p>Compute the horizontal range that the horizontal scrollbar 14561 * represents.</p> 14562 * 14563 * <p>The range is expressed in arbitrary units that must be the same as the 14564 * units used by {@link #computeHorizontalScrollExtent()} and 14565 * {@link #computeHorizontalScrollOffset()}.</p> 14566 * 14567 * <p>The default range is the drawing width of this view.</p> 14568 * 14569 * @return the total horizontal range represented by the horizontal 14570 * scrollbar 14571 * 14572 * @see #computeHorizontalScrollExtent() 14573 * @see #computeHorizontalScrollOffset() 14574 * @see android.widget.ScrollBarDrawable 14575 */ computeHorizontalScrollRange()14576 protected int computeHorizontalScrollRange() { 14577 return getWidth(); 14578 } 14579 14580 /** 14581 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 14582 * within the horizontal range. This value is used to compute the position 14583 * of the thumb within the scrollbar's track.</p> 14584 * 14585 * <p>The range is expressed in arbitrary units that must be the same as the 14586 * units used by {@link #computeHorizontalScrollRange()} and 14587 * {@link #computeHorizontalScrollExtent()}.</p> 14588 * 14589 * <p>The default offset is the scroll offset of this view.</p> 14590 * 14591 * @return the horizontal offset of the scrollbar's thumb 14592 * 14593 * @see #computeHorizontalScrollRange() 14594 * @see #computeHorizontalScrollExtent() 14595 * @see android.widget.ScrollBarDrawable 14596 */ computeHorizontalScrollOffset()14597 protected int computeHorizontalScrollOffset() { 14598 return mScrollX; 14599 } 14600 14601 /** 14602 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 14603 * within the horizontal range. This value is used to compute the length 14604 * of the thumb within the scrollbar's track.</p> 14605 * 14606 * <p>The range is expressed in arbitrary units that must be the same as the 14607 * units used by {@link #computeHorizontalScrollRange()} and 14608 * {@link #computeHorizontalScrollOffset()}.</p> 14609 * 14610 * <p>The default extent is the drawing width of this view.</p> 14611 * 14612 * @return the horizontal extent of the scrollbar's thumb 14613 * 14614 * @see #computeHorizontalScrollRange() 14615 * @see #computeHorizontalScrollOffset() 14616 * @see android.widget.ScrollBarDrawable 14617 */ computeHorizontalScrollExtent()14618 protected int computeHorizontalScrollExtent() { 14619 return getWidth(); 14620 } 14621 14622 /** 14623 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 14624 * 14625 * <p>The range is expressed in arbitrary units that must be the same as the 14626 * units used by {@link #computeVerticalScrollExtent()} and 14627 * {@link #computeVerticalScrollOffset()}.</p> 14628 * 14629 * @return the total vertical range represented by the vertical scrollbar 14630 * 14631 * <p>The default range is the drawing height of this view.</p> 14632 * 14633 * @see #computeVerticalScrollExtent() 14634 * @see #computeVerticalScrollOffset() 14635 * @see android.widget.ScrollBarDrawable 14636 */ computeVerticalScrollRange()14637 protected int computeVerticalScrollRange() { 14638 return getHeight(); 14639 } 14640 14641 /** 14642 * <p>Compute the vertical offset of the vertical scrollbar's thumb 14643 * within the horizontal range. This value is used to compute the position 14644 * of the thumb within the scrollbar's track.</p> 14645 * 14646 * <p>The range is expressed in arbitrary units that must be the same as the 14647 * units used by {@link #computeVerticalScrollRange()} and 14648 * {@link #computeVerticalScrollExtent()}.</p> 14649 * 14650 * <p>The default offset is the scroll offset of this view.</p> 14651 * 14652 * @return the vertical offset of the scrollbar's thumb 14653 * 14654 * @see #computeVerticalScrollRange() 14655 * @see #computeVerticalScrollExtent() 14656 * @see android.widget.ScrollBarDrawable 14657 */ computeVerticalScrollOffset()14658 protected int computeVerticalScrollOffset() { 14659 return mScrollY; 14660 } 14661 14662 /** 14663 * <p>Compute the vertical extent of the vertical scrollbar's thumb 14664 * within the vertical range. This value is used to compute the length 14665 * of the thumb within the scrollbar's track.</p> 14666 * 14667 * <p>The range is expressed in arbitrary units that must be the same as the 14668 * units used by {@link #computeVerticalScrollRange()} and 14669 * {@link #computeVerticalScrollOffset()}.</p> 14670 * 14671 * <p>The default extent is the drawing height of this view.</p> 14672 * 14673 * @return the vertical extent of the scrollbar's thumb 14674 * 14675 * @see #computeVerticalScrollRange() 14676 * @see #computeVerticalScrollOffset() 14677 * @see android.widget.ScrollBarDrawable 14678 */ computeVerticalScrollExtent()14679 protected int computeVerticalScrollExtent() { 14680 return getHeight(); 14681 } 14682 14683 /** 14684 * Check if this view can be scrolled horizontally in a certain direction. 14685 * 14686 * @param direction Negative to check scrolling left, positive to check scrolling right. 14687 * @return true if this view can be scrolled in the specified direction, false otherwise. 14688 */ canScrollHorizontally(int direction)14689 public boolean canScrollHorizontally(int direction) { 14690 final int offset = computeHorizontalScrollOffset(); 14691 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 14692 if (range == 0) return false; 14693 if (direction < 0) { 14694 return offset > 0; 14695 } else { 14696 return offset < range - 1; 14697 } 14698 } 14699 14700 /** 14701 * Check if this view can be scrolled vertically in a certain direction. 14702 * 14703 * @param direction Negative to check scrolling up, positive to check scrolling down. 14704 * @return true if this view can be scrolled in the specified direction, false otherwise. 14705 */ canScrollVertically(int direction)14706 public boolean canScrollVertically(int direction) { 14707 final int offset = computeVerticalScrollOffset(); 14708 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 14709 if (range == 0) return false; 14710 if (direction < 0) { 14711 return offset > 0; 14712 } else { 14713 return offset < range - 1; 14714 } 14715 } 14716 getScrollIndicatorBounds(@onNull Rect out)14717 void getScrollIndicatorBounds(@NonNull Rect out) { 14718 out.left = mScrollX; 14719 out.right = mScrollX + mRight - mLeft; 14720 out.top = mScrollY; 14721 out.bottom = mScrollY + mBottom - mTop; 14722 } 14723 onDrawScrollIndicators(Canvas c)14724 private void onDrawScrollIndicators(Canvas c) { 14725 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 14726 // No scroll indicators enabled. 14727 return; 14728 } 14729 14730 final Drawable dr = mScrollIndicatorDrawable; 14731 if (dr == null) { 14732 // Scroll indicators aren't supported here. 14733 return; 14734 } 14735 14736 final int h = dr.getIntrinsicHeight(); 14737 final int w = dr.getIntrinsicWidth(); 14738 final Rect rect = mAttachInfo.mTmpInvalRect; 14739 getScrollIndicatorBounds(rect); 14740 14741 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 14742 final boolean canScrollUp = canScrollVertically(-1); 14743 if (canScrollUp) { 14744 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 14745 dr.draw(c); 14746 } 14747 } 14748 14749 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 14750 final boolean canScrollDown = canScrollVertically(1); 14751 if (canScrollDown) { 14752 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 14753 dr.draw(c); 14754 } 14755 } 14756 14757 final int leftRtl; 14758 final int rightRtl; 14759 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 14760 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 14761 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 14762 } else { 14763 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 14764 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 14765 } 14766 14767 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 14768 if ((mPrivateFlags3 & leftMask) != 0) { 14769 final boolean canScrollLeft = canScrollHorizontally(-1); 14770 if (canScrollLeft) { 14771 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 14772 dr.draw(c); 14773 } 14774 } 14775 14776 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 14777 if ((mPrivateFlags3 & rightMask) != 0) { 14778 final boolean canScrollRight = canScrollHorizontally(1); 14779 if (canScrollRight) { 14780 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 14781 dr.draw(c); 14782 } 14783 } 14784 } 14785 getHorizontalScrollBarBounds(Rect bounds)14786 private void getHorizontalScrollBarBounds(Rect bounds) { 14787 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 14788 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 14789 && !isVerticalScrollBarHidden(); 14790 final int size = getHorizontalScrollbarHeight(); 14791 final int verticalScrollBarGap = drawVerticalScrollBar ? 14792 getVerticalScrollbarWidth() : 0; 14793 final int width = mRight - mLeft; 14794 final int height = mBottom - mTop; 14795 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 14796 bounds.left = mScrollX + (mPaddingLeft & inside); 14797 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 14798 bounds.bottom = bounds.top + size; 14799 } 14800 getVerticalScrollBarBounds(Rect bounds)14801 private void getVerticalScrollBarBounds(Rect bounds) { 14802 if (mRoundScrollbarRenderer == null) { 14803 getStraightVerticalScrollBarBounds(bounds); 14804 } else { 14805 getRoundVerticalScrollBarBounds(bounds); 14806 } 14807 } 14808 getRoundVerticalScrollBarBounds(Rect bounds)14809 private void getRoundVerticalScrollBarBounds(Rect bounds) { 14810 final int width = mRight - mLeft; 14811 final int height = mBottom - mTop; 14812 // Do not take padding into account as we always want the scrollbars 14813 // to hug the screen for round wearable devices. 14814 bounds.left = mScrollX; 14815 bounds.top = mScrollY; 14816 bounds.right = bounds.left + width; 14817 bounds.bottom = mScrollY + height; 14818 } 14819 getStraightVerticalScrollBarBounds(Rect bounds)14820 private void getStraightVerticalScrollBarBounds(Rect bounds) { 14821 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 14822 final int size = getVerticalScrollbarWidth(); 14823 int verticalScrollbarPosition = mVerticalScrollbarPosition; 14824 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 14825 verticalScrollbarPosition = isLayoutRtl() ? 14826 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 14827 } 14828 final int width = mRight - mLeft; 14829 final int height = mBottom - mTop; 14830 switch (verticalScrollbarPosition) { 14831 default: 14832 case SCROLLBAR_POSITION_RIGHT: 14833 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 14834 break; 14835 case SCROLLBAR_POSITION_LEFT: 14836 bounds.left = mScrollX + (mUserPaddingLeft & inside); 14837 break; 14838 } 14839 bounds.top = mScrollY + (mPaddingTop & inside); 14840 bounds.right = bounds.left + size; 14841 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 14842 } 14843 14844 /** 14845 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 14846 * scrollbars are painted only if they have been awakened first.</p> 14847 * 14848 * @param canvas the canvas on which to draw the scrollbars 14849 * 14850 * @see #awakenScrollBars(int) 14851 */ onDrawScrollBars(Canvas canvas)14852 protected final void onDrawScrollBars(Canvas canvas) { 14853 // scrollbars are drawn only when the animation is running 14854 final ScrollabilityCache cache = mScrollCache; 14855 14856 if (cache != null) { 14857 14858 int state = cache.state; 14859 14860 if (state == ScrollabilityCache.OFF) { 14861 return; 14862 } 14863 14864 boolean invalidate = false; 14865 14866 if (state == ScrollabilityCache.FADING) { 14867 // We're fading -- get our fade interpolation 14868 if (cache.interpolatorValues == null) { 14869 cache.interpolatorValues = new float[1]; 14870 } 14871 14872 float[] values = cache.interpolatorValues; 14873 14874 // Stops the animation if we're done 14875 if (cache.scrollBarInterpolator.timeToValues(values) == 14876 Interpolator.Result.FREEZE_END) { 14877 cache.state = ScrollabilityCache.OFF; 14878 } else { 14879 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 14880 } 14881 14882 // This will make the scroll bars inval themselves after 14883 // drawing. We only want this when we're fading so that 14884 // we prevent excessive redraws 14885 invalidate = true; 14886 } else { 14887 // We're just on -- but we may have been fading before so 14888 // reset alpha 14889 cache.scrollBar.mutate().setAlpha(255); 14890 } 14891 14892 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 14893 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 14894 && !isVerticalScrollBarHidden(); 14895 14896 // Fork out the scroll bar drawing for round wearable devices. 14897 if (mRoundScrollbarRenderer != null) { 14898 if (drawVerticalScrollBar) { 14899 final Rect bounds = cache.mScrollBarBounds; 14900 getVerticalScrollBarBounds(bounds); 14901 mRoundScrollbarRenderer.drawRoundScrollbars( 14902 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 14903 if (invalidate) { 14904 invalidate(); 14905 } 14906 } 14907 // Do not draw horizontal scroll bars for round wearable devices. 14908 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 14909 final ScrollBarDrawable scrollBar = cache.scrollBar; 14910 14911 if (drawHorizontalScrollBar) { 14912 scrollBar.setParameters(computeHorizontalScrollRange(), 14913 computeHorizontalScrollOffset(), 14914 computeHorizontalScrollExtent(), false); 14915 final Rect bounds = cache.mScrollBarBounds; 14916 getHorizontalScrollBarBounds(bounds); 14917 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 14918 bounds.right, bounds.bottom); 14919 if (invalidate) { 14920 invalidate(bounds); 14921 } 14922 } 14923 14924 if (drawVerticalScrollBar) { 14925 scrollBar.setParameters(computeVerticalScrollRange(), 14926 computeVerticalScrollOffset(), 14927 computeVerticalScrollExtent(), true); 14928 final Rect bounds = cache.mScrollBarBounds; 14929 getVerticalScrollBarBounds(bounds); 14930 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 14931 bounds.right, bounds.bottom); 14932 if (invalidate) { 14933 invalidate(bounds); 14934 } 14935 } 14936 } 14937 } 14938 } 14939 14940 /** 14941 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 14942 * FastScroller is visible. 14943 * @return whether to temporarily hide the vertical scrollbar 14944 * @hide 14945 */ isVerticalScrollBarHidden()14946 protected boolean isVerticalScrollBarHidden() { 14947 return false; 14948 } 14949 14950 /** 14951 * <p>Draw the horizontal scrollbar if 14952 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 14953 * 14954 * @param canvas the canvas on which to draw the scrollbar 14955 * @param scrollBar the scrollbar's drawable 14956 * 14957 * @see #isHorizontalScrollBarEnabled() 14958 * @see #computeHorizontalScrollRange() 14959 * @see #computeHorizontalScrollExtent() 14960 * @see #computeHorizontalScrollOffset() 14961 * @see android.widget.ScrollBarDrawable 14962 * @hide 14963 */ onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)14964 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 14965 int l, int t, int r, int b) { 14966 scrollBar.setBounds(l, t, r, b); 14967 scrollBar.draw(canvas); 14968 } 14969 14970 /** 14971 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 14972 * returns true.</p> 14973 * 14974 * @param canvas the canvas on which to draw the scrollbar 14975 * @param scrollBar the scrollbar's drawable 14976 * 14977 * @see #isVerticalScrollBarEnabled() 14978 * @see #computeVerticalScrollRange() 14979 * @see #computeVerticalScrollExtent() 14980 * @see #computeVerticalScrollOffset() 14981 * @see android.widget.ScrollBarDrawable 14982 * @hide 14983 */ onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)14984 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 14985 int l, int t, int r, int b) { 14986 scrollBar.setBounds(l, t, r, b); 14987 scrollBar.draw(canvas); 14988 } 14989 14990 /** 14991 * Implement this to do your drawing. 14992 * 14993 * @param canvas the canvas on which the background will be drawn 14994 */ onDraw(Canvas canvas)14995 protected void onDraw(Canvas canvas) { 14996 } 14997 14998 /* 14999 * Caller is responsible for calling requestLayout if necessary. 15000 * (This allows addViewInLayout to not request a new layout.) 15001 */ assignParent(ViewParent parent)15002 void assignParent(ViewParent parent) { 15003 if (mParent == null) { 15004 mParent = parent; 15005 } else if (parent == null) { 15006 mParent = null; 15007 } else { 15008 throw new RuntimeException("view " + this + " being added, but" 15009 + " it already has a parent"); 15010 } 15011 } 15012 15013 /** 15014 * This is called when the view is attached to a window. At this point it 15015 * has a Surface and will start drawing. Note that this function is 15016 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 15017 * however it may be called any time before the first onDraw -- including 15018 * before or after {@link #onMeasure(int, int)}. 15019 * 15020 * @see #onDetachedFromWindow() 15021 */ 15022 @CallSuper onAttachedToWindow()15023 protected void onAttachedToWindow() { 15024 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 15025 mParent.requestTransparentRegion(this); 15026 } 15027 15028 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15029 15030 jumpDrawablesToCurrentState(); 15031 15032 resetSubtreeAccessibilityStateChanged(); 15033 15034 // rebuild, since Outline not maintained while View is detached 15035 rebuildOutline(); 15036 15037 if (isFocused()) { 15038 InputMethodManager imm = InputMethodManager.peekInstance(); 15039 if (imm != null) { 15040 imm.focusIn(this); 15041 } 15042 } 15043 } 15044 15045 /** 15046 * Resolve all RTL related properties. 15047 * 15048 * @return true if resolution of RTL properties has been done 15049 * 15050 * @hide 15051 */ resolveRtlPropertiesIfNeeded()15052 public boolean resolveRtlPropertiesIfNeeded() { 15053 if (!needRtlPropertiesResolution()) return false; 15054 15055 // Order is important here: LayoutDirection MUST be resolved first 15056 if (!isLayoutDirectionResolved()) { 15057 resolveLayoutDirection(); 15058 resolveLayoutParams(); 15059 } 15060 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 15061 if (!isTextDirectionResolved()) { 15062 resolveTextDirection(); 15063 } 15064 if (!isTextAlignmentResolved()) { 15065 resolveTextAlignment(); 15066 } 15067 // Should resolve Drawables before Padding because we need the layout direction of the 15068 // Drawable to correctly resolve Padding. 15069 if (!areDrawablesResolved()) { 15070 resolveDrawables(); 15071 } 15072 if (!isPaddingResolved()) { 15073 resolvePadding(); 15074 } 15075 onRtlPropertiesChanged(getLayoutDirection()); 15076 return true; 15077 } 15078 15079 /** 15080 * Reset resolution of all RTL related properties. 15081 * 15082 * @hide 15083 */ resetRtlProperties()15084 public void resetRtlProperties() { 15085 resetResolvedLayoutDirection(); 15086 resetResolvedTextDirection(); 15087 resetResolvedTextAlignment(); 15088 resetResolvedPadding(); 15089 resetResolvedDrawables(); 15090 } 15091 15092 /** 15093 * @see #onScreenStateChanged(int) 15094 */ dispatchScreenStateChanged(int screenState)15095 void dispatchScreenStateChanged(int screenState) { 15096 onScreenStateChanged(screenState); 15097 } 15098 15099 /** 15100 * This method is called whenever the state of the screen this view is 15101 * attached to changes. A state change will usually occurs when the screen 15102 * turns on or off (whether it happens automatically or the user does it 15103 * manually.) 15104 * 15105 * @param screenState The new state of the screen. Can be either 15106 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 15107 */ onScreenStateChanged(int screenState)15108 public void onScreenStateChanged(int screenState) { 15109 } 15110 15111 /** 15112 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 15113 */ hasRtlSupport()15114 private boolean hasRtlSupport() { 15115 return mContext.getApplicationInfo().hasRtlSupport(); 15116 } 15117 15118 /** 15119 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 15120 * RTL not supported) 15121 */ isRtlCompatibilityMode()15122 private boolean isRtlCompatibilityMode() { 15123 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 15124 return targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport(); 15125 } 15126 15127 /** 15128 * @return true if RTL properties need resolution. 15129 * 15130 */ needRtlPropertiesResolution()15131 private boolean needRtlPropertiesResolution() { 15132 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 15133 } 15134 15135 /** 15136 * Called when any RTL property (layout direction or text direction or text alignment) has 15137 * been changed. 15138 * 15139 * Subclasses need to override this method to take care of cached information that depends on the 15140 * resolved layout direction, or to inform child views that inherit their layout direction. 15141 * 15142 * The default implementation does nothing. 15143 * 15144 * @param layoutDirection the direction of the layout 15145 * 15146 * @see #LAYOUT_DIRECTION_LTR 15147 * @see #LAYOUT_DIRECTION_RTL 15148 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)15149 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 15150 } 15151 15152 /** 15153 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 15154 * that the parent directionality can and will be resolved before its children. 15155 * 15156 * @return true if resolution has been done, false otherwise. 15157 * 15158 * @hide 15159 */ resolveLayoutDirection()15160 public boolean resolveLayoutDirection() { 15161 // Clear any previous layout direction resolution 15162 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15163 15164 if (hasRtlSupport()) { 15165 // Set resolved depending on layout direction 15166 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 15167 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 15168 case LAYOUT_DIRECTION_INHERIT: 15169 // We cannot resolve yet. LTR is by default and let the resolution happen again 15170 // later to get the correct resolved value 15171 if (!canResolveLayoutDirection()) return false; 15172 15173 // Parent has not yet resolved, LTR is still the default 15174 try { 15175 if (!mParent.isLayoutDirectionResolved()) return false; 15176 15177 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 15178 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15179 } 15180 } catch (AbstractMethodError e) { 15181 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15182 " does not fully implement ViewParent", e); 15183 } 15184 break; 15185 case LAYOUT_DIRECTION_RTL: 15186 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15187 break; 15188 case LAYOUT_DIRECTION_LOCALE: 15189 if((LAYOUT_DIRECTION_RTL == 15190 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 15191 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 15192 } 15193 break; 15194 default: 15195 // Nothing to do, LTR by default 15196 } 15197 } 15198 15199 // Set to resolved 15200 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15201 return true; 15202 } 15203 15204 /** 15205 * Check if layout direction resolution can be done. 15206 * 15207 * @return true if layout direction resolution can be done otherwise return false. 15208 */ canResolveLayoutDirection()15209 public boolean canResolveLayoutDirection() { 15210 switch (getRawLayoutDirection()) { 15211 case LAYOUT_DIRECTION_INHERIT: 15212 if (mParent != null) { 15213 try { 15214 return mParent.canResolveLayoutDirection(); 15215 } catch (AbstractMethodError e) { 15216 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15217 " does not fully implement ViewParent", e); 15218 } 15219 } 15220 return false; 15221 15222 default: 15223 return true; 15224 } 15225 } 15226 15227 /** 15228 * Reset the resolved layout direction. Layout direction will be resolved during a call to 15229 * {@link #onMeasure(int, int)}. 15230 * 15231 * @hide 15232 */ resetResolvedLayoutDirection()15233 public void resetResolvedLayoutDirection() { 15234 // Reset the current resolved bits 15235 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 15236 } 15237 15238 /** 15239 * @return true if the layout direction is inherited. 15240 * 15241 * @hide 15242 */ isLayoutDirectionInherited()15243 public boolean isLayoutDirectionInherited() { 15244 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 15245 } 15246 15247 /** 15248 * @return true if layout direction has been resolved. 15249 */ isLayoutDirectionResolved()15250 public boolean isLayoutDirectionResolved() { 15251 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 15252 } 15253 15254 /** 15255 * Return if padding has been resolved 15256 * 15257 * @hide 15258 */ isPaddingResolved()15259 boolean isPaddingResolved() { 15260 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 15261 } 15262 15263 /** 15264 * Resolves padding depending on layout direction, if applicable, and 15265 * recomputes internal padding values to adjust for scroll bars. 15266 * 15267 * @hide 15268 */ resolvePadding()15269 public void resolvePadding() { 15270 final int resolvedLayoutDirection = getLayoutDirection(); 15271 15272 if (!isRtlCompatibilityMode()) { 15273 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 15274 // If start / end padding are defined, they will be resolved (hence overriding) to 15275 // left / right or right / left depending on the resolved layout direction. 15276 // If start / end padding are not defined, use the left / right ones. 15277 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 15278 Rect padding = sThreadLocal.get(); 15279 if (padding == null) { 15280 padding = new Rect(); 15281 sThreadLocal.set(padding); 15282 } 15283 mBackground.getPadding(padding); 15284 if (!mLeftPaddingDefined) { 15285 mUserPaddingLeftInitial = padding.left; 15286 } 15287 if (!mRightPaddingDefined) { 15288 mUserPaddingRightInitial = padding.right; 15289 } 15290 } 15291 switch (resolvedLayoutDirection) { 15292 case LAYOUT_DIRECTION_RTL: 15293 if (mUserPaddingStart != UNDEFINED_PADDING) { 15294 mUserPaddingRight = mUserPaddingStart; 15295 } else { 15296 mUserPaddingRight = mUserPaddingRightInitial; 15297 } 15298 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15299 mUserPaddingLeft = mUserPaddingEnd; 15300 } else { 15301 mUserPaddingLeft = mUserPaddingLeftInitial; 15302 } 15303 break; 15304 case LAYOUT_DIRECTION_LTR: 15305 default: 15306 if (mUserPaddingStart != UNDEFINED_PADDING) { 15307 mUserPaddingLeft = mUserPaddingStart; 15308 } else { 15309 mUserPaddingLeft = mUserPaddingLeftInitial; 15310 } 15311 if (mUserPaddingEnd != UNDEFINED_PADDING) { 15312 mUserPaddingRight = mUserPaddingEnd; 15313 } else { 15314 mUserPaddingRight = mUserPaddingRightInitial; 15315 } 15316 } 15317 15318 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 15319 } 15320 15321 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 15322 onRtlPropertiesChanged(resolvedLayoutDirection); 15323 15324 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 15325 } 15326 15327 /** 15328 * Reset the resolved layout direction. 15329 * 15330 * @hide 15331 */ resetResolvedPadding()15332 public void resetResolvedPadding() { 15333 resetResolvedPaddingInternal(); 15334 } 15335 15336 /** 15337 * Used when we only want to reset *this* view's padding and not trigger overrides 15338 * in ViewGroup that reset children too. 15339 */ resetResolvedPaddingInternal()15340 void resetResolvedPaddingInternal() { 15341 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 15342 } 15343 15344 /** 15345 * This is called when the view is detached from a window. At this point it 15346 * no longer has a surface for drawing. 15347 * 15348 * @see #onAttachedToWindow() 15349 */ 15350 @CallSuper onDetachedFromWindow()15351 protected void onDetachedFromWindow() { 15352 } 15353 15354 /** 15355 * This is a framework-internal mirror of onDetachedFromWindow() that's called 15356 * after onDetachedFromWindow(). 15357 * 15358 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 15359 * The super method should be called at the end of the overridden method to ensure 15360 * subclasses are destroyed first 15361 * 15362 * @hide 15363 */ 15364 @CallSuper onDetachedFromWindowInternal()15365 protected void onDetachedFromWindowInternal() { 15366 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 15367 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 15368 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 15369 15370 removeUnsetPressCallback(); 15371 removeLongPressCallback(); 15372 removePerformClickCallback(); 15373 removeSendViewScrolledAccessibilityEventCallback(); 15374 stopNestedScroll(); 15375 15376 // Anything that started animating right before detach should already 15377 // be in its final state when re-attached. 15378 jumpDrawablesToCurrentState(); 15379 15380 destroyDrawingCache(); 15381 15382 cleanupDraw(); 15383 mCurrentAnimation = null; 15384 } 15385 cleanupDraw()15386 private void cleanupDraw() { 15387 resetDisplayList(); 15388 if (mAttachInfo != null) { 15389 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 15390 } 15391 } 15392 invalidateInheritedLayoutMode(int layoutModeOfRoot)15393 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 15394 } 15395 15396 /** 15397 * @return The number of times this view has been attached to a window 15398 */ getWindowAttachCount()15399 protected int getWindowAttachCount() { 15400 return mWindowAttachCount; 15401 } 15402 15403 /** 15404 * Retrieve a unique token identifying the window this view is attached to. 15405 * @return Return the window's token for use in 15406 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 15407 */ getWindowToken()15408 public IBinder getWindowToken() { 15409 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 15410 } 15411 15412 /** 15413 * Retrieve the {@link WindowId} for the window this view is 15414 * currently attached to. 15415 */ getWindowId()15416 public WindowId getWindowId() { 15417 if (mAttachInfo == null) { 15418 return null; 15419 } 15420 if (mAttachInfo.mWindowId == null) { 15421 try { 15422 mAttachInfo.mIWindowId = mAttachInfo.mSession.getWindowId( 15423 mAttachInfo.mWindowToken); 15424 mAttachInfo.mWindowId = new WindowId( 15425 mAttachInfo.mIWindowId); 15426 } catch (RemoteException e) { 15427 } 15428 } 15429 return mAttachInfo.mWindowId; 15430 } 15431 15432 /** 15433 * Retrieve a unique token identifying the top-level "real" window of 15434 * the window that this view is attached to. That is, this is like 15435 * {@link #getWindowToken}, except if the window this view in is a panel 15436 * window (attached to another containing window), then the token of 15437 * the containing window is returned instead. 15438 * 15439 * @return Returns the associated window token, either 15440 * {@link #getWindowToken()} or the containing window's token. 15441 */ getApplicationWindowToken()15442 public IBinder getApplicationWindowToken() { 15443 AttachInfo ai = mAttachInfo; 15444 if (ai != null) { 15445 IBinder appWindowToken = ai.mPanelParentWindowToken; 15446 if (appWindowToken == null) { 15447 appWindowToken = ai.mWindowToken; 15448 } 15449 return appWindowToken; 15450 } 15451 return null; 15452 } 15453 15454 /** 15455 * Gets the logical display to which the view's window has been attached. 15456 * 15457 * @return The logical display, or null if the view is not currently attached to a window. 15458 */ getDisplay()15459 public Display getDisplay() { 15460 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 15461 } 15462 15463 /** 15464 * Retrieve private session object this view hierarchy is using to 15465 * communicate with the window manager. 15466 * @return the session object to communicate with the window manager 15467 */ getWindowSession()15468 /*package*/ IWindowSession getWindowSession() { 15469 return mAttachInfo != null ? mAttachInfo.mSession : null; 15470 } 15471 15472 /** 15473 * Return the visibility value of the least visible component passed. 15474 */ combineVisibility(int vis1, int vis2)15475 int combineVisibility(int vis1, int vis2) { 15476 // This works because VISIBLE < INVISIBLE < GONE. 15477 return Math.max(vis1, vis2); 15478 } 15479 15480 /** 15481 * @param info the {@link android.view.View.AttachInfo} to associated with 15482 * this view 15483 */ dispatchAttachedToWindow(AttachInfo info, int visibility)15484 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 15485 mAttachInfo = info; 15486 if (mOverlay != null) { 15487 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 15488 } 15489 mWindowAttachCount++; 15490 // We will need to evaluate the drawable state at least once. 15491 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 15492 if (mFloatingTreeObserver != null) { 15493 info.mTreeObserver.merge(mFloatingTreeObserver); 15494 mFloatingTreeObserver = null; 15495 } 15496 15497 registerPendingFrameMetricsObservers(); 15498 15499 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 15500 mAttachInfo.mScrollContainers.add(this); 15501 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 15502 } 15503 // Transfer all pending runnables. 15504 if (mRunQueue != null) { 15505 mRunQueue.executeActions(info.mHandler); 15506 mRunQueue = null; 15507 } 15508 performCollectViewAttributes(mAttachInfo, visibility); 15509 onAttachedToWindow(); 15510 15511 ListenerInfo li = mListenerInfo; 15512 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 15513 li != null ? li.mOnAttachStateChangeListeners : null; 15514 if (listeners != null && listeners.size() > 0) { 15515 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 15516 // perform the dispatching. The iterator is a safe guard against listeners that 15517 // could mutate the list by calling the various add/remove methods. This prevents 15518 // the array from being modified while we iterate it. 15519 for (OnAttachStateChangeListener listener : listeners) { 15520 listener.onViewAttachedToWindow(this); 15521 } 15522 } 15523 15524 int vis = info.mWindowVisibility; 15525 if (vis != GONE) { 15526 onWindowVisibilityChanged(vis); 15527 if (isShown()) { 15528 // Calling onVisibilityAggregated directly here since the subtree will also 15529 // receive dispatchAttachedToWindow and this same call 15530 onVisibilityAggregated(vis == VISIBLE); 15531 } 15532 } 15533 15534 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 15535 // As all views in the subtree will already receive dispatchAttachedToWindow 15536 // traversing the subtree again here is not desired. 15537 onVisibilityChanged(this, visibility); 15538 15539 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 15540 // If nobody has evaluated the drawable state yet, then do it now. 15541 refreshDrawableState(); 15542 } 15543 needGlobalAttributesUpdate(false); 15544 } 15545 dispatchDetachedFromWindow()15546 void dispatchDetachedFromWindow() { 15547 AttachInfo info = mAttachInfo; 15548 if (info != null) { 15549 int vis = info.mWindowVisibility; 15550 if (vis != GONE) { 15551 onWindowVisibilityChanged(GONE); 15552 if (isShown()) { 15553 // Invoking onVisibilityAggregated directly here since the subtree 15554 // will also receive detached from window 15555 onVisibilityAggregated(false); 15556 } 15557 } 15558 } 15559 15560 onDetachedFromWindow(); 15561 onDetachedFromWindowInternal(); 15562 15563 InputMethodManager imm = InputMethodManager.peekInstance(); 15564 if (imm != null) { 15565 imm.onViewDetachedFromWindow(this); 15566 } 15567 15568 ListenerInfo li = mListenerInfo; 15569 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 15570 li != null ? li.mOnAttachStateChangeListeners : null; 15571 if (listeners != null && listeners.size() > 0) { 15572 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 15573 // perform the dispatching. The iterator is a safe guard against listeners that 15574 // could mutate the list by calling the various add/remove methods. This prevents 15575 // the array from being modified while we iterate it. 15576 for (OnAttachStateChangeListener listener : listeners) { 15577 listener.onViewDetachedFromWindow(this); 15578 } 15579 } 15580 15581 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 15582 mAttachInfo.mScrollContainers.remove(this); 15583 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 15584 } 15585 15586 mAttachInfo = null; 15587 if (mOverlay != null) { 15588 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 15589 } 15590 } 15591 15592 /** 15593 * Cancel any deferred high-level input events that were previously posted to the event queue. 15594 * 15595 * <p>Many views post high-level events such as click handlers to the event queue 15596 * to run deferred in order to preserve a desired user experience - clearing visible 15597 * pressed states before executing, etc. This method will abort any events of this nature 15598 * that are currently in flight.</p> 15599 * 15600 * <p>Custom views that generate their own high-level deferred input events should override 15601 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 15602 * 15603 * <p>This will also cancel pending input events for any child views.</p> 15604 * 15605 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 15606 * This will not impact newer events posted after this call that may occur as a result of 15607 * lower-level input events still waiting in the queue. If you are trying to prevent 15608 * double-submitted events for the duration of some sort of asynchronous transaction 15609 * you should also take other steps to protect against unexpected double inputs e.g. calling 15610 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 15611 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 15612 */ cancelPendingInputEvents()15613 public final void cancelPendingInputEvents() { 15614 dispatchCancelPendingInputEvents(); 15615 } 15616 15617 /** 15618 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 15619 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 15620 */ dispatchCancelPendingInputEvents()15621 void dispatchCancelPendingInputEvents() { 15622 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 15623 onCancelPendingInputEvents(); 15624 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 15625 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 15626 " did not call through to super.onCancelPendingInputEvents()"); 15627 } 15628 } 15629 15630 /** 15631 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 15632 * a parent view. 15633 * 15634 * <p>This method is responsible for removing any pending high-level input events that were 15635 * posted to the event queue to run later. Custom view classes that post their own deferred 15636 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 15637 * {@link android.os.Handler} should override this method, call 15638 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 15639 * </p> 15640 */ onCancelPendingInputEvents()15641 public void onCancelPendingInputEvents() { 15642 removePerformClickCallback(); 15643 cancelLongPress(); 15644 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 15645 } 15646 15647 /** 15648 * Store this view hierarchy's frozen state into the given container. 15649 * 15650 * @param container The SparseArray in which to save the view's state. 15651 * 15652 * @see #restoreHierarchyState(android.util.SparseArray) 15653 * @see #dispatchSaveInstanceState(android.util.SparseArray) 15654 * @see #onSaveInstanceState() 15655 */ saveHierarchyState(SparseArray<Parcelable> container)15656 public void saveHierarchyState(SparseArray<Parcelable> container) { 15657 dispatchSaveInstanceState(container); 15658 } 15659 15660 /** 15661 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 15662 * this view and its children. May be overridden to modify how freezing happens to a 15663 * view's children; for example, some views may want to not store state for their children. 15664 * 15665 * @param container The SparseArray in which to save the view's state. 15666 * 15667 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 15668 * @see #saveHierarchyState(android.util.SparseArray) 15669 * @see #onSaveInstanceState() 15670 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)15671 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 15672 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 15673 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 15674 Parcelable state = onSaveInstanceState(); 15675 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 15676 throw new IllegalStateException( 15677 "Derived class did not call super.onSaveInstanceState()"); 15678 } 15679 if (state != null) { 15680 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 15681 // + ": " + state); 15682 container.put(mID, state); 15683 } 15684 } 15685 } 15686 15687 /** 15688 * Hook allowing a view to generate a representation of its internal state 15689 * that can later be used to create a new instance with that same state. 15690 * This state should only contain information that is not persistent or can 15691 * not be reconstructed later. For example, you will never store your 15692 * current position on screen because that will be computed again when a 15693 * new instance of the view is placed in its view hierarchy. 15694 * <p> 15695 * Some examples of things you may store here: the current cursor position 15696 * in a text view (but usually not the text itself since that is stored in a 15697 * content provider or other persistent storage), the currently selected 15698 * item in a list view. 15699 * 15700 * @return Returns a Parcelable object containing the view's current dynamic 15701 * state, or null if there is nothing interesting to save. The 15702 * default implementation returns null. 15703 * @see #onRestoreInstanceState(android.os.Parcelable) 15704 * @see #saveHierarchyState(android.util.SparseArray) 15705 * @see #dispatchSaveInstanceState(android.util.SparseArray) 15706 * @see #setSaveEnabled(boolean) 15707 */ 15708 @CallSuper onSaveInstanceState()15709 protected Parcelable onSaveInstanceState() { 15710 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 15711 if (mStartActivityRequestWho != null) { 15712 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 15713 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 15714 return state; 15715 } 15716 return BaseSavedState.EMPTY_STATE; 15717 } 15718 15719 /** 15720 * Restore this view hierarchy's frozen state from the given container. 15721 * 15722 * @param container The SparseArray which holds previously frozen states. 15723 * 15724 * @see #saveHierarchyState(android.util.SparseArray) 15725 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 15726 * @see #onRestoreInstanceState(android.os.Parcelable) 15727 */ restoreHierarchyState(SparseArray<Parcelable> container)15728 public void restoreHierarchyState(SparseArray<Parcelable> container) { 15729 dispatchRestoreInstanceState(container); 15730 } 15731 15732 /** 15733 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 15734 * state for this view and its children. May be overridden to modify how restoring 15735 * happens to a view's children; for example, some views may want to not store state 15736 * for their children. 15737 * 15738 * @param container The SparseArray which holds previously saved state. 15739 * 15740 * @see #dispatchSaveInstanceState(android.util.SparseArray) 15741 * @see #restoreHierarchyState(android.util.SparseArray) 15742 * @see #onRestoreInstanceState(android.os.Parcelable) 15743 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)15744 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 15745 if (mID != NO_ID) { 15746 Parcelable state = container.get(mID); 15747 if (state != null) { 15748 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 15749 // + ": " + state); 15750 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 15751 onRestoreInstanceState(state); 15752 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 15753 throw new IllegalStateException( 15754 "Derived class did not call super.onRestoreInstanceState()"); 15755 } 15756 } 15757 } 15758 } 15759 15760 /** 15761 * Hook allowing a view to re-apply a representation of its internal state that had previously 15762 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 15763 * null state. 15764 * 15765 * @param state The frozen state that had previously been returned by 15766 * {@link #onSaveInstanceState}. 15767 * 15768 * @see #onSaveInstanceState() 15769 * @see #restoreHierarchyState(android.util.SparseArray) 15770 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 15771 */ 15772 @CallSuper onRestoreInstanceState(Parcelable state)15773 protected void onRestoreInstanceState(Parcelable state) { 15774 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 15775 if (state != null && !(state instanceof AbsSavedState)) { 15776 throw new IllegalArgumentException("Wrong state class, expecting View State but " 15777 + "received " + state.getClass().toString() + " instead. This usually happens " 15778 + "when two views of different type have the same id in the same hierarchy. " 15779 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 15780 + "other views do not use the same id."); 15781 } 15782 if (state != null && state instanceof BaseSavedState) { 15783 mStartActivityRequestWho = ((BaseSavedState) state).mStartActivityRequestWhoSaved; 15784 } 15785 } 15786 15787 /** 15788 * <p>Return the time at which the drawing of the view hierarchy started.</p> 15789 * 15790 * @return the drawing start time in milliseconds 15791 */ getDrawingTime()15792 public long getDrawingTime() { 15793 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 15794 } 15795 15796 /** 15797 * <p>Enables or disables the duplication of the parent's state into this view. When 15798 * duplication is enabled, this view gets its drawable state from its parent rather 15799 * than from its own internal properties.</p> 15800 * 15801 * <p>Note: in the current implementation, setting this property to true after the 15802 * view was added to a ViewGroup might have no effect at all. This property should 15803 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 15804 * 15805 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 15806 * property is enabled, an exception will be thrown.</p> 15807 * 15808 * <p>Note: if the child view uses and updates additional states which are unknown to the 15809 * parent, these states should not be affected by this method.</p> 15810 * 15811 * @param enabled True to enable duplication of the parent's drawable state, false 15812 * to disable it. 15813 * 15814 * @see #getDrawableState() 15815 * @see #isDuplicateParentStateEnabled() 15816 */ setDuplicateParentStateEnabled(boolean enabled)15817 public void setDuplicateParentStateEnabled(boolean enabled) { 15818 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 15819 } 15820 15821 /** 15822 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 15823 * 15824 * @return True if this view's drawable state is duplicated from the parent, 15825 * false otherwise 15826 * 15827 * @see #getDrawableState() 15828 * @see #setDuplicateParentStateEnabled(boolean) 15829 */ isDuplicateParentStateEnabled()15830 public boolean isDuplicateParentStateEnabled() { 15831 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 15832 } 15833 15834 /** 15835 * <p>Specifies the type of layer backing this view. The layer can be 15836 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 15837 * {@link #LAYER_TYPE_HARDWARE}.</p> 15838 * 15839 * <p>A layer is associated with an optional {@link android.graphics.Paint} 15840 * instance that controls how the layer is composed on screen. The following 15841 * properties of the paint are taken into account when composing the layer:</p> 15842 * <ul> 15843 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 15844 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 15845 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 15846 * </ul> 15847 * 15848 * <p>If this view has an alpha value set to < 1.0 by calling 15849 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 15850 * by this view's alpha value.</p> 15851 * 15852 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 15853 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 15854 * for more information on when and how to use layers.</p> 15855 * 15856 * @param layerType The type of layer to use with this view, must be one of 15857 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 15858 * {@link #LAYER_TYPE_HARDWARE} 15859 * @param paint The paint used to compose the layer. This argument is optional 15860 * and can be null. It is ignored when the layer type is 15861 * {@link #LAYER_TYPE_NONE} 15862 * 15863 * @see #getLayerType() 15864 * @see #LAYER_TYPE_NONE 15865 * @see #LAYER_TYPE_SOFTWARE 15866 * @see #LAYER_TYPE_HARDWARE 15867 * @see #setAlpha(float) 15868 * 15869 * @attr ref android.R.styleable#View_layerType 15870 */ setLayerType(int layerType, @Nullable Paint paint)15871 public void setLayerType(int layerType, @Nullable Paint paint) { 15872 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 15873 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 15874 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 15875 } 15876 15877 boolean typeChanged = mRenderNode.setLayerType(layerType); 15878 15879 if (!typeChanged) { 15880 setLayerPaint(paint); 15881 return; 15882 } 15883 15884 if (layerType != LAYER_TYPE_SOFTWARE) { 15885 // Destroy any previous software drawing cache if present 15886 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 15887 // drawing cache created in View#draw when drawing to a SW canvas. 15888 destroyDrawingCache(); 15889 } 15890 15891 mLayerType = layerType; 15892 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 15893 mRenderNode.setLayerPaint(mLayerPaint); 15894 15895 // draw() behaves differently if we are on a layer, so we need to 15896 // invalidate() here 15897 invalidateParentCaches(); 15898 invalidate(true); 15899 } 15900 15901 /** 15902 * Updates the {@link Paint} object used with the current layer (used only if the current 15903 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 15904 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 15905 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 15906 * ensure that the view gets redrawn immediately. 15907 * 15908 * <p>A layer is associated with an optional {@link android.graphics.Paint} 15909 * instance that controls how the layer is composed on screen. The following 15910 * properties of the paint are taken into account when composing the layer:</p> 15911 * <ul> 15912 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 15913 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 15914 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 15915 * </ul> 15916 * 15917 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 15918 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 15919 * 15920 * @param paint The paint used to compose the layer. This argument is optional 15921 * and can be null. It is ignored when the layer type is 15922 * {@link #LAYER_TYPE_NONE} 15923 * 15924 * @see #setLayerType(int, android.graphics.Paint) 15925 */ setLayerPaint(@ullable Paint paint)15926 public void setLayerPaint(@Nullable Paint paint) { 15927 int layerType = getLayerType(); 15928 if (layerType != LAYER_TYPE_NONE) { 15929 mLayerPaint = paint; 15930 if (layerType == LAYER_TYPE_HARDWARE) { 15931 if (mRenderNode.setLayerPaint(paint)) { 15932 invalidateViewProperty(false, false); 15933 } 15934 } else { 15935 invalidate(); 15936 } 15937 } 15938 } 15939 15940 /** 15941 * Indicates what type of layer is currently associated with this view. By default 15942 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 15943 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 15944 * for more information on the different types of layers. 15945 * 15946 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 15947 * {@link #LAYER_TYPE_HARDWARE} 15948 * 15949 * @see #setLayerType(int, android.graphics.Paint) 15950 * @see #buildLayer() 15951 * @see #LAYER_TYPE_NONE 15952 * @see #LAYER_TYPE_SOFTWARE 15953 * @see #LAYER_TYPE_HARDWARE 15954 */ getLayerType()15955 public int getLayerType() { 15956 return mLayerType; 15957 } 15958 15959 /** 15960 * Forces this view's layer to be created and this view to be rendered 15961 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 15962 * invoking this method will have no effect. 15963 * 15964 * This method can for instance be used to render a view into its layer before 15965 * starting an animation. If this view is complex, rendering into the layer 15966 * before starting the animation will avoid skipping frames. 15967 * 15968 * @throws IllegalStateException If this view is not attached to a window 15969 * 15970 * @see #setLayerType(int, android.graphics.Paint) 15971 */ buildLayer()15972 public void buildLayer() { 15973 if (mLayerType == LAYER_TYPE_NONE) return; 15974 15975 final AttachInfo attachInfo = mAttachInfo; 15976 if (attachInfo == null) { 15977 throw new IllegalStateException("This view must be attached to a window first"); 15978 } 15979 15980 if (getWidth() == 0 || getHeight() == 0) { 15981 return; 15982 } 15983 15984 switch (mLayerType) { 15985 case LAYER_TYPE_HARDWARE: 15986 updateDisplayListIfDirty(); 15987 if (attachInfo.mHardwareRenderer != null && mRenderNode.isValid()) { 15988 attachInfo.mHardwareRenderer.buildLayer(mRenderNode); 15989 } 15990 break; 15991 case LAYER_TYPE_SOFTWARE: 15992 buildDrawingCache(true); 15993 break; 15994 } 15995 } 15996 15997 /** 15998 * Destroys all hardware rendering resources. This method is invoked 15999 * when the system needs to reclaim resources. Upon execution of this 16000 * method, you should free any OpenGL resources created by the view. 16001 * 16002 * Note: you <strong>must</strong> call 16003 * <code>super.destroyHardwareResources()</code> when overriding 16004 * this method. 16005 * 16006 * @hide 16007 */ 16008 @CallSuper destroyHardwareResources()16009 protected void destroyHardwareResources() { 16010 // Although the Layer will be destroyed by RenderNode, we want to release 16011 // the staging display list, which is also a signal to RenderNode that it's 16012 // safe to free its copy of the display list as it knows that we will 16013 // push an updated DisplayList if we try to draw again 16014 resetDisplayList(); 16015 } 16016 16017 /** 16018 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 16019 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 16020 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 16021 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 16022 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 16023 * null.</p> 16024 * 16025 * <p>Enabling the drawing cache is similar to 16026 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 16027 * acceleration is turned off. When hardware acceleration is turned on, enabling the 16028 * drawing cache has no effect on rendering because the system uses a different mechanism 16029 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 16030 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 16031 * for information on how to enable software and hardware layers.</p> 16032 * 16033 * <p>This API can be used to manually generate 16034 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 16035 * {@link #getDrawingCache()}.</p> 16036 * 16037 * @param enabled true to enable the drawing cache, false otherwise 16038 * 16039 * @see #isDrawingCacheEnabled() 16040 * @see #getDrawingCache() 16041 * @see #buildDrawingCache() 16042 * @see #setLayerType(int, android.graphics.Paint) 16043 */ setDrawingCacheEnabled(boolean enabled)16044 public void setDrawingCacheEnabled(boolean enabled) { 16045 mCachingFailed = false; 16046 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 16047 } 16048 16049 /** 16050 * <p>Indicates whether the drawing cache is enabled for this view.</p> 16051 * 16052 * @return true if the drawing cache is enabled 16053 * 16054 * @see #setDrawingCacheEnabled(boolean) 16055 * @see #getDrawingCache() 16056 */ 16057 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()16058 public boolean isDrawingCacheEnabled() { 16059 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 16060 } 16061 16062 /** 16063 * Debugging utility which recursively outputs the dirty state of a view and its 16064 * descendants. 16065 * 16066 * @hide 16067 */ 16068 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)16069 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 16070 Log.d("View", indent + this + " DIRTY(" + (mPrivateFlags & View.PFLAG_DIRTY_MASK) + 16071 ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" + 16072 (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) + 16073 ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 16074 if (clear) { 16075 mPrivateFlags &= clearMask; 16076 } 16077 if (this instanceof ViewGroup) { 16078 ViewGroup parent = (ViewGroup) this; 16079 final int count = parent.getChildCount(); 16080 for (int i = 0; i < count; i++) { 16081 final View child = parent.getChildAt(i); 16082 child.outputDirtyFlags(indent + " ", clear, clearMask); 16083 } 16084 } 16085 } 16086 16087 /** 16088 * This method is used by ViewGroup to cause its children to restore or recreate their 16089 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 16090 * to recreate its own display list, which would happen if it went through the normal 16091 * draw/dispatchDraw mechanisms. 16092 * 16093 * @hide 16094 */ dispatchGetDisplayList()16095 protected void dispatchGetDisplayList() {} 16096 16097 /** 16098 * A view that is not attached or hardware accelerated cannot create a display list. 16099 * This method checks these conditions and returns the appropriate result. 16100 * 16101 * @return true if view has the ability to create a display list, false otherwise. 16102 * 16103 * @hide 16104 */ canHaveDisplayList()16105 public boolean canHaveDisplayList() { 16106 return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null); 16107 } 16108 16109 /** 16110 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 16111 * @hide 16112 */ 16113 @NonNull updateDisplayListIfDirty()16114 public RenderNode updateDisplayListIfDirty() { 16115 final RenderNode renderNode = mRenderNode; 16116 if (!canHaveDisplayList()) { 16117 // can't populate RenderNode, don't try 16118 return renderNode; 16119 } 16120 16121 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 16122 || !renderNode.isValid() 16123 || (mRecreateDisplayList)) { 16124 // Don't need to recreate the display list, just need to tell our 16125 // children to restore/recreate theirs 16126 if (renderNode.isValid() 16127 && !mRecreateDisplayList) { 16128 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16129 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16130 dispatchGetDisplayList(); 16131 16132 return renderNode; // no work needed 16133 } 16134 16135 // If we got here, we're recreating it. Mark it as such to ensure that 16136 // we copy in child display lists into ours in drawChild() 16137 mRecreateDisplayList = true; 16138 16139 int width = mRight - mLeft; 16140 int height = mBottom - mTop; 16141 int layerType = getLayerType(); 16142 16143 final DisplayListCanvas canvas = renderNode.start(width, height); 16144 canvas.setHighContrastText(mAttachInfo.mHighContrastText); 16145 16146 try { 16147 if (layerType == LAYER_TYPE_SOFTWARE) { 16148 buildDrawingCache(true); 16149 Bitmap cache = getDrawingCache(true); 16150 if (cache != null) { 16151 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 16152 } 16153 } else { 16154 computeScroll(); 16155 16156 canvas.translate(-mScrollX, -mScrollY); 16157 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16158 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16159 16160 // Fast path for layouts with no backgrounds 16161 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16162 dispatchDraw(canvas); 16163 if (mOverlay != null && !mOverlay.isEmpty()) { 16164 mOverlay.getOverlayView().draw(canvas); 16165 } 16166 } else { 16167 draw(canvas); 16168 } 16169 } 16170 } finally { 16171 renderNode.end(canvas); 16172 setDisplayListProperties(renderNode); 16173 } 16174 } else { 16175 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 16176 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16177 } 16178 return renderNode; 16179 } 16180 resetDisplayList()16181 private void resetDisplayList() { 16182 if (mRenderNode.isValid()) { 16183 mRenderNode.discardDisplayList(); 16184 } 16185 16186 if (mBackgroundRenderNode != null && mBackgroundRenderNode.isValid()) { 16187 mBackgroundRenderNode.discardDisplayList(); 16188 } 16189 } 16190 16191 /** 16192 * Called when the passed RenderNode is removed from the draw tree 16193 * @hide 16194 */ onRenderNodeDetached(RenderNode renderNode)16195 public void onRenderNodeDetached(RenderNode renderNode) { 16196 } 16197 16198 /** 16199 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 16200 * 16201 * @return A non-scaled bitmap representing this view or null if cache is disabled. 16202 * 16203 * @see #getDrawingCache(boolean) 16204 */ getDrawingCache()16205 public Bitmap getDrawingCache() { 16206 return getDrawingCache(false); 16207 } 16208 16209 /** 16210 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 16211 * is null when caching is disabled. If caching is enabled and the cache is not ready, 16212 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 16213 * draw from the cache when the cache is enabled. To benefit from the cache, you must 16214 * request the drawing cache by calling this method and draw it on screen if the 16215 * returned bitmap is not null.</p> 16216 * 16217 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16218 * this method will create a bitmap of the same size as this view. Because this bitmap 16219 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16220 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16221 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16222 * size than the view. This implies that your application must be able to handle this 16223 * size.</p> 16224 * 16225 * @param autoScale Indicates whether the generated bitmap should be scaled based on 16226 * the current density of the screen when the application is in compatibility 16227 * mode. 16228 * 16229 * @return A bitmap representing this view or null if cache is disabled. 16230 * 16231 * @see #setDrawingCacheEnabled(boolean) 16232 * @see #isDrawingCacheEnabled() 16233 * @see #buildDrawingCache(boolean) 16234 * @see #destroyDrawingCache() 16235 */ getDrawingCache(boolean autoScale)16236 public Bitmap getDrawingCache(boolean autoScale) { 16237 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 16238 return null; 16239 } 16240 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 16241 buildDrawingCache(autoScale); 16242 } 16243 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 16244 } 16245 16246 /** 16247 * <p>Frees the resources used by the drawing cache. If you call 16248 * {@link #buildDrawingCache()} manually without calling 16249 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16250 * should cleanup the cache with this method afterwards.</p> 16251 * 16252 * @see #setDrawingCacheEnabled(boolean) 16253 * @see #buildDrawingCache() 16254 * @see #getDrawingCache() 16255 */ destroyDrawingCache()16256 public void destroyDrawingCache() { 16257 if (mDrawingCache != null) { 16258 mDrawingCache.recycle(); 16259 mDrawingCache = null; 16260 } 16261 if (mUnscaledDrawingCache != null) { 16262 mUnscaledDrawingCache.recycle(); 16263 mUnscaledDrawingCache = null; 16264 } 16265 } 16266 16267 /** 16268 * Setting a solid background color for the drawing cache's bitmaps will improve 16269 * performance and memory usage. Note, though that this should only be used if this 16270 * view will always be drawn on top of a solid color. 16271 * 16272 * @param color The background color to use for the drawing cache's bitmap 16273 * 16274 * @see #setDrawingCacheEnabled(boolean) 16275 * @see #buildDrawingCache() 16276 * @see #getDrawingCache() 16277 */ setDrawingCacheBackgroundColor(@olorInt int color)16278 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 16279 if (color != mDrawingCacheBackgroundColor) { 16280 mDrawingCacheBackgroundColor = color; 16281 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16282 } 16283 } 16284 16285 /** 16286 * @see #setDrawingCacheBackgroundColor(int) 16287 * 16288 * @return The background color to used for the drawing cache's bitmap 16289 */ 16290 @ColorInt getDrawingCacheBackgroundColor()16291 public int getDrawingCacheBackgroundColor() { 16292 return mDrawingCacheBackgroundColor; 16293 } 16294 16295 /** 16296 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 16297 * 16298 * @see #buildDrawingCache(boolean) 16299 */ buildDrawingCache()16300 public void buildDrawingCache() { 16301 buildDrawingCache(false); 16302 } 16303 16304 /** 16305 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 16306 * 16307 * <p>If you call {@link #buildDrawingCache()} manually without calling 16308 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 16309 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 16310 * 16311 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 16312 * this method will create a bitmap of the same size as this view. Because this bitmap 16313 * will be drawn scaled by the parent ViewGroup, the result on screen might show 16314 * scaling artifacts. To avoid such artifacts, you should call this method by setting 16315 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 16316 * size than the view. This implies that your application must be able to handle this 16317 * size.</p> 16318 * 16319 * <p>You should avoid calling this method when hardware acceleration is enabled. If 16320 * you do not need the drawing cache bitmap, calling this method will increase memory 16321 * usage and cause the view to be rendered in software once, thus negatively impacting 16322 * performance.</p> 16323 * 16324 * @see #getDrawingCache() 16325 * @see #destroyDrawingCache() 16326 */ buildDrawingCache(boolean autoScale)16327 public void buildDrawingCache(boolean autoScale) { 16328 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 16329 mDrawingCache == null : mUnscaledDrawingCache == null)) { 16330 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 16331 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 16332 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 16333 } 16334 try { 16335 buildDrawingCacheImpl(autoScale); 16336 } finally { 16337 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 16338 } 16339 } 16340 } 16341 16342 /** 16343 * private, internal implementation of buildDrawingCache, used to enable tracing 16344 */ buildDrawingCacheImpl(boolean autoScale)16345 private void buildDrawingCacheImpl(boolean autoScale) { 16346 mCachingFailed = false; 16347 16348 int width = mRight - mLeft; 16349 int height = mBottom - mTop; 16350 16351 final AttachInfo attachInfo = mAttachInfo; 16352 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 16353 16354 if (autoScale && scalingRequired) { 16355 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 16356 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 16357 } 16358 16359 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 16360 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 16361 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 16362 16363 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 16364 final long drawingCacheSize = 16365 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 16366 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 16367 if (width > 0 && height > 0) { 16368 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 16369 + " too large to fit into a software layer (or drawing cache), needs " 16370 + projectedBitmapSize + " bytes, only " 16371 + drawingCacheSize + " available"); 16372 } 16373 destroyDrawingCache(); 16374 mCachingFailed = true; 16375 return; 16376 } 16377 16378 boolean clear = true; 16379 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 16380 16381 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 16382 Bitmap.Config quality; 16383 if (!opaque) { 16384 // Never pick ARGB_4444 because it looks awful 16385 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 16386 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 16387 case DRAWING_CACHE_QUALITY_AUTO: 16388 case DRAWING_CACHE_QUALITY_LOW: 16389 case DRAWING_CACHE_QUALITY_HIGH: 16390 default: 16391 quality = Bitmap.Config.ARGB_8888; 16392 break; 16393 } 16394 } else { 16395 // Optimization for translucent windows 16396 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 16397 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 16398 } 16399 16400 // Try to cleanup memory 16401 if (bitmap != null) bitmap.recycle(); 16402 16403 try { 16404 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 16405 width, height, quality); 16406 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 16407 if (autoScale) { 16408 mDrawingCache = bitmap; 16409 } else { 16410 mUnscaledDrawingCache = bitmap; 16411 } 16412 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 16413 } catch (OutOfMemoryError e) { 16414 // If there is not enough memory to create the bitmap cache, just 16415 // ignore the issue as bitmap caches are not required to draw the 16416 // view hierarchy 16417 if (autoScale) { 16418 mDrawingCache = null; 16419 } else { 16420 mUnscaledDrawingCache = null; 16421 } 16422 mCachingFailed = true; 16423 return; 16424 } 16425 16426 clear = drawingCacheBackgroundColor != 0; 16427 } 16428 16429 Canvas canvas; 16430 if (attachInfo != null) { 16431 canvas = attachInfo.mCanvas; 16432 if (canvas == null) { 16433 canvas = new Canvas(); 16434 } 16435 canvas.setBitmap(bitmap); 16436 // Temporarily clobber the cached Canvas in case one of our children 16437 // is also using a drawing cache. Without this, the children would 16438 // steal the canvas by attaching their own bitmap to it and bad, bad 16439 // thing would happen (invisible views, corrupted drawings, etc.) 16440 attachInfo.mCanvas = null; 16441 } else { 16442 // This case should hopefully never or seldom happen 16443 canvas = new Canvas(bitmap); 16444 } 16445 16446 if (clear) { 16447 bitmap.eraseColor(drawingCacheBackgroundColor); 16448 } 16449 16450 computeScroll(); 16451 final int restoreCount = canvas.save(); 16452 16453 if (autoScale && scalingRequired) { 16454 final float scale = attachInfo.mApplicationScale; 16455 canvas.scale(scale, scale); 16456 } 16457 16458 canvas.translate(-mScrollX, -mScrollY); 16459 16460 mPrivateFlags |= PFLAG_DRAWN; 16461 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 16462 mLayerType != LAYER_TYPE_NONE) { 16463 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 16464 } 16465 16466 // Fast path for layouts with no backgrounds 16467 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16468 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16469 dispatchDraw(canvas); 16470 if (mOverlay != null && !mOverlay.isEmpty()) { 16471 mOverlay.getOverlayView().draw(canvas); 16472 } 16473 } else { 16474 draw(canvas); 16475 } 16476 16477 canvas.restoreToCount(restoreCount); 16478 canvas.setBitmap(null); 16479 16480 if (attachInfo != null) { 16481 // Restore the cached Canvas for our siblings 16482 attachInfo.mCanvas = canvas; 16483 } 16484 } 16485 16486 /** 16487 * Create a snapshot of the view into a bitmap. We should probably make 16488 * some form of this public, but should think about the API. 16489 * 16490 * @hide 16491 */ createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren)16492 public Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) { 16493 int width = mRight - mLeft; 16494 int height = mBottom - mTop; 16495 16496 final AttachInfo attachInfo = mAttachInfo; 16497 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 16498 width = (int) ((width * scale) + 0.5f); 16499 height = (int) ((height * scale) + 0.5f); 16500 16501 Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 16502 width > 0 ? width : 1, height > 0 ? height : 1, quality); 16503 if (bitmap == null) { 16504 throw new OutOfMemoryError(); 16505 } 16506 16507 Resources resources = getResources(); 16508 if (resources != null) { 16509 bitmap.setDensity(resources.getDisplayMetrics().densityDpi); 16510 } 16511 16512 Canvas canvas; 16513 if (attachInfo != null) { 16514 canvas = attachInfo.mCanvas; 16515 if (canvas == null) { 16516 canvas = new Canvas(); 16517 } 16518 canvas.setBitmap(bitmap); 16519 // Temporarily clobber the cached Canvas in case one of our children 16520 // is also using a drawing cache. Without this, the children would 16521 // steal the canvas by attaching their own bitmap to it and bad, bad 16522 // things would happen (invisible views, corrupted drawings, etc.) 16523 attachInfo.mCanvas = null; 16524 } else { 16525 // This case should hopefully never or seldom happen 16526 canvas = new Canvas(bitmap); 16527 } 16528 16529 if ((backgroundColor & 0xff000000) != 0) { 16530 bitmap.eraseColor(backgroundColor); 16531 } 16532 16533 computeScroll(); 16534 final int restoreCount = canvas.save(); 16535 canvas.scale(scale, scale); 16536 canvas.translate(-mScrollX, -mScrollY); 16537 16538 // Temporarily remove the dirty mask 16539 int flags = mPrivateFlags; 16540 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 16541 16542 // Fast path for layouts with no backgrounds 16543 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 16544 dispatchDraw(canvas); 16545 if (mOverlay != null && !mOverlay.isEmpty()) { 16546 mOverlay.getOverlayView().draw(canvas); 16547 } 16548 } else { 16549 draw(canvas); 16550 } 16551 16552 mPrivateFlags = flags; 16553 16554 canvas.restoreToCount(restoreCount); 16555 canvas.setBitmap(null); 16556 16557 if (attachInfo != null) { 16558 // Restore the cached Canvas for our siblings 16559 attachInfo.mCanvas = canvas; 16560 } 16561 16562 return bitmap; 16563 } 16564 16565 /** 16566 * Indicates whether this View is currently in edit mode. A View is usually 16567 * in edit mode when displayed within a developer tool. For instance, if 16568 * this View is being drawn by a visual user interface builder, this method 16569 * should return true. 16570 * 16571 * Subclasses should check the return value of this method to provide 16572 * different behaviors if their normal behavior might interfere with the 16573 * host environment. For instance: the class spawns a thread in its 16574 * constructor, the drawing code relies on device-specific features, etc. 16575 * 16576 * This method is usually checked in the drawing code of custom widgets. 16577 * 16578 * @return True if this View is in edit mode, false otherwise. 16579 */ isInEditMode()16580 public boolean isInEditMode() { 16581 return false; 16582 } 16583 16584 /** 16585 * If the View draws content inside its padding and enables fading edges, 16586 * it needs to support padding offsets. Padding offsets are added to the 16587 * fading edges to extend the length of the fade so that it covers pixels 16588 * drawn inside the padding. 16589 * 16590 * Subclasses of this class should override this method if they need 16591 * to draw content inside the padding. 16592 * 16593 * @return True if padding offset must be applied, false otherwise. 16594 * 16595 * @see #getLeftPaddingOffset() 16596 * @see #getRightPaddingOffset() 16597 * @see #getTopPaddingOffset() 16598 * @see #getBottomPaddingOffset() 16599 * 16600 * @since CURRENT 16601 */ isPaddingOffsetRequired()16602 protected boolean isPaddingOffsetRequired() { 16603 return false; 16604 } 16605 16606 /** 16607 * Amount by which to extend the left fading region. Called only when 16608 * {@link #isPaddingOffsetRequired()} returns true. 16609 * 16610 * @return The left padding offset in pixels. 16611 * 16612 * @see #isPaddingOffsetRequired() 16613 * 16614 * @since CURRENT 16615 */ getLeftPaddingOffset()16616 protected int getLeftPaddingOffset() { 16617 return 0; 16618 } 16619 16620 /** 16621 * Amount by which to extend the right fading region. Called only when 16622 * {@link #isPaddingOffsetRequired()} returns true. 16623 * 16624 * @return The right padding offset in pixels. 16625 * 16626 * @see #isPaddingOffsetRequired() 16627 * 16628 * @since CURRENT 16629 */ getRightPaddingOffset()16630 protected int getRightPaddingOffset() { 16631 return 0; 16632 } 16633 16634 /** 16635 * Amount by which to extend the top fading region. Called only when 16636 * {@link #isPaddingOffsetRequired()} returns true. 16637 * 16638 * @return The top padding offset in pixels. 16639 * 16640 * @see #isPaddingOffsetRequired() 16641 * 16642 * @since CURRENT 16643 */ getTopPaddingOffset()16644 protected int getTopPaddingOffset() { 16645 return 0; 16646 } 16647 16648 /** 16649 * Amount by which to extend the bottom fading region. Called only when 16650 * {@link #isPaddingOffsetRequired()} returns true. 16651 * 16652 * @return The bottom padding offset in pixels. 16653 * 16654 * @see #isPaddingOffsetRequired() 16655 * 16656 * @since CURRENT 16657 */ getBottomPaddingOffset()16658 protected int getBottomPaddingOffset() { 16659 return 0; 16660 } 16661 16662 /** 16663 * @hide 16664 * @param offsetRequired 16665 */ getFadeTop(boolean offsetRequired)16666 protected int getFadeTop(boolean offsetRequired) { 16667 int top = mPaddingTop; 16668 if (offsetRequired) top += getTopPaddingOffset(); 16669 return top; 16670 } 16671 16672 /** 16673 * @hide 16674 * @param offsetRequired 16675 */ getFadeHeight(boolean offsetRequired)16676 protected int getFadeHeight(boolean offsetRequired) { 16677 int padding = mPaddingTop; 16678 if (offsetRequired) padding += getTopPaddingOffset(); 16679 return mBottom - mTop - mPaddingBottom - padding; 16680 } 16681 16682 /** 16683 * <p>Indicates whether this view is attached to a hardware accelerated 16684 * window or not.</p> 16685 * 16686 * <p>Even if this method returns true, it does not mean that every call 16687 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 16688 * accelerated {@link android.graphics.Canvas}. For instance, if this view 16689 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 16690 * window is hardware accelerated, 16691 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 16692 * return false, and this method will return true.</p> 16693 * 16694 * @return True if the view is attached to a window and the window is 16695 * hardware accelerated; false in any other case. 16696 */ 16697 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()16698 public boolean isHardwareAccelerated() { 16699 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 16700 } 16701 16702 /** 16703 * Sets a rectangular area on this view to which the view will be clipped 16704 * when it is drawn. Setting the value to null will remove the clip bounds 16705 * and the view will draw normally, using its full bounds. 16706 * 16707 * @param clipBounds The rectangular area, in the local coordinates of 16708 * this view, to which future drawing operations will be clipped. 16709 */ setClipBounds(Rect clipBounds)16710 public void setClipBounds(Rect clipBounds) { 16711 if (clipBounds == mClipBounds 16712 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 16713 return; 16714 } 16715 if (clipBounds != null) { 16716 if (mClipBounds == null) { 16717 mClipBounds = new Rect(clipBounds); 16718 } else { 16719 mClipBounds.set(clipBounds); 16720 } 16721 } else { 16722 mClipBounds = null; 16723 } 16724 mRenderNode.setClipBounds(mClipBounds); 16725 invalidateViewProperty(false, false); 16726 } 16727 16728 /** 16729 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 16730 * 16731 * @return A copy of the current clip bounds if clip bounds are set, 16732 * otherwise null. 16733 */ getClipBounds()16734 public Rect getClipBounds() { 16735 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 16736 } 16737 16738 16739 /** 16740 * Populates an output rectangle with the clip bounds of the view, 16741 * returning {@code true} if successful or {@code false} if the view's 16742 * clip bounds are {@code null}. 16743 * 16744 * @param outRect rectangle in which to place the clip bounds of the view 16745 * @return {@code true} if successful or {@code false} if the view's 16746 * clip bounds are {@code null} 16747 */ getClipBounds(Rect outRect)16748 public boolean getClipBounds(Rect outRect) { 16749 if (mClipBounds != null) { 16750 outRect.set(mClipBounds); 16751 return true; 16752 } 16753 return false; 16754 } 16755 16756 /** 16757 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 16758 * case of an active Animation being run on the view. 16759 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)16760 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 16761 Animation a, boolean scalingRequired) { 16762 Transformation invalidationTransform; 16763 final int flags = parent.mGroupFlags; 16764 final boolean initialized = a.isInitialized(); 16765 if (!initialized) { 16766 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 16767 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 16768 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 16769 onAnimationStart(); 16770 } 16771 16772 final Transformation t = parent.getChildTransformation(); 16773 boolean more = a.getTransformation(drawingTime, t, 1f); 16774 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 16775 if (parent.mInvalidationTransformation == null) { 16776 parent.mInvalidationTransformation = new Transformation(); 16777 } 16778 invalidationTransform = parent.mInvalidationTransformation; 16779 a.getTransformation(drawingTime, invalidationTransform, 1f); 16780 } else { 16781 invalidationTransform = t; 16782 } 16783 16784 if (more) { 16785 if (!a.willChangeBounds()) { 16786 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 16787 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 16788 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 16789 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 16790 // The child need to draw an animation, potentially offscreen, so 16791 // make sure we do not cancel invalidate requests 16792 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 16793 parent.invalidate(mLeft, mTop, mRight, mBottom); 16794 } 16795 } else { 16796 if (parent.mInvalidateRegion == null) { 16797 parent.mInvalidateRegion = new RectF(); 16798 } 16799 final RectF region = parent.mInvalidateRegion; 16800 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 16801 invalidationTransform); 16802 16803 // The child need to draw an animation, potentially offscreen, so 16804 // make sure we do not cancel invalidate requests 16805 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 16806 16807 final int left = mLeft + (int) region.left; 16808 final int top = mTop + (int) region.top; 16809 parent.invalidate(left, top, left + (int) (region.width() + .5f), 16810 top + (int) (region.height() + .5f)); 16811 } 16812 } 16813 return more; 16814 } 16815 16816 /** 16817 * This method is called by getDisplayList() when a display list is recorded for a View. 16818 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 16819 */ setDisplayListProperties(RenderNode renderNode)16820 void setDisplayListProperties(RenderNode renderNode) { 16821 if (renderNode != null) { 16822 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 16823 renderNode.setClipToBounds(mParent instanceof ViewGroup 16824 && ((ViewGroup) mParent).getClipChildren()); 16825 16826 float alpha = 1; 16827 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 16828 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 16829 ViewGroup parentVG = (ViewGroup) mParent; 16830 final Transformation t = parentVG.getChildTransformation(); 16831 if (parentVG.getChildStaticTransformation(this, t)) { 16832 final int transformType = t.getTransformationType(); 16833 if (transformType != Transformation.TYPE_IDENTITY) { 16834 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 16835 alpha = t.getAlpha(); 16836 } 16837 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 16838 renderNode.setStaticMatrix(t.getMatrix()); 16839 } 16840 } 16841 } 16842 } 16843 if (mTransformationInfo != null) { 16844 alpha *= getFinalAlpha(); 16845 if (alpha < 1) { 16846 final int multipliedAlpha = (int) (255 * alpha); 16847 if (onSetAlpha(multipliedAlpha)) { 16848 alpha = 1; 16849 } 16850 } 16851 renderNode.setAlpha(alpha); 16852 } else if (alpha < 1) { 16853 renderNode.setAlpha(alpha); 16854 } 16855 } 16856 } 16857 16858 /** 16859 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 16860 * 16861 * This is where the View specializes rendering behavior based on layer type, 16862 * and hardware acceleration. 16863 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)16864 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 16865 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 16866 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 16867 * 16868 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 16869 * HW accelerated, it can't handle drawing RenderNodes. 16870 */ 16871 boolean drawingWithRenderNode = mAttachInfo != null 16872 && mAttachInfo.mHardwareAccelerated 16873 && hardwareAcceleratedCanvas; 16874 16875 boolean more = false; 16876 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 16877 final int parentFlags = parent.mGroupFlags; 16878 16879 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 16880 parent.getChildTransformation().clear(); 16881 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 16882 } 16883 16884 Transformation transformToApply = null; 16885 boolean concatMatrix = false; 16886 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 16887 final Animation a = getAnimation(); 16888 if (a != null) { 16889 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 16890 concatMatrix = a.willChangeTransformationMatrix(); 16891 if (concatMatrix) { 16892 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 16893 } 16894 transformToApply = parent.getChildTransformation(); 16895 } else { 16896 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 16897 // No longer animating: clear out old animation matrix 16898 mRenderNode.setAnimationMatrix(null); 16899 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 16900 } 16901 if (!drawingWithRenderNode 16902 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 16903 final Transformation t = parent.getChildTransformation(); 16904 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 16905 if (hasTransform) { 16906 final int transformType = t.getTransformationType(); 16907 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 16908 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 16909 } 16910 } 16911 } 16912 16913 concatMatrix |= !childHasIdentityMatrix; 16914 16915 // Sets the flag as early as possible to allow draw() implementations 16916 // to call invalidate() successfully when doing animations 16917 mPrivateFlags |= PFLAG_DRAWN; 16918 16919 if (!concatMatrix && 16920 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 16921 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 16922 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 16923 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 16924 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 16925 return more; 16926 } 16927 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 16928 16929 if (hardwareAcceleratedCanvas) { 16930 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 16931 // retain the flag's value temporarily in the mRecreateDisplayList flag 16932 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 16933 mPrivateFlags &= ~PFLAG_INVALIDATED; 16934 } 16935 16936 RenderNode renderNode = null; 16937 Bitmap cache = null; 16938 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 16939 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 16940 if (layerType != LAYER_TYPE_NONE) { 16941 // If not drawing with RenderNode, treat HW layers as SW 16942 layerType = LAYER_TYPE_SOFTWARE; 16943 buildDrawingCache(true); 16944 } 16945 cache = getDrawingCache(true); 16946 } 16947 16948 if (drawingWithRenderNode) { 16949 // Delay getting the display list until animation-driven alpha values are 16950 // set up and possibly passed on to the view 16951 renderNode = updateDisplayListIfDirty(); 16952 if (!renderNode.isValid()) { 16953 // Uncommon, but possible. If a view is removed from the hierarchy during the call 16954 // to getDisplayList(), the display list will be marked invalid and we should not 16955 // try to use it again. 16956 renderNode = null; 16957 drawingWithRenderNode = false; 16958 } 16959 } 16960 16961 int sx = 0; 16962 int sy = 0; 16963 if (!drawingWithRenderNode) { 16964 computeScroll(); 16965 sx = mScrollX; 16966 sy = mScrollY; 16967 } 16968 16969 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 16970 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 16971 16972 int restoreTo = -1; 16973 if (!drawingWithRenderNode || transformToApply != null) { 16974 restoreTo = canvas.save(); 16975 } 16976 if (offsetForScroll) { 16977 canvas.translate(mLeft - sx, mTop - sy); 16978 } else { 16979 if (!drawingWithRenderNode) { 16980 canvas.translate(mLeft, mTop); 16981 } 16982 if (scalingRequired) { 16983 if (drawingWithRenderNode) { 16984 // TODO: Might not need this if we put everything inside the DL 16985 restoreTo = canvas.save(); 16986 } 16987 // mAttachInfo cannot be null, otherwise scalingRequired == false 16988 final float scale = 1.0f / mAttachInfo.mApplicationScale; 16989 canvas.scale(scale, scale); 16990 } 16991 } 16992 16993 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 16994 if (transformToApply != null 16995 || alpha < 1 16996 || !hasIdentityMatrix() 16997 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 16998 if (transformToApply != null || !childHasIdentityMatrix) { 16999 int transX = 0; 17000 int transY = 0; 17001 17002 if (offsetForScroll) { 17003 transX = -sx; 17004 transY = -sy; 17005 } 17006 17007 if (transformToApply != null) { 17008 if (concatMatrix) { 17009 if (drawingWithRenderNode) { 17010 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 17011 } else { 17012 // Undo the scroll translation, apply the transformation matrix, 17013 // then redo the scroll translate to get the correct result. 17014 canvas.translate(-transX, -transY); 17015 canvas.concat(transformToApply.getMatrix()); 17016 canvas.translate(transX, transY); 17017 } 17018 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17019 } 17020 17021 float transformAlpha = transformToApply.getAlpha(); 17022 if (transformAlpha < 1) { 17023 alpha *= transformAlpha; 17024 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17025 } 17026 } 17027 17028 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 17029 canvas.translate(-transX, -transY); 17030 canvas.concat(getMatrix()); 17031 canvas.translate(transX, transY); 17032 } 17033 } 17034 17035 // Deal with alpha if it is or used to be <1 17036 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 17037 if (alpha < 1) { 17038 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17039 } else { 17040 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 17041 } 17042 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 17043 if (!drawingWithDrawingCache) { 17044 final int multipliedAlpha = (int) (255 * alpha); 17045 if (!onSetAlpha(multipliedAlpha)) { 17046 if (drawingWithRenderNode) { 17047 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 17048 } else if (layerType == LAYER_TYPE_NONE) { 17049 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 17050 multipliedAlpha); 17051 } 17052 } else { 17053 // Alpha is handled by the child directly, clobber the layer's alpha 17054 mPrivateFlags |= PFLAG_ALPHA_SET; 17055 } 17056 } 17057 } 17058 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17059 onSetAlpha(255); 17060 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17061 } 17062 17063 if (!drawingWithRenderNode) { 17064 // apply clips directly, since RenderNode won't do it for this draw 17065 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 17066 if (offsetForScroll) { 17067 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 17068 } else { 17069 if (!scalingRequired || cache == null) { 17070 canvas.clipRect(0, 0, getWidth(), getHeight()); 17071 } else { 17072 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 17073 } 17074 } 17075 } 17076 17077 if (mClipBounds != null) { 17078 // clip bounds ignore scroll 17079 canvas.clipRect(mClipBounds); 17080 } 17081 } 17082 17083 if (!drawingWithDrawingCache) { 17084 if (drawingWithRenderNode) { 17085 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17086 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17087 } else { 17088 // Fast path for layouts with no backgrounds 17089 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 17090 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17091 dispatchDraw(canvas); 17092 } else { 17093 draw(canvas); 17094 } 17095 } 17096 } else if (cache != null) { 17097 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 17098 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 17099 // no layer paint, use temporary paint to draw bitmap 17100 Paint cachePaint = parent.mCachePaint; 17101 if (cachePaint == null) { 17102 cachePaint = new Paint(); 17103 cachePaint.setDither(false); 17104 parent.mCachePaint = cachePaint; 17105 } 17106 cachePaint.setAlpha((int) (alpha * 255)); 17107 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 17108 } else { 17109 // use layer paint to draw the bitmap, merging the two alphas, but also restore 17110 int layerPaintAlpha = mLayerPaint.getAlpha(); 17111 if (alpha < 1) { 17112 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 17113 } 17114 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 17115 if (alpha < 1) { 17116 mLayerPaint.setAlpha(layerPaintAlpha); 17117 } 17118 } 17119 } 17120 17121 if (restoreTo >= 0) { 17122 canvas.restoreToCount(restoreTo); 17123 } 17124 17125 if (a != null && !more) { 17126 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 17127 onSetAlpha(255); 17128 } 17129 parent.finishAnimatingView(this, a); 17130 } 17131 17132 if (more && hardwareAcceleratedCanvas) { 17133 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 17134 // alpha animations should cause the child to recreate its display list 17135 invalidate(true); 17136 } 17137 } 17138 17139 mRecreateDisplayList = false; 17140 17141 return more; 17142 } 17143 17144 /** 17145 * Manually render this view (and all of its children) to the given Canvas. 17146 * The view must have already done a full layout before this function is 17147 * called. When implementing a view, implement 17148 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 17149 * If you do need to override this method, call the superclass version. 17150 * 17151 * @param canvas The Canvas to which the View is rendered. 17152 */ 17153 @CallSuper draw(Canvas canvas)17154 public void draw(Canvas canvas) { 17155 final int privateFlags = mPrivateFlags; 17156 final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && 17157 (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); 17158 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 17159 17160 /* 17161 * Draw traversal performs several drawing steps which must be executed 17162 * in the appropriate order: 17163 * 17164 * 1. Draw the background 17165 * 2. If necessary, save the canvas' layers to prepare for fading 17166 * 3. Draw view's content 17167 * 4. Draw children 17168 * 5. If necessary, draw the fading edges and restore layers 17169 * 6. Draw decorations (scrollbars for instance) 17170 */ 17171 17172 // Step 1, draw the background, if needed 17173 int saveCount; 17174 17175 if (!dirtyOpaque) { 17176 drawBackground(canvas); 17177 } 17178 17179 // skip step 2 & 5 if possible (common case) 17180 final int viewFlags = mViewFlags; 17181 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 17182 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 17183 if (!verticalEdges && !horizontalEdges) { 17184 // Step 3, draw the content 17185 if (!dirtyOpaque) onDraw(canvas); 17186 17187 // Step 4, draw the children 17188 dispatchDraw(canvas); 17189 17190 // Overlay is part of the content and draws beneath Foreground 17191 if (mOverlay != null && !mOverlay.isEmpty()) { 17192 mOverlay.getOverlayView().dispatchDraw(canvas); 17193 } 17194 17195 // Step 6, draw decorations (foreground, scrollbars) 17196 onDrawForeground(canvas); 17197 17198 // we're done... 17199 return; 17200 } 17201 17202 /* 17203 * Here we do the full fledged routine... 17204 * (this is an uncommon case where speed matters less, 17205 * this is why we repeat some of the tests that have been 17206 * done above) 17207 */ 17208 17209 boolean drawTop = false; 17210 boolean drawBottom = false; 17211 boolean drawLeft = false; 17212 boolean drawRight = false; 17213 17214 float topFadeStrength = 0.0f; 17215 float bottomFadeStrength = 0.0f; 17216 float leftFadeStrength = 0.0f; 17217 float rightFadeStrength = 0.0f; 17218 17219 // Step 2, save the canvas' layers 17220 int paddingLeft = mPaddingLeft; 17221 17222 final boolean offsetRequired = isPaddingOffsetRequired(); 17223 if (offsetRequired) { 17224 paddingLeft += getLeftPaddingOffset(); 17225 } 17226 17227 int left = mScrollX + paddingLeft; 17228 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 17229 int top = mScrollY + getFadeTop(offsetRequired); 17230 int bottom = top + getFadeHeight(offsetRequired); 17231 17232 if (offsetRequired) { 17233 right += getRightPaddingOffset(); 17234 bottom += getBottomPaddingOffset(); 17235 } 17236 17237 final ScrollabilityCache scrollabilityCache = mScrollCache; 17238 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 17239 int length = (int) fadeHeight; 17240 17241 // clip the fade length if top and bottom fades overlap 17242 // overlapping fades produce odd-looking artifacts 17243 if (verticalEdges && (top + length > bottom - length)) { 17244 length = (bottom - top) / 2; 17245 } 17246 17247 // also clip horizontal fades if necessary 17248 if (horizontalEdges && (left + length > right - length)) { 17249 length = (right - left) / 2; 17250 } 17251 17252 if (verticalEdges) { 17253 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 17254 drawTop = topFadeStrength * fadeHeight > 1.0f; 17255 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 17256 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 17257 } 17258 17259 if (horizontalEdges) { 17260 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 17261 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 17262 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 17263 drawRight = rightFadeStrength * fadeHeight > 1.0f; 17264 } 17265 17266 saveCount = canvas.getSaveCount(); 17267 17268 int solidColor = getSolidColor(); 17269 if (solidColor == 0) { 17270 final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; 17271 17272 if (drawTop) { 17273 canvas.saveLayer(left, top, right, top + length, null, flags); 17274 } 17275 17276 if (drawBottom) { 17277 canvas.saveLayer(left, bottom - length, right, bottom, null, flags); 17278 } 17279 17280 if (drawLeft) { 17281 canvas.saveLayer(left, top, left + length, bottom, null, flags); 17282 } 17283 17284 if (drawRight) { 17285 canvas.saveLayer(right - length, top, right, bottom, null, flags); 17286 } 17287 } else { 17288 scrollabilityCache.setFadeColor(solidColor); 17289 } 17290 17291 // Step 3, draw the content 17292 if (!dirtyOpaque) onDraw(canvas); 17293 17294 // Step 4, draw the children 17295 dispatchDraw(canvas); 17296 17297 // Step 5, draw the fade effect and restore layers 17298 final Paint p = scrollabilityCache.paint; 17299 final Matrix matrix = scrollabilityCache.matrix; 17300 final Shader fade = scrollabilityCache.shader; 17301 17302 if (drawTop) { 17303 matrix.setScale(1, fadeHeight * topFadeStrength); 17304 matrix.postTranslate(left, top); 17305 fade.setLocalMatrix(matrix); 17306 p.setShader(fade); 17307 canvas.drawRect(left, top, right, top + length, p); 17308 } 17309 17310 if (drawBottom) { 17311 matrix.setScale(1, fadeHeight * bottomFadeStrength); 17312 matrix.postRotate(180); 17313 matrix.postTranslate(left, bottom); 17314 fade.setLocalMatrix(matrix); 17315 p.setShader(fade); 17316 canvas.drawRect(left, bottom - length, right, bottom, p); 17317 } 17318 17319 if (drawLeft) { 17320 matrix.setScale(1, fadeHeight * leftFadeStrength); 17321 matrix.postRotate(-90); 17322 matrix.postTranslate(left, top); 17323 fade.setLocalMatrix(matrix); 17324 p.setShader(fade); 17325 canvas.drawRect(left, top, left + length, bottom, p); 17326 } 17327 17328 if (drawRight) { 17329 matrix.setScale(1, fadeHeight * rightFadeStrength); 17330 matrix.postRotate(90); 17331 matrix.postTranslate(right, top); 17332 fade.setLocalMatrix(matrix); 17333 p.setShader(fade); 17334 canvas.drawRect(right - length, top, right, bottom, p); 17335 } 17336 17337 canvas.restoreToCount(saveCount); 17338 17339 // Overlay is part of the content and draws beneath Foreground 17340 if (mOverlay != null && !mOverlay.isEmpty()) { 17341 mOverlay.getOverlayView().dispatchDraw(canvas); 17342 } 17343 17344 // Step 6, draw decorations (foreground, scrollbars) 17345 onDrawForeground(canvas); 17346 } 17347 17348 /** 17349 * Draws the background onto the specified canvas. 17350 * 17351 * @param canvas Canvas on which to draw the background 17352 */ drawBackground(Canvas canvas)17353 private void drawBackground(Canvas canvas) { 17354 final Drawable background = mBackground; 17355 if (background == null) { 17356 return; 17357 } 17358 17359 setBackgroundBounds(); 17360 17361 // Attempt to use a display list if requested. 17362 if (canvas.isHardwareAccelerated() && mAttachInfo != null 17363 && mAttachInfo.mHardwareRenderer != null) { 17364 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 17365 17366 final RenderNode renderNode = mBackgroundRenderNode; 17367 if (renderNode != null && renderNode.isValid()) { 17368 setBackgroundRenderNodeProperties(renderNode); 17369 ((DisplayListCanvas) canvas).drawRenderNode(renderNode); 17370 return; 17371 } 17372 } 17373 17374 final int scrollX = mScrollX; 17375 final int scrollY = mScrollY; 17376 if ((scrollX | scrollY) == 0) { 17377 background.draw(canvas); 17378 } else { 17379 canvas.translate(scrollX, scrollY); 17380 background.draw(canvas); 17381 canvas.translate(-scrollX, -scrollY); 17382 } 17383 } 17384 17385 /** 17386 * Sets the correct background bounds and rebuilds the outline, if needed. 17387 * <p/> 17388 * This is called by LayoutLib. 17389 */ setBackgroundBounds()17390 void setBackgroundBounds() { 17391 if (mBackgroundSizeChanged && mBackground != null) { 17392 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 17393 mBackgroundSizeChanged = false; 17394 rebuildOutline(); 17395 } 17396 } 17397 setBackgroundRenderNodeProperties(RenderNode renderNode)17398 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 17399 renderNode.setTranslationX(mScrollX); 17400 renderNode.setTranslationY(mScrollY); 17401 } 17402 17403 /** 17404 * Creates a new display list or updates the existing display list for the 17405 * specified Drawable. 17406 * 17407 * @param drawable Drawable for which to create a display list 17408 * @param renderNode Existing RenderNode, or {@code null} 17409 * @return A valid display list for the specified drawable 17410 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)17411 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 17412 if (renderNode == null) { 17413 renderNode = RenderNode.create(drawable.getClass().getName(), this); 17414 } 17415 17416 final Rect bounds = drawable.getBounds(); 17417 final int width = bounds.width(); 17418 final int height = bounds.height(); 17419 final DisplayListCanvas canvas = renderNode.start(width, height); 17420 17421 // Reverse left/top translation done by drawable canvas, which will 17422 // instead be applied by rendernode's LTRB bounds below. This way, the 17423 // drawable's bounds match with its rendernode bounds and its content 17424 // will lie within those bounds in the rendernode tree. 17425 canvas.translate(-bounds.left, -bounds.top); 17426 17427 try { 17428 drawable.draw(canvas); 17429 } finally { 17430 renderNode.end(canvas); 17431 } 17432 17433 // Set up drawable properties that are view-independent. 17434 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 17435 renderNode.setProjectBackwards(drawable.isProjected()); 17436 renderNode.setProjectionReceiver(true); 17437 renderNode.setClipToBounds(false); 17438 return renderNode; 17439 } 17440 17441 /** 17442 * Returns the overlay for this view, creating it if it does not yet exist. 17443 * Adding drawables to the overlay will cause them to be displayed whenever 17444 * the view itself is redrawn. Objects in the overlay should be actively 17445 * managed: remove them when they should not be displayed anymore. The 17446 * overlay will always have the same size as its host view. 17447 * 17448 * <p>Note: Overlays do not currently work correctly with {@link 17449 * SurfaceView} or {@link TextureView}; contents in overlays for these 17450 * types of views may not display correctly.</p> 17451 * 17452 * @return The ViewOverlay object for this view. 17453 * @see ViewOverlay 17454 */ getOverlay()17455 public ViewOverlay getOverlay() { 17456 if (mOverlay == null) { 17457 mOverlay = new ViewOverlay(mContext, this); 17458 } 17459 return mOverlay; 17460 } 17461 17462 /** 17463 * Override this if your view is known to always be drawn on top of a solid color background, 17464 * and needs to draw fading edges. Returning a non-zero color enables the view system to 17465 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 17466 * should be set to 0xFF. 17467 * 17468 * @see #setVerticalFadingEdgeEnabled(boolean) 17469 * @see #setHorizontalFadingEdgeEnabled(boolean) 17470 * 17471 * @return The known solid color background for this view, or 0 if the color may vary 17472 */ 17473 @ViewDebug.ExportedProperty(category = "drawing") 17474 @ColorInt getSolidColor()17475 public int getSolidColor() { 17476 return 0; 17477 } 17478 17479 /** 17480 * Build a human readable string representation of the specified view flags. 17481 * 17482 * @param flags the view flags to convert to a string 17483 * @return a String representing the supplied flags 17484 */ printFlags(int flags)17485 private static String printFlags(int flags) { 17486 String output = ""; 17487 int numFlags = 0; 17488 if ((flags & FOCUSABLE_MASK) == FOCUSABLE) { 17489 output += "TAKES_FOCUS"; 17490 numFlags++; 17491 } 17492 17493 switch (flags & VISIBILITY_MASK) { 17494 case INVISIBLE: 17495 if (numFlags > 0) { 17496 output += " "; 17497 } 17498 output += "INVISIBLE"; 17499 // USELESS HERE numFlags++; 17500 break; 17501 case GONE: 17502 if (numFlags > 0) { 17503 output += " "; 17504 } 17505 output += "GONE"; 17506 // USELESS HERE numFlags++; 17507 break; 17508 default: 17509 break; 17510 } 17511 return output; 17512 } 17513 17514 /** 17515 * Build a human readable string representation of the specified private 17516 * view flags. 17517 * 17518 * @param privateFlags the private view flags to convert to a string 17519 * @return a String representing the supplied flags 17520 */ printPrivateFlags(int privateFlags)17521 private static String printPrivateFlags(int privateFlags) { 17522 String output = ""; 17523 int numFlags = 0; 17524 17525 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 17526 output += "WANTS_FOCUS"; 17527 numFlags++; 17528 } 17529 17530 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 17531 if (numFlags > 0) { 17532 output += " "; 17533 } 17534 output += "FOCUSED"; 17535 numFlags++; 17536 } 17537 17538 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 17539 if (numFlags > 0) { 17540 output += " "; 17541 } 17542 output += "SELECTED"; 17543 numFlags++; 17544 } 17545 17546 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 17547 if (numFlags > 0) { 17548 output += " "; 17549 } 17550 output += "IS_ROOT_NAMESPACE"; 17551 numFlags++; 17552 } 17553 17554 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 17555 if (numFlags > 0) { 17556 output += " "; 17557 } 17558 output += "HAS_BOUNDS"; 17559 numFlags++; 17560 } 17561 17562 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 17563 if (numFlags > 0) { 17564 output += " "; 17565 } 17566 output += "DRAWN"; 17567 // USELESS HERE numFlags++; 17568 } 17569 return output; 17570 } 17571 17572 /** 17573 * <p>Indicates whether or not this view's layout will be requested during 17574 * the next hierarchy layout pass.</p> 17575 * 17576 * @return true if the layout will be forced during next layout pass 17577 */ isLayoutRequested()17578 public boolean isLayoutRequested() { 17579 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 17580 } 17581 17582 /** 17583 * Return true if o is a ViewGroup that is laying out using optical bounds. 17584 * @hide 17585 */ isLayoutModeOptical(Object o)17586 public static boolean isLayoutModeOptical(Object o) { 17587 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 17588 } 17589 setOpticalFrame(int left, int top, int right, int bottom)17590 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 17591 Insets parentInsets = mParent instanceof View ? 17592 ((View) mParent).getOpticalInsets() : Insets.NONE; 17593 Insets childInsets = getOpticalInsets(); 17594 return setFrame( 17595 left + parentInsets.left - childInsets.left, 17596 top + parentInsets.top - childInsets.top, 17597 right + parentInsets.left + childInsets.right, 17598 bottom + parentInsets.top + childInsets.bottom); 17599 } 17600 17601 /** 17602 * Assign a size and position to a view and all of its 17603 * descendants 17604 * 17605 * <p>This is the second phase of the layout mechanism. 17606 * (The first is measuring). In this phase, each parent calls 17607 * layout on all of its children to position them. 17608 * This is typically done using the child measurements 17609 * that were stored in the measure pass().</p> 17610 * 17611 * <p>Derived classes should not override this method. 17612 * Derived classes with children should override 17613 * onLayout. In that method, they should 17614 * call layout on each of their children.</p> 17615 * 17616 * @param l Left position, relative to parent 17617 * @param t Top position, relative to parent 17618 * @param r Right position, relative to parent 17619 * @param b Bottom position, relative to parent 17620 */ 17621 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)17622 public void layout(int l, int t, int r, int b) { 17623 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 17624 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 17625 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 17626 } 17627 17628 int oldL = mLeft; 17629 int oldT = mTop; 17630 int oldB = mBottom; 17631 int oldR = mRight; 17632 17633 boolean changed = isLayoutModeOptical(mParent) ? 17634 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 17635 17636 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 17637 onLayout(changed, l, t, r, b); 17638 17639 if (shouldDrawRoundScrollbar()) { 17640 if(mRoundScrollbarRenderer == null) { 17641 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 17642 } 17643 } else { 17644 mRoundScrollbarRenderer = null; 17645 } 17646 17647 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 17648 17649 ListenerInfo li = mListenerInfo; 17650 if (li != null && li.mOnLayoutChangeListeners != null) { 17651 ArrayList<OnLayoutChangeListener> listenersCopy = 17652 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 17653 int numListeners = listenersCopy.size(); 17654 for (int i = 0; i < numListeners; ++i) { 17655 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 17656 } 17657 } 17658 } 17659 17660 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 17661 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 17662 } 17663 17664 /** 17665 * Called from layout when this view should 17666 * assign a size and position to each of its children. 17667 * 17668 * Derived classes with children should override 17669 * this method and call layout on each of 17670 * their children. 17671 * @param changed This is a new size or position for this view 17672 * @param left Left position, relative to parent 17673 * @param top Top position, relative to parent 17674 * @param right Right position, relative to parent 17675 * @param bottom Bottom position, relative to parent 17676 */ onLayout(boolean changed, int left, int top, int right, int bottom)17677 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 17678 } 17679 17680 /** 17681 * Assign a size and position to this view. 17682 * 17683 * This is called from layout. 17684 * 17685 * @param left Left position, relative to parent 17686 * @param top Top position, relative to parent 17687 * @param right Right position, relative to parent 17688 * @param bottom Bottom position, relative to parent 17689 * @return true if the new size and position are different than the 17690 * previous ones 17691 * {@hide} 17692 */ setFrame(int left, int top, int right, int bottom)17693 protected boolean setFrame(int left, int top, int right, int bottom) { 17694 boolean changed = false; 17695 17696 if (DBG) { 17697 Log.d("View", this + " View.setFrame(" + left + "," + top + "," 17698 + right + "," + bottom + ")"); 17699 } 17700 17701 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 17702 changed = true; 17703 17704 // Remember our drawn bit 17705 int drawn = mPrivateFlags & PFLAG_DRAWN; 17706 17707 int oldWidth = mRight - mLeft; 17708 int oldHeight = mBottom - mTop; 17709 int newWidth = right - left; 17710 int newHeight = bottom - top; 17711 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 17712 17713 // Invalidate our old position 17714 invalidate(sizeChanged); 17715 17716 mLeft = left; 17717 mTop = top; 17718 mRight = right; 17719 mBottom = bottom; 17720 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 17721 17722 mPrivateFlags |= PFLAG_HAS_BOUNDS; 17723 17724 17725 if (sizeChanged) { 17726 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 17727 } 17728 17729 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 17730 // If we are visible, force the DRAWN bit to on so that 17731 // this invalidate will go through (at least to our parent). 17732 // This is because someone may have invalidated this view 17733 // before this call to setFrame came in, thereby clearing 17734 // the DRAWN bit. 17735 mPrivateFlags |= PFLAG_DRAWN; 17736 invalidate(sizeChanged); 17737 // parent display list may need to be recreated based on a change in the bounds 17738 // of any child 17739 invalidateParentCaches(); 17740 } 17741 17742 // Reset drawn bit to original value (invalidate turns it off) 17743 mPrivateFlags |= drawn; 17744 17745 mBackgroundSizeChanged = true; 17746 if (mForegroundInfo != null) { 17747 mForegroundInfo.mBoundsChanged = true; 17748 } 17749 17750 notifySubtreeAccessibilityStateChangedIfNeeded(); 17751 } 17752 return changed; 17753 } 17754 17755 /** 17756 * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. 17757 * @hide 17758 */ setLeftTopRightBottom(int left, int top, int right, int bottom)17759 public void setLeftTopRightBottom(int left, int top, int right, int bottom) { 17760 setFrame(left, top, right, bottom); 17761 } 17762 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)17763 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 17764 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 17765 if (mOverlay != null) { 17766 mOverlay.getOverlayView().setRight(newWidth); 17767 mOverlay.getOverlayView().setBottom(newHeight); 17768 } 17769 rebuildOutline(); 17770 } 17771 17772 /** 17773 * Finalize inflating a view from XML. This is called as the last phase 17774 * of inflation, after all child views have been added. 17775 * 17776 * <p>Even if the subclass overrides onFinishInflate, they should always be 17777 * sure to call the super method, so that we get called. 17778 */ 17779 @CallSuper onFinishInflate()17780 protected void onFinishInflate() { 17781 } 17782 17783 /** 17784 * Returns the resources associated with this view. 17785 * 17786 * @return Resources object. 17787 */ getResources()17788 public Resources getResources() { 17789 return mResources; 17790 } 17791 17792 /** 17793 * Invalidates the specified Drawable. 17794 * 17795 * @param drawable the drawable to invalidate 17796 */ 17797 @Override invalidateDrawable(@onNull Drawable drawable)17798 public void invalidateDrawable(@NonNull Drawable drawable) { 17799 if (verifyDrawable(drawable)) { 17800 final Rect dirty = drawable.getDirtyBounds(); 17801 final int scrollX = mScrollX; 17802 final int scrollY = mScrollY; 17803 17804 invalidate(dirty.left + scrollX, dirty.top + scrollY, 17805 dirty.right + scrollX, dirty.bottom + scrollY); 17806 rebuildOutline(); 17807 } 17808 } 17809 17810 /** 17811 * Schedules an action on a drawable to occur at a specified time. 17812 * 17813 * @param who the recipient of the action 17814 * @param what the action to run on the drawable 17815 * @param when the time at which the action must occur. Uses the 17816 * {@link SystemClock#uptimeMillis} timebase. 17817 */ 17818 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)17819 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 17820 if (verifyDrawable(who) && what != null) { 17821 final long delay = when - SystemClock.uptimeMillis(); 17822 if (mAttachInfo != null) { 17823 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 17824 Choreographer.CALLBACK_ANIMATION, what, who, 17825 Choreographer.subtractFrameDelay(delay)); 17826 } else { 17827 // Postpone the runnable until we know 17828 // on which thread it needs to run. 17829 getRunQueue().postDelayed(what, delay); 17830 } 17831 } 17832 } 17833 17834 /** 17835 * Cancels a scheduled action on a drawable. 17836 * 17837 * @param who the recipient of the action 17838 * @param what the action to cancel 17839 */ 17840 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)17841 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 17842 if (verifyDrawable(who) && what != null) { 17843 if (mAttachInfo != null) { 17844 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 17845 Choreographer.CALLBACK_ANIMATION, what, who); 17846 } 17847 getRunQueue().removeCallbacks(what); 17848 } 17849 } 17850 17851 /** 17852 * Unschedule any events associated with the given Drawable. This can be 17853 * used when selecting a new Drawable into a view, so that the previous 17854 * one is completely unscheduled. 17855 * 17856 * @param who The Drawable to unschedule. 17857 * 17858 * @see #drawableStateChanged 17859 */ unscheduleDrawable(Drawable who)17860 public void unscheduleDrawable(Drawable who) { 17861 if (mAttachInfo != null && who != null) { 17862 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 17863 Choreographer.CALLBACK_ANIMATION, null, who); 17864 } 17865 } 17866 17867 /** 17868 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 17869 * that the View directionality can and will be resolved before its Drawables. 17870 * 17871 * Will call {@link View#onResolveDrawables} when resolution is done. 17872 * 17873 * @hide 17874 */ resolveDrawables()17875 protected void resolveDrawables() { 17876 // Drawables resolution may need to happen before resolving the layout direction (which is 17877 // done only during the measure() call). 17878 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 17879 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 17880 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 17881 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 17882 // direction to be resolved as its resolved value will be the same as its raw value. 17883 if (!isLayoutDirectionResolved() && 17884 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 17885 return; 17886 } 17887 17888 final int layoutDirection = isLayoutDirectionResolved() ? 17889 getLayoutDirection() : getRawLayoutDirection(); 17890 17891 if (mBackground != null) { 17892 mBackground.setLayoutDirection(layoutDirection); 17893 } 17894 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 17895 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 17896 } 17897 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 17898 onResolveDrawables(layoutDirection); 17899 } 17900 areDrawablesResolved()17901 boolean areDrawablesResolved() { 17902 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 17903 } 17904 17905 /** 17906 * Called when layout direction has been resolved. 17907 * 17908 * The default implementation does nothing. 17909 * 17910 * @param layoutDirection The resolved layout direction. 17911 * 17912 * @see #LAYOUT_DIRECTION_LTR 17913 * @see #LAYOUT_DIRECTION_RTL 17914 * 17915 * @hide 17916 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)17917 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 17918 } 17919 17920 /** 17921 * @hide 17922 */ resetResolvedDrawables()17923 protected void resetResolvedDrawables() { 17924 resetResolvedDrawablesInternal(); 17925 } 17926 resetResolvedDrawablesInternal()17927 void resetResolvedDrawablesInternal() { 17928 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 17929 } 17930 17931 /** 17932 * If your view subclass is displaying its own Drawable objects, it should 17933 * override this function and return true for any Drawable it is 17934 * displaying. This allows animations for those drawables to be 17935 * scheduled. 17936 * 17937 * <p>Be sure to call through to the super class when overriding this 17938 * function. 17939 * 17940 * @param who The Drawable to verify. Return true if it is one you are 17941 * displaying, else return the result of calling through to the 17942 * super class. 17943 * 17944 * @return boolean If true than the Drawable is being displayed in the 17945 * view; else false and it is not allowed to animate. 17946 * 17947 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 17948 * @see #drawableStateChanged() 17949 */ 17950 @CallSuper verifyDrawable(@onNull Drawable who)17951 protected boolean verifyDrawable(@NonNull Drawable who) { 17952 // Avoid verifying the scroll bar drawable so that we don't end up in 17953 // an invalidation loop. This effectively prevents the scroll bar 17954 // drawable from triggering invalidations and scheduling runnables. 17955 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); 17956 } 17957 17958 /** 17959 * This function is called whenever the state of the view changes in such 17960 * a way that it impacts the state of drawables being shown. 17961 * <p> 17962 * If the View has a StateListAnimator, it will also be called to run necessary state 17963 * change animations. 17964 * <p> 17965 * Be sure to call through to the superclass when overriding this function. 17966 * 17967 * @see Drawable#setState(int[]) 17968 */ 17969 @CallSuper drawableStateChanged()17970 protected void drawableStateChanged() { 17971 final int[] state = getDrawableState(); 17972 boolean changed = false; 17973 17974 final Drawable bg = mBackground; 17975 if (bg != null && bg.isStateful()) { 17976 changed |= bg.setState(state); 17977 } 17978 17979 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 17980 if (fg != null && fg.isStateful()) { 17981 changed |= fg.setState(state); 17982 } 17983 17984 if (mScrollCache != null) { 17985 final Drawable scrollBar = mScrollCache.scrollBar; 17986 if (scrollBar != null && scrollBar.isStateful()) { 17987 changed |= scrollBar.setState(state) 17988 && mScrollCache.state != ScrollabilityCache.OFF; 17989 } 17990 } 17991 17992 if (mStateListAnimator != null) { 17993 mStateListAnimator.setState(state); 17994 } 17995 17996 if (changed) { 17997 invalidate(); 17998 } 17999 } 18000 18001 /** 18002 * This function is called whenever the view hotspot changes and needs to 18003 * be propagated to drawables or child views managed by the view. 18004 * <p> 18005 * Dispatching to child views is handled by 18006 * {@link #dispatchDrawableHotspotChanged(float, float)}. 18007 * <p> 18008 * Be sure to call through to the superclass when overriding this function. 18009 * 18010 * @param x hotspot x coordinate 18011 * @param y hotspot y coordinate 18012 */ 18013 @CallSuper drawableHotspotChanged(float x, float y)18014 public void drawableHotspotChanged(float x, float y) { 18015 if (mBackground != null) { 18016 mBackground.setHotspot(x, y); 18017 } 18018 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18019 mForegroundInfo.mDrawable.setHotspot(x, y); 18020 } 18021 18022 dispatchDrawableHotspotChanged(x, y); 18023 } 18024 18025 /** 18026 * Dispatches drawableHotspotChanged to all of this View's children. 18027 * 18028 * @param x hotspot x coordinate 18029 * @param y hotspot y coordinate 18030 * @see #drawableHotspotChanged(float, float) 18031 */ dispatchDrawableHotspotChanged(float x, float y)18032 public void dispatchDrawableHotspotChanged(float x, float y) { 18033 } 18034 18035 /** 18036 * Call this to force a view to update its drawable state. This will cause 18037 * drawableStateChanged to be called on this view. Views that are interested 18038 * in the new state should call getDrawableState. 18039 * 18040 * @see #drawableStateChanged 18041 * @see #getDrawableState 18042 */ refreshDrawableState()18043 public void refreshDrawableState() { 18044 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 18045 drawableStateChanged(); 18046 18047 ViewParent parent = mParent; 18048 if (parent != null) { 18049 parent.childDrawableStateChanged(this); 18050 } 18051 } 18052 18053 /** 18054 * Return an array of resource IDs of the drawable states representing the 18055 * current state of the view. 18056 * 18057 * @return The current drawable state 18058 * 18059 * @see Drawable#setState(int[]) 18060 * @see #drawableStateChanged() 18061 * @see #onCreateDrawableState(int) 18062 */ getDrawableState()18063 public final int[] getDrawableState() { 18064 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 18065 return mDrawableState; 18066 } else { 18067 mDrawableState = onCreateDrawableState(0); 18068 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 18069 return mDrawableState; 18070 } 18071 } 18072 18073 /** 18074 * Generate the new {@link android.graphics.drawable.Drawable} state for 18075 * this view. This is called by the view 18076 * system when the cached Drawable state is determined to be invalid. To 18077 * retrieve the current state, you should use {@link #getDrawableState}. 18078 * 18079 * @param extraSpace if non-zero, this is the number of extra entries you 18080 * would like in the returned array in which you can place your own 18081 * states. 18082 * 18083 * @return Returns an array holding the current {@link Drawable} state of 18084 * the view. 18085 * 18086 * @see #mergeDrawableStates(int[], int[]) 18087 */ onCreateDrawableState(int extraSpace)18088 protected int[] onCreateDrawableState(int extraSpace) { 18089 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 18090 mParent instanceof View) { 18091 return ((View) mParent).onCreateDrawableState(extraSpace); 18092 } 18093 18094 int[] drawableState; 18095 18096 int privateFlags = mPrivateFlags; 18097 18098 int viewStateIndex = 0; 18099 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 18100 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 18101 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 18102 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 18103 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 18104 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 18105 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 18106 ThreadedRenderer.isAvailable()) { 18107 // This is set if HW acceleration is requested, even if the current 18108 // process doesn't allow it. This is just to allow app preview 18109 // windows to better match their app. 18110 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 18111 } 18112 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 18113 18114 final int privateFlags2 = mPrivateFlags2; 18115 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 18116 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 18117 } 18118 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 18119 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 18120 } 18121 18122 drawableState = StateSet.get(viewStateIndex); 18123 18124 //noinspection ConstantIfStatement 18125 if (false) { 18126 Log.i("View", "drawableStateIndex=" + viewStateIndex); 18127 Log.i("View", toString() 18128 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 18129 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 18130 + " fo=" + hasFocus() 18131 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 18132 + " wf=" + hasWindowFocus() 18133 + ": " + Arrays.toString(drawableState)); 18134 } 18135 18136 if (extraSpace == 0) { 18137 return drawableState; 18138 } 18139 18140 final int[] fullState; 18141 if (drawableState != null) { 18142 fullState = new int[drawableState.length + extraSpace]; 18143 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 18144 } else { 18145 fullState = new int[extraSpace]; 18146 } 18147 18148 return fullState; 18149 } 18150 18151 /** 18152 * Merge your own state values in <var>additionalState</var> into the base 18153 * state values <var>baseState</var> that were returned by 18154 * {@link #onCreateDrawableState(int)}. 18155 * 18156 * @param baseState The base state values returned by 18157 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 18158 * own additional state values. 18159 * 18160 * @param additionalState The additional state values you would like 18161 * added to <var>baseState</var>; this array is not modified. 18162 * 18163 * @return As a convenience, the <var>baseState</var> array you originally 18164 * passed into the function is returned. 18165 * 18166 * @see #onCreateDrawableState(int) 18167 */ mergeDrawableStates(int[] baseState, int[] additionalState)18168 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 18169 final int N = baseState.length; 18170 int i = N - 1; 18171 while (i >= 0 && baseState[i] == 0) { 18172 i--; 18173 } 18174 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 18175 return baseState; 18176 } 18177 18178 /** 18179 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 18180 * on all Drawable objects associated with this view. 18181 * <p> 18182 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 18183 * attached to this view. 18184 */ 18185 @CallSuper jumpDrawablesToCurrentState()18186 public void jumpDrawablesToCurrentState() { 18187 if (mBackground != null) { 18188 mBackground.jumpToCurrentState(); 18189 } 18190 if (mStateListAnimator != null) { 18191 mStateListAnimator.jumpToCurrentState(); 18192 } 18193 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 18194 mForegroundInfo.mDrawable.jumpToCurrentState(); 18195 } 18196 } 18197 18198 /** 18199 * Sets the background color for this view. 18200 * @param color the color of the background 18201 */ 18202 @RemotableViewMethod setBackgroundColor(@olorInt int color)18203 public void setBackgroundColor(@ColorInt int color) { 18204 if (mBackground instanceof ColorDrawable) { 18205 ((ColorDrawable) mBackground.mutate()).setColor(color); 18206 computeOpaqueFlags(); 18207 mBackgroundResource = 0; 18208 } else { 18209 setBackground(new ColorDrawable(color)); 18210 } 18211 } 18212 18213 /** 18214 * Set the background to a given resource. The resource should refer to 18215 * a Drawable object or 0 to remove the background. 18216 * @param resid The identifier of the resource. 18217 * 18218 * @attr ref android.R.styleable#View_background 18219 */ 18220 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)18221 public void setBackgroundResource(@DrawableRes int resid) { 18222 if (resid != 0 && resid == mBackgroundResource) { 18223 return; 18224 } 18225 18226 Drawable d = null; 18227 if (resid != 0) { 18228 d = mContext.getDrawable(resid); 18229 } 18230 setBackground(d); 18231 18232 mBackgroundResource = resid; 18233 } 18234 18235 /** 18236 * Set the background to a given Drawable, or remove the background. If the 18237 * background has padding, this View's padding is set to the background's 18238 * padding. However, when a background is removed, this View's padding isn't 18239 * touched. If setting the padding is desired, please use 18240 * {@link #setPadding(int, int, int, int)}. 18241 * 18242 * @param background The Drawable to use as the background, or null to remove the 18243 * background 18244 */ setBackground(Drawable background)18245 public void setBackground(Drawable background) { 18246 //noinspection deprecation 18247 setBackgroundDrawable(background); 18248 } 18249 18250 /** 18251 * @deprecated use {@link #setBackground(Drawable)} instead 18252 */ 18253 @Deprecated setBackgroundDrawable(Drawable background)18254 public void setBackgroundDrawable(Drawable background) { 18255 computeOpaqueFlags(); 18256 18257 if (background == mBackground) { 18258 return; 18259 } 18260 18261 boolean requestLayout = false; 18262 18263 mBackgroundResource = 0; 18264 18265 /* 18266 * Regardless of whether we're setting a new background or not, we want 18267 * to clear the previous drawable. setVisible first while we still have the callback set. 18268 */ 18269 if (mBackground != null) { 18270 if (isAttachedToWindow()) { 18271 mBackground.setVisible(false, false); 18272 } 18273 mBackground.setCallback(null); 18274 unscheduleDrawable(mBackground); 18275 } 18276 18277 if (background != null) { 18278 Rect padding = sThreadLocal.get(); 18279 if (padding == null) { 18280 padding = new Rect(); 18281 sThreadLocal.set(padding); 18282 } 18283 resetResolvedDrawablesInternal(); 18284 background.setLayoutDirection(getLayoutDirection()); 18285 if (background.getPadding(padding)) { 18286 resetResolvedPaddingInternal(); 18287 switch (background.getLayoutDirection()) { 18288 case LAYOUT_DIRECTION_RTL: 18289 mUserPaddingLeftInitial = padding.right; 18290 mUserPaddingRightInitial = padding.left; 18291 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 18292 break; 18293 case LAYOUT_DIRECTION_LTR: 18294 default: 18295 mUserPaddingLeftInitial = padding.left; 18296 mUserPaddingRightInitial = padding.right; 18297 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 18298 } 18299 mLeftPaddingDefined = false; 18300 mRightPaddingDefined = false; 18301 } 18302 18303 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 18304 // if it has a different minimum size, we should layout again 18305 if (mBackground == null 18306 || mBackground.getMinimumHeight() != background.getMinimumHeight() 18307 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 18308 requestLayout = true; 18309 } 18310 18311 // Set mBackground before we set this as the callback and start making other 18312 // background drawable state change calls. In particular, the setVisible call below 18313 // can result in drawables attempting to start animations or otherwise invalidate, 18314 // which requires the view set as the callback (us) to recognize the drawable as 18315 // belonging to it as per verifyDrawable. 18316 mBackground = background; 18317 if (background.isStateful()) { 18318 background.setState(getDrawableState()); 18319 } 18320 if (isAttachedToWindow()) { 18321 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18322 } 18323 18324 applyBackgroundTint(); 18325 18326 // Set callback last, since the view may still be initializing. 18327 background.setCallback(this); 18328 18329 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 18330 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18331 requestLayout = true; 18332 } 18333 } else { 18334 /* Remove the background */ 18335 mBackground = null; 18336 if ((mViewFlags & WILL_NOT_DRAW) != 0 18337 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 18338 mPrivateFlags |= PFLAG_SKIP_DRAW; 18339 } 18340 18341 /* 18342 * When the background is set, we try to apply its padding to this 18343 * View. When the background is removed, we don't touch this View's 18344 * padding. This is noted in the Javadocs. Hence, we don't need to 18345 * requestLayout(), the invalidate() below is sufficient. 18346 */ 18347 18348 // The old background's minimum size could have affected this 18349 // View's layout, so let's requestLayout 18350 requestLayout = true; 18351 } 18352 18353 computeOpaqueFlags(); 18354 18355 if (requestLayout) { 18356 requestLayout(); 18357 } 18358 18359 mBackgroundSizeChanged = true; 18360 invalidate(true); 18361 invalidateOutline(); 18362 } 18363 18364 /** 18365 * Gets the background drawable 18366 * 18367 * @return The drawable used as the background for this view, if any. 18368 * 18369 * @see #setBackground(Drawable) 18370 * 18371 * @attr ref android.R.styleable#View_background 18372 */ getBackground()18373 public Drawable getBackground() { 18374 return mBackground; 18375 } 18376 18377 /** 18378 * Applies a tint to the background drawable. Does not modify the current tint 18379 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 18380 * <p> 18381 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 18382 * mutate the drawable and apply the specified tint and tint mode using 18383 * {@link Drawable#setTintList(ColorStateList)}. 18384 * 18385 * @param tint the tint to apply, may be {@code null} to clear tint 18386 * 18387 * @attr ref android.R.styleable#View_backgroundTint 18388 * @see #getBackgroundTintList() 18389 * @see Drawable#setTintList(ColorStateList) 18390 */ setBackgroundTintList(@ullable ColorStateList tint)18391 public void setBackgroundTintList(@Nullable ColorStateList tint) { 18392 if (mBackgroundTint == null) { 18393 mBackgroundTint = new TintInfo(); 18394 } 18395 mBackgroundTint.mTintList = tint; 18396 mBackgroundTint.mHasTintList = true; 18397 18398 applyBackgroundTint(); 18399 } 18400 18401 /** 18402 * Return the tint applied to the background drawable, if specified. 18403 * 18404 * @return the tint applied to the background drawable 18405 * @attr ref android.R.styleable#View_backgroundTint 18406 * @see #setBackgroundTintList(ColorStateList) 18407 */ 18408 @Nullable getBackgroundTintList()18409 public ColorStateList getBackgroundTintList() { 18410 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 18411 } 18412 18413 /** 18414 * Specifies the blending mode used to apply the tint specified by 18415 * {@link #setBackgroundTintList(ColorStateList)}} to the background 18416 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 18417 * 18418 * @param tintMode the blending mode used to apply the tint, may be 18419 * {@code null} to clear tint 18420 * @attr ref android.R.styleable#View_backgroundTintMode 18421 * @see #getBackgroundTintMode() 18422 * @see Drawable#setTintMode(PorterDuff.Mode) 18423 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)18424 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 18425 if (mBackgroundTint == null) { 18426 mBackgroundTint = new TintInfo(); 18427 } 18428 mBackgroundTint.mTintMode = tintMode; 18429 mBackgroundTint.mHasTintMode = true; 18430 18431 applyBackgroundTint(); 18432 } 18433 18434 /** 18435 * Return the blending mode used to apply the tint to the background 18436 * drawable, if specified. 18437 * 18438 * @return the blending mode used to apply the tint to the background 18439 * drawable 18440 * @attr ref android.R.styleable#View_backgroundTintMode 18441 * @see #setBackgroundTintMode(PorterDuff.Mode) 18442 */ 18443 @Nullable getBackgroundTintMode()18444 public PorterDuff.Mode getBackgroundTintMode() { 18445 return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 18446 } 18447 applyBackgroundTint()18448 private void applyBackgroundTint() { 18449 if (mBackground != null && mBackgroundTint != null) { 18450 final TintInfo tintInfo = mBackgroundTint; 18451 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 18452 mBackground = mBackground.mutate(); 18453 18454 if (tintInfo.mHasTintList) { 18455 mBackground.setTintList(tintInfo.mTintList); 18456 } 18457 18458 if (tintInfo.mHasTintMode) { 18459 mBackground.setTintMode(tintInfo.mTintMode); 18460 } 18461 18462 // The drawable (or one of its children) may not have been 18463 // stateful before applying the tint, so let's try again. 18464 if (mBackground.isStateful()) { 18465 mBackground.setState(getDrawableState()); 18466 } 18467 } 18468 } 18469 } 18470 18471 /** 18472 * Returns the drawable used as the foreground of this View. The 18473 * foreground drawable, if non-null, is always drawn on top of the view's content. 18474 * 18475 * @return a Drawable or null if no foreground was set 18476 * 18477 * @see #onDrawForeground(Canvas) 18478 */ getForeground()18479 public Drawable getForeground() { 18480 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18481 } 18482 18483 /** 18484 * Supply a Drawable that is to be rendered on top of all of the content in the view. 18485 * 18486 * @param foreground the Drawable to be drawn on top of the children 18487 * 18488 * @attr ref android.R.styleable#View_foreground 18489 */ setForeground(Drawable foreground)18490 public void setForeground(Drawable foreground) { 18491 if (mForegroundInfo == null) { 18492 if (foreground == null) { 18493 // Nothing to do. 18494 return; 18495 } 18496 mForegroundInfo = new ForegroundInfo(); 18497 } 18498 18499 if (foreground == mForegroundInfo.mDrawable) { 18500 // Nothing to do 18501 return; 18502 } 18503 18504 if (mForegroundInfo.mDrawable != null) { 18505 if (isAttachedToWindow()) { 18506 mForegroundInfo.mDrawable.setVisible(false, false); 18507 } 18508 mForegroundInfo.mDrawable.setCallback(null); 18509 unscheduleDrawable(mForegroundInfo.mDrawable); 18510 } 18511 18512 mForegroundInfo.mDrawable = foreground; 18513 mForegroundInfo.mBoundsChanged = true; 18514 if (foreground != null) { 18515 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 18516 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18517 } 18518 foreground.setLayoutDirection(getLayoutDirection()); 18519 if (foreground.isStateful()) { 18520 foreground.setState(getDrawableState()); 18521 } 18522 applyForegroundTint(); 18523 if (isAttachedToWindow()) { 18524 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 18525 } 18526 // Set callback last, since the view may still be initializing. 18527 foreground.setCallback(this); 18528 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) { 18529 mPrivateFlags |= PFLAG_SKIP_DRAW; 18530 } 18531 requestLayout(); 18532 invalidate(); 18533 } 18534 18535 /** 18536 * Magic bit used to support features of framework-internal window decor implementation details. 18537 * This used to live exclusively in FrameLayout. 18538 * 18539 * @return true if the foreground should draw inside the padding region or false 18540 * if it should draw inset by the view's padding 18541 * @hide internal use only; only used by FrameLayout and internal screen layouts. 18542 */ isForegroundInsidePadding()18543 public boolean isForegroundInsidePadding() { 18544 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 18545 } 18546 18547 /** 18548 * Describes how the foreground is positioned. 18549 * 18550 * @return foreground gravity. 18551 * 18552 * @see #setForegroundGravity(int) 18553 * 18554 * @attr ref android.R.styleable#View_foregroundGravity 18555 */ getForegroundGravity()18556 public int getForegroundGravity() { 18557 return mForegroundInfo != null ? mForegroundInfo.mGravity 18558 : Gravity.START | Gravity.TOP; 18559 } 18560 18561 /** 18562 * Describes how the foreground is positioned. Defaults to START and TOP. 18563 * 18564 * @param gravity see {@link android.view.Gravity} 18565 * 18566 * @see #getForegroundGravity() 18567 * 18568 * @attr ref android.R.styleable#View_foregroundGravity 18569 */ setForegroundGravity(int gravity)18570 public void setForegroundGravity(int gravity) { 18571 if (mForegroundInfo == null) { 18572 mForegroundInfo = new ForegroundInfo(); 18573 } 18574 18575 if (mForegroundInfo.mGravity != gravity) { 18576 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 18577 gravity |= Gravity.START; 18578 } 18579 18580 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 18581 gravity |= Gravity.TOP; 18582 } 18583 18584 mForegroundInfo.mGravity = gravity; 18585 requestLayout(); 18586 } 18587 } 18588 18589 /** 18590 * Applies a tint to the foreground drawable. Does not modify the current tint 18591 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 18592 * <p> 18593 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 18594 * mutate the drawable and apply the specified tint and tint mode using 18595 * {@link Drawable#setTintList(ColorStateList)}. 18596 * 18597 * @param tint the tint to apply, may be {@code null} to clear tint 18598 * 18599 * @attr ref android.R.styleable#View_foregroundTint 18600 * @see #getForegroundTintList() 18601 * @see Drawable#setTintList(ColorStateList) 18602 */ setForegroundTintList(@ullable ColorStateList tint)18603 public void setForegroundTintList(@Nullable ColorStateList tint) { 18604 if (mForegroundInfo == null) { 18605 mForegroundInfo = new ForegroundInfo(); 18606 } 18607 if (mForegroundInfo.mTintInfo == null) { 18608 mForegroundInfo.mTintInfo = new TintInfo(); 18609 } 18610 mForegroundInfo.mTintInfo.mTintList = tint; 18611 mForegroundInfo.mTintInfo.mHasTintList = true; 18612 18613 applyForegroundTint(); 18614 } 18615 18616 /** 18617 * Return the tint applied to the foreground drawable, if specified. 18618 * 18619 * @return the tint applied to the foreground drawable 18620 * @attr ref android.R.styleable#View_foregroundTint 18621 * @see #setForegroundTintList(ColorStateList) 18622 */ 18623 @Nullable getForegroundTintList()18624 public ColorStateList getForegroundTintList() { 18625 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 18626 ? mForegroundInfo.mTintInfo.mTintList : null; 18627 } 18628 18629 /** 18630 * Specifies the blending mode used to apply the tint specified by 18631 * {@link #setForegroundTintList(ColorStateList)}} to the background 18632 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 18633 * 18634 * @param tintMode the blending mode used to apply the tint, may be 18635 * {@code null} to clear tint 18636 * @attr ref android.R.styleable#View_foregroundTintMode 18637 * @see #getForegroundTintMode() 18638 * @see Drawable#setTintMode(PorterDuff.Mode) 18639 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)18640 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 18641 if (mForegroundInfo == null) { 18642 mForegroundInfo = new ForegroundInfo(); 18643 } 18644 if (mForegroundInfo.mTintInfo == null) { 18645 mForegroundInfo.mTintInfo = new TintInfo(); 18646 } 18647 mForegroundInfo.mTintInfo.mTintMode = tintMode; 18648 mForegroundInfo.mTintInfo.mHasTintMode = true; 18649 18650 applyForegroundTint(); 18651 } 18652 18653 /** 18654 * Return the blending mode used to apply the tint to the foreground 18655 * drawable, if specified. 18656 * 18657 * @return the blending mode used to apply the tint to the foreground 18658 * drawable 18659 * @attr ref android.R.styleable#View_foregroundTintMode 18660 * @see #setForegroundTintMode(PorterDuff.Mode) 18661 */ 18662 @Nullable getForegroundTintMode()18663 public PorterDuff.Mode getForegroundTintMode() { 18664 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 18665 ? mForegroundInfo.mTintInfo.mTintMode : null; 18666 } 18667 applyForegroundTint()18668 private void applyForegroundTint() { 18669 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 18670 && mForegroundInfo.mTintInfo != null) { 18671 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 18672 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 18673 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 18674 18675 if (tintInfo.mHasTintList) { 18676 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 18677 } 18678 18679 if (tintInfo.mHasTintMode) { 18680 mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); 18681 } 18682 18683 // The drawable (or one of its children) may not have been 18684 // stateful before applying the tint, so let's try again. 18685 if (mForegroundInfo.mDrawable.isStateful()) { 18686 mForegroundInfo.mDrawable.setState(getDrawableState()); 18687 } 18688 } 18689 } 18690 } 18691 18692 /** 18693 * Draw any foreground content for this view. 18694 * 18695 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 18696 * drawable or other view-specific decorations. The foreground is drawn on top of the 18697 * primary view content.</p> 18698 * 18699 * @param canvas canvas to draw into 18700 */ onDrawForeground(Canvas canvas)18701 public void onDrawForeground(Canvas canvas) { 18702 onDrawScrollIndicators(canvas); 18703 onDrawScrollBars(canvas); 18704 18705 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 18706 if (foreground != null) { 18707 if (mForegroundInfo.mBoundsChanged) { 18708 mForegroundInfo.mBoundsChanged = false; 18709 final Rect selfBounds = mForegroundInfo.mSelfBounds; 18710 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 18711 18712 if (mForegroundInfo.mInsidePadding) { 18713 selfBounds.set(0, 0, getWidth(), getHeight()); 18714 } else { 18715 selfBounds.set(getPaddingLeft(), getPaddingTop(), 18716 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 18717 } 18718 18719 final int ld = getLayoutDirection(); 18720 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 18721 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 18722 foreground.setBounds(overlayBounds); 18723 } 18724 18725 foreground.draw(canvas); 18726 } 18727 } 18728 18729 /** 18730 * Sets the padding. The view may add on the space required to display 18731 * the scrollbars, depending on the style and visibility of the scrollbars. 18732 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 18733 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 18734 * from the values set in this call. 18735 * 18736 * @attr ref android.R.styleable#View_padding 18737 * @attr ref android.R.styleable#View_paddingBottom 18738 * @attr ref android.R.styleable#View_paddingLeft 18739 * @attr ref android.R.styleable#View_paddingRight 18740 * @attr ref android.R.styleable#View_paddingTop 18741 * @param left the left padding in pixels 18742 * @param top the top padding in pixels 18743 * @param right the right padding in pixels 18744 * @param bottom the bottom padding in pixels 18745 */ setPadding(int left, int top, int right, int bottom)18746 public void setPadding(int left, int top, int right, int bottom) { 18747 resetResolvedPaddingInternal(); 18748 18749 mUserPaddingStart = UNDEFINED_PADDING; 18750 mUserPaddingEnd = UNDEFINED_PADDING; 18751 18752 mUserPaddingLeftInitial = left; 18753 mUserPaddingRightInitial = right; 18754 18755 mLeftPaddingDefined = true; 18756 mRightPaddingDefined = true; 18757 18758 internalSetPadding(left, top, right, bottom); 18759 } 18760 18761 /** 18762 * @hide 18763 */ internalSetPadding(int left, int top, int right, int bottom)18764 protected void internalSetPadding(int left, int top, int right, int bottom) { 18765 mUserPaddingLeft = left; 18766 mUserPaddingRight = right; 18767 mUserPaddingBottom = bottom; 18768 18769 final int viewFlags = mViewFlags; 18770 boolean changed = false; 18771 18772 // Common case is there are no scroll bars. 18773 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 18774 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 18775 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 18776 ? 0 : getVerticalScrollbarWidth(); 18777 switch (mVerticalScrollbarPosition) { 18778 case SCROLLBAR_POSITION_DEFAULT: 18779 if (isLayoutRtl()) { 18780 left += offset; 18781 } else { 18782 right += offset; 18783 } 18784 break; 18785 case SCROLLBAR_POSITION_RIGHT: 18786 right += offset; 18787 break; 18788 case SCROLLBAR_POSITION_LEFT: 18789 left += offset; 18790 break; 18791 } 18792 } 18793 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 18794 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 18795 ? 0 : getHorizontalScrollbarHeight(); 18796 } 18797 } 18798 18799 if (mPaddingLeft != left) { 18800 changed = true; 18801 mPaddingLeft = left; 18802 } 18803 if (mPaddingTop != top) { 18804 changed = true; 18805 mPaddingTop = top; 18806 } 18807 if (mPaddingRight != right) { 18808 changed = true; 18809 mPaddingRight = right; 18810 } 18811 if (mPaddingBottom != bottom) { 18812 changed = true; 18813 mPaddingBottom = bottom; 18814 } 18815 18816 if (changed) { 18817 requestLayout(); 18818 invalidateOutline(); 18819 } 18820 } 18821 18822 /** 18823 * Sets the relative padding. The view may add on the space required to display 18824 * the scrollbars, depending on the style and visibility of the scrollbars. 18825 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 18826 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 18827 * from the values set in this call. 18828 * 18829 * @attr ref android.R.styleable#View_padding 18830 * @attr ref android.R.styleable#View_paddingBottom 18831 * @attr ref android.R.styleable#View_paddingStart 18832 * @attr ref android.R.styleable#View_paddingEnd 18833 * @attr ref android.R.styleable#View_paddingTop 18834 * @param start the start padding in pixels 18835 * @param top the top padding in pixels 18836 * @param end the end padding in pixels 18837 * @param bottom the bottom padding in pixels 18838 */ setPaddingRelative(int start, int top, int end, int bottom)18839 public void setPaddingRelative(int start, int top, int end, int bottom) { 18840 resetResolvedPaddingInternal(); 18841 18842 mUserPaddingStart = start; 18843 mUserPaddingEnd = end; 18844 mLeftPaddingDefined = true; 18845 mRightPaddingDefined = true; 18846 18847 switch(getLayoutDirection()) { 18848 case LAYOUT_DIRECTION_RTL: 18849 mUserPaddingLeftInitial = end; 18850 mUserPaddingRightInitial = start; 18851 internalSetPadding(end, top, start, bottom); 18852 break; 18853 case LAYOUT_DIRECTION_LTR: 18854 default: 18855 mUserPaddingLeftInitial = start; 18856 mUserPaddingRightInitial = end; 18857 internalSetPadding(start, top, end, bottom); 18858 } 18859 } 18860 18861 /** 18862 * Returns the top padding of this view. 18863 * 18864 * @return the top padding in pixels 18865 */ getPaddingTop()18866 public int getPaddingTop() { 18867 return mPaddingTop; 18868 } 18869 18870 /** 18871 * Returns the bottom padding of this view. If there are inset and enabled 18872 * scrollbars, this value may include the space required to display the 18873 * scrollbars as well. 18874 * 18875 * @return the bottom padding in pixels 18876 */ getPaddingBottom()18877 public int getPaddingBottom() { 18878 return mPaddingBottom; 18879 } 18880 18881 /** 18882 * Returns the left padding of this view. If there are inset and enabled 18883 * scrollbars, this value may include the space required to display the 18884 * scrollbars as well. 18885 * 18886 * @return the left padding in pixels 18887 */ getPaddingLeft()18888 public int getPaddingLeft() { 18889 if (!isPaddingResolved()) { 18890 resolvePadding(); 18891 } 18892 return mPaddingLeft; 18893 } 18894 18895 /** 18896 * Returns the start padding of this view depending on its resolved layout direction. 18897 * If there are inset and enabled scrollbars, this value may include the space 18898 * required to display the scrollbars as well. 18899 * 18900 * @return the start padding in pixels 18901 */ getPaddingStart()18902 public int getPaddingStart() { 18903 if (!isPaddingResolved()) { 18904 resolvePadding(); 18905 } 18906 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 18907 mPaddingRight : mPaddingLeft; 18908 } 18909 18910 /** 18911 * Returns the right padding of this view. If there are inset and enabled 18912 * scrollbars, this value may include the space required to display the 18913 * scrollbars as well. 18914 * 18915 * @return the right padding in pixels 18916 */ getPaddingRight()18917 public int getPaddingRight() { 18918 if (!isPaddingResolved()) { 18919 resolvePadding(); 18920 } 18921 return mPaddingRight; 18922 } 18923 18924 /** 18925 * Returns the end padding of this view depending on its resolved layout direction. 18926 * If there are inset and enabled scrollbars, this value may include the space 18927 * required to display the scrollbars as well. 18928 * 18929 * @return the end padding in pixels 18930 */ getPaddingEnd()18931 public int getPaddingEnd() { 18932 if (!isPaddingResolved()) { 18933 resolvePadding(); 18934 } 18935 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 18936 mPaddingLeft : mPaddingRight; 18937 } 18938 18939 /** 18940 * Return if the padding has been set through relative values 18941 * {@link #setPaddingRelative(int, int, int, int)} or through 18942 * @attr ref android.R.styleable#View_paddingStart or 18943 * @attr ref android.R.styleable#View_paddingEnd 18944 * 18945 * @return true if the padding is relative or false if it is not. 18946 */ isPaddingRelative()18947 public boolean isPaddingRelative() { 18948 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 18949 } 18950 computeOpticalInsets()18951 Insets computeOpticalInsets() { 18952 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 18953 } 18954 18955 /** 18956 * @hide 18957 */ resetPaddingToInitialValues()18958 public void resetPaddingToInitialValues() { 18959 if (isRtlCompatibilityMode()) { 18960 mPaddingLeft = mUserPaddingLeftInitial; 18961 mPaddingRight = mUserPaddingRightInitial; 18962 return; 18963 } 18964 if (isLayoutRtl()) { 18965 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 18966 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 18967 } else { 18968 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 18969 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 18970 } 18971 } 18972 18973 /** 18974 * @hide 18975 */ getOpticalInsets()18976 public Insets getOpticalInsets() { 18977 if (mLayoutInsets == null) { 18978 mLayoutInsets = computeOpticalInsets(); 18979 } 18980 return mLayoutInsets; 18981 } 18982 18983 /** 18984 * Set this view's optical insets. 18985 * 18986 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 18987 * property. Views that compute their own optical insets should call it as part of measurement. 18988 * This method does not request layout. If you are setting optical insets outside of 18989 * measure/layout itself you will want to call requestLayout() yourself. 18990 * </p> 18991 * @hide 18992 */ setOpticalInsets(Insets insets)18993 public void setOpticalInsets(Insets insets) { 18994 mLayoutInsets = insets; 18995 } 18996 18997 /** 18998 * Changes the selection state of this view. A view can be selected or not. 18999 * Note that selection is not the same as focus. Views are typically 19000 * selected in the context of an AdapterView like ListView or GridView; 19001 * the selected view is the view that is highlighted. 19002 * 19003 * @param selected true if the view must be selected, false otherwise 19004 */ setSelected(boolean selected)19005 public void setSelected(boolean selected) { 19006 //noinspection DoubleNegation 19007 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 19008 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 19009 if (!selected) resetPressedState(); 19010 invalidate(true); 19011 refreshDrawableState(); 19012 dispatchSetSelected(selected); 19013 if (selected) { 19014 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 19015 } else { 19016 notifyViewAccessibilityStateChangedIfNeeded( 19017 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 19018 } 19019 } 19020 } 19021 19022 /** 19023 * Dispatch setSelected to all of this View's children. 19024 * 19025 * @see #setSelected(boolean) 19026 * 19027 * @param selected The new selected state 19028 */ dispatchSetSelected(boolean selected)19029 protected void dispatchSetSelected(boolean selected) { 19030 } 19031 19032 /** 19033 * Indicates the selection state of this view. 19034 * 19035 * @return true if the view is selected, false otherwise 19036 */ 19037 @ViewDebug.ExportedProperty isSelected()19038 public boolean isSelected() { 19039 return (mPrivateFlags & PFLAG_SELECTED) != 0; 19040 } 19041 19042 /** 19043 * Changes the activated state of this view. A view can be activated or not. 19044 * Note that activation is not the same as selection. Selection is 19045 * a transient property, representing the view (hierarchy) the user is 19046 * currently interacting with. Activation is a longer-term state that the 19047 * user can move views in and out of. For example, in a list view with 19048 * single or multiple selection enabled, the views in the current selection 19049 * set are activated. (Um, yeah, we are deeply sorry about the terminology 19050 * here.) The activated state is propagated down to children of the view it 19051 * is set on. 19052 * 19053 * @param activated true if the view must be activated, false otherwise 19054 */ setActivated(boolean activated)19055 public void setActivated(boolean activated) { 19056 //noinspection DoubleNegation 19057 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 19058 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 19059 invalidate(true); 19060 refreshDrawableState(); 19061 dispatchSetActivated(activated); 19062 } 19063 } 19064 19065 /** 19066 * Dispatch setActivated to all of this View's children. 19067 * 19068 * @see #setActivated(boolean) 19069 * 19070 * @param activated The new activated state 19071 */ dispatchSetActivated(boolean activated)19072 protected void dispatchSetActivated(boolean activated) { 19073 } 19074 19075 /** 19076 * Indicates the activation state of this view. 19077 * 19078 * @return true if the view is activated, false otherwise 19079 */ 19080 @ViewDebug.ExportedProperty isActivated()19081 public boolean isActivated() { 19082 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 19083 } 19084 19085 /** 19086 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 19087 * observer can be used to get notifications when global events, like 19088 * layout, happen. 19089 * 19090 * The returned ViewTreeObserver observer is not guaranteed to remain 19091 * valid for the lifetime of this View. If the caller of this method keeps 19092 * a long-lived reference to ViewTreeObserver, it should always check for 19093 * the return value of {@link ViewTreeObserver#isAlive()}. 19094 * 19095 * @return The ViewTreeObserver for this view's hierarchy. 19096 */ getViewTreeObserver()19097 public ViewTreeObserver getViewTreeObserver() { 19098 if (mAttachInfo != null) { 19099 return mAttachInfo.mTreeObserver; 19100 } 19101 if (mFloatingTreeObserver == null) { 19102 mFloatingTreeObserver = new ViewTreeObserver(); 19103 } 19104 return mFloatingTreeObserver; 19105 } 19106 19107 /** 19108 * <p>Finds the topmost view in the current view hierarchy.</p> 19109 * 19110 * @return the topmost view containing this view 19111 */ getRootView()19112 public View getRootView() { 19113 if (mAttachInfo != null) { 19114 final View v = mAttachInfo.mRootView; 19115 if (v != null) { 19116 return v; 19117 } 19118 } 19119 19120 View parent = this; 19121 19122 while (parent.mParent != null && parent.mParent instanceof View) { 19123 parent = (View) parent.mParent; 19124 } 19125 19126 return parent; 19127 } 19128 19129 /** 19130 * Transforms a motion event from view-local coordinates to on-screen 19131 * coordinates. 19132 * 19133 * @param ev the view-local motion event 19134 * @return false if the transformation could not be applied 19135 * @hide 19136 */ toGlobalMotionEvent(MotionEvent ev)19137 public boolean toGlobalMotionEvent(MotionEvent ev) { 19138 final AttachInfo info = mAttachInfo; 19139 if (info == null) { 19140 return false; 19141 } 19142 19143 final Matrix m = info.mTmpMatrix; 19144 m.set(Matrix.IDENTITY_MATRIX); 19145 transformMatrixToGlobal(m); 19146 ev.transform(m); 19147 return true; 19148 } 19149 19150 /** 19151 * Transforms a motion event from on-screen coordinates to view-local 19152 * coordinates. 19153 * 19154 * @param ev the on-screen motion event 19155 * @return false if the transformation could not be applied 19156 * @hide 19157 */ toLocalMotionEvent(MotionEvent ev)19158 public boolean toLocalMotionEvent(MotionEvent ev) { 19159 final AttachInfo info = mAttachInfo; 19160 if (info == null) { 19161 return false; 19162 } 19163 19164 final Matrix m = info.mTmpMatrix; 19165 m.set(Matrix.IDENTITY_MATRIX); 19166 transformMatrixToLocal(m); 19167 ev.transform(m); 19168 return true; 19169 } 19170 19171 /** 19172 * Modifies the input matrix such that it maps view-local coordinates to 19173 * on-screen coordinates. 19174 * 19175 * @param m input matrix to modify 19176 * @hide 19177 */ transformMatrixToGlobal(Matrix m)19178 public void transformMatrixToGlobal(Matrix m) { 19179 final ViewParent parent = mParent; 19180 if (parent instanceof View) { 19181 final View vp = (View) parent; 19182 vp.transformMatrixToGlobal(m); 19183 m.preTranslate(-vp.mScrollX, -vp.mScrollY); 19184 } else if (parent instanceof ViewRootImpl) { 19185 final ViewRootImpl vr = (ViewRootImpl) parent; 19186 vr.transformMatrixToGlobal(m); 19187 m.preTranslate(0, -vr.mCurScrollY); 19188 } 19189 19190 m.preTranslate(mLeft, mTop); 19191 19192 if (!hasIdentityMatrix()) { 19193 m.preConcat(getMatrix()); 19194 } 19195 } 19196 19197 /** 19198 * Modifies the input matrix such that it maps on-screen coordinates to 19199 * view-local coordinates. 19200 * 19201 * @param m input matrix to modify 19202 * @hide 19203 */ transformMatrixToLocal(Matrix m)19204 public void transformMatrixToLocal(Matrix m) { 19205 final ViewParent parent = mParent; 19206 if (parent instanceof View) { 19207 final View vp = (View) parent; 19208 vp.transformMatrixToLocal(m); 19209 m.postTranslate(vp.mScrollX, vp.mScrollY); 19210 } else if (parent instanceof ViewRootImpl) { 19211 final ViewRootImpl vr = (ViewRootImpl) parent; 19212 vr.transformMatrixToLocal(m); 19213 m.postTranslate(0, vr.mCurScrollY); 19214 } 19215 19216 m.postTranslate(-mLeft, -mTop); 19217 19218 if (!hasIdentityMatrix()) { 19219 m.postConcat(getInverseMatrix()); 19220 } 19221 } 19222 19223 /** 19224 * @hide 19225 */ 19226 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 19227 @ViewDebug.IntToString(from = 0, to = "x"), 19228 @ViewDebug.IntToString(from = 1, to = "y") 19229 }) getLocationOnScreen()19230 public int[] getLocationOnScreen() { 19231 int[] location = new int[2]; 19232 getLocationOnScreen(location); 19233 return location; 19234 } 19235 19236 /** 19237 * <p>Computes the coordinates of this view on the screen. The argument 19238 * must be an array of two integers. After the method returns, the array 19239 * contains the x and y location in that order.</p> 19240 * 19241 * @param outLocation an array of two integers in which to hold the coordinates 19242 */ getLocationOnScreen(@ize2) int[] outLocation)19243 public void getLocationOnScreen(@Size(2) int[] outLocation) { 19244 getLocationInWindow(outLocation); 19245 19246 final AttachInfo info = mAttachInfo; 19247 if (info != null) { 19248 outLocation[0] += info.mWindowLeft; 19249 outLocation[1] += info.mWindowTop; 19250 } 19251 } 19252 19253 /** 19254 * <p>Computes the coordinates of this view in its window. The argument 19255 * must be an array of two integers. After the method returns, the array 19256 * contains the x and y location in that order.</p> 19257 * 19258 * @param outLocation an array of two integers in which to hold the coordinates 19259 */ getLocationInWindow(@ize2) int[] outLocation)19260 public void getLocationInWindow(@Size(2) int[] outLocation) { 19261 if (outLocation == null || outLocation.length < 2) { 19262 throw new IllegalArgumentException("outLocation must be an array of two integers"); 19263 } 19264 19265 outLocation[0] = 0; 19266 outLocation[1] = 0; 19267 19268 transformFromViewToWindowSpace(outLocation); 19269 } 19270 19271 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)19272 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 19273 if (inOutLocation == null || inOutLocation.length < 2) { 19274 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 19275 } 19276 19277 if (mAttachInfo == null) { 19278 // When the view is not attached to a window, this method does not make sense 19279 inOutLocation[0] = inOutLocation[1] = 0; 19280 return; 19281 } 19282 19283 float position[] = mAttachInfo.mTmpTransformLocation; 19284 position[0] = inOutLocation[0]; 19285 position[1] = inOutLocation[1]; 19286 19287 if (!hasIdentityMatrix()) { 19288 getMatrix().mapPoints(position); 19289 } 19290 19291 position[0] += mLeft; 19292 position[1] += mTop; 19293 19294 ViewParent viewParent = mParent; 19295 while (viewParent instanceof View) { 19296 final View view = (View) viewParent; 19297 19298 position[0] -= view.mScrollX; 19299 position[1] -= view.mScrollY; 19300 19301 if (!view.hasIdentityMatrix()) { 19302 view.getMatrix().mapPoints(position); 19303 } 19304 19305 position[0] += view.mLeft; 19306 position[1] += view.mTop; 19307 19308 viewParent = view.mParent; 19309 } 19310 19311 if (viewParent instanceof ViewRootImpl) { 19312 // *cough* 19313 final ViewRootImpl vr = (ViewRootImpl) viewParent; 19314 position[1] -= vr.mCurScrollY; 19315 } 19316 19317 inOutLocation[0] = Math.round(position[0]); 19318 inOutLocation[1] = Math.round(position[1]); 19319 } 19320 19321 /** 19322 * {@hide} 19323 * @param id the id of the view to be found 19324 * @return the view of the specified id, null if cannot be found 19325 */ findViewTraversal(@dRes int id)19326 protected View findViewTraversal(@IdRes int id) { 19327 if (id == mID) { 19328 return this; 19329 } 19330 return null; 19331 } 19332 19333 /** 19334 * {@hide} 19335 * @param tag the tag of the view to be found 19336 * @return the view of specified tag, null if cannot be found 19337 */ findViewWithTagTraversal(Object tag)19338 protected View findViewWithTagTraversal(Object tag) { 19339 if (tag != null && tag.equals(mTag)) { 19340 return this; 19341 } 19342 return null; 19343 } 19344 19345 /** 19346 * {@hide} 19347 * @param predicate The predicate to evaluate. 19348 * @param childToSkip If not null, ignores this child during the recursive traversal. 19349 * @return The first view that matches the predicate or null. 19350 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)19351 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) { 19352 if (predicate.apply(this)) { 19353 return this; 19354 } 19355 return null; 19356 } 19357 19358 /** 19359 * Look for a child view with the given id. If this view has the given 19360 * id, return this view. 19361 * 19362 * @param id The id to search for. 19363 * @return The view that has the given id in the hierarchy or null 19364 */ 19365 @Nullable findViewById(@dRes int id)19366 public final View findViewById(@IdRes int id) { 19367 if (id < 0) { 19368 return null; 19369 } 19370 return findViewTraversal(id); 19371 } 19372 19373 /** 19374 * Finds a view by its unuque and stable accessibility id. 19375 * 19376 * @param accessibilityId The searched accessibility id. 19377 * @return The found view. 19378 */ findViewByAccessibilityId(int accessibilityId)19379 final View findViewByAccessibilityId(int accessibilityId) { 19380 if (accessibilityId < 0) { 19381 return null; 19382 } 19383 View view = findViewByAccessibilityIdTraversal(accessibilityId); 19384 if (view != null) { 19385 return view.includeForAccessibility() ? view : null; 19386 } 19387 return null; 19388 } 19389 19390 /** 19391 * Performs the traversal to find a view by its unuque and stable accessibility id. 19392 * 19393 * <strong>Note:</strong>This method does not stop at the root namespace 19394 * boundary since the user can touch the screen at an arbitrary location 19395 * potentially crossing the root namespace bounday which will send an 19396 * accessibility event to accessibility services and they should be able 19397 * to obtain the event source. Also accessibility ids are guaranteed to be 19398 * unique in the window. 19399 * 19400 * @param accessibilityId The accessibility id. 19401 * @return The found view. 19402 * 19403 * @hide 19404 */ findViewByAccessibilityIdTraversal(int accessibilityId)19405 public View findViewByAccessibilityIdTraversal(int accessibilityId) { 19406 if (getAccessibilityViewId() == accessibilityId) { 19407 return this; 19408 } 19409 return null; 19410 } 19411 19412 /** 19413 * Look for a child view with the given tag. If this view has the given 19414 * tag, return this view. 19415 * 19416 * @param tag The tag to search for, using "tag.equals(getTag())". 19417 * @return The View that has the given tag in the hierarchy or null 19418 */ findViewWithTag(Object tag)19419 public final View findViewWithTag(Object tag) { 19420 if (tag == null) { 19421 return null; 19422 } 19423 return findViewWithTagTraversal(tag); 19424 } 19425 19426 /** 19427 * {@hide} 19428 * Look for a child view that matches the specified predicate. 19429 * If this view matches the predicate, return this view. 19430 * 19431 * @param predicate The predicate to evaluate. 19432 * @return The first view that matches the predicate or null. 19433 */ findViewByPredicate(Predicate<View> predicate)19434 public final View findViewByPredicate(Predicate<View> predicate) { 19435 return findViewByPredicateTraversal(predicate, null); 19436 } 19437 19438 /** 19439 * {@hide} 19440 * Look for a child view that matches the specified predicate, 19441 * starting with the specified view and its descendents and then 19442 * recusively searching the ancestors and siblings of that view 19443 * until this view is reached. 19444 * 19445 * This method is useful in cases where the predicate does not match 19446 * a single unique view (perhaps multiple views use the same id) 19447 * and we are trying to find the view that is "closest" in scope to the 19448 * starting view. 19449 * 19450 * @param start The view to start from. 19451 * @param predicate The predicate to evaluate. 19452 * @return The first view that matches the predicate or null. 19453 */ findViewByPredicateInsideOut(View start, Predicate<View> predicate)19454 public final View findViewByPredicateInsideOut(View start, Predicate<View> predicate) { 19455 View childToSkip = null; 19456 for (;;) { 19457 View view = start.findViewByPredicateTraversal(predicate, childToSkip); 19458 if (view != null || start == this) { 19459 return view; 19460 } 19461 19462 ViewParent parent = start.getParent(); 19463 if (parent == null || !(parent instanceof View)) { 19464 return null; 19465 } 19466 19467 childToSkip = start; 19468 start = (View) parent; 19469 } 19470 } 19471 19472 /** 19473 * Sets the identifier for this view. The identifier does not have to be 19474 * unique in this view's hierarchy. The identifier should be a positive 19475 * number. 19476 * 19477 * @see #NO_ID 19478 * @see #getId() 19479 * @see #findViewById(int) 19480 * 19481 * @param id a number used to identify the view 19482 * 19483 * @attr ref android.R.styleable#View_id 19484 */ setId(@dRes int id)19485 public void setId(@IdRes int id) { 19486 mID = id; 19487 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 19488 mID = generateViewId(); 19489 } 19490 } 19491 19492 /** 19493 * {@hide} 19494 * 19495 * @param isRoot true if the view belongs to the root namespace, false 19496 * otherwise 19497 */ setIsRootNamespace(boolean isRoot)19498 public void setIsRootNamespace(boolean isRoot) { 19499 if (isRoot) { 19500 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 19501 } else { 19502 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 19503 } 19504 } 19505 19506 /** 19507 * {@hide} 19508 * 19509 * @return true if the view belongs to the root namespace, false otherwise 19510 */ isRootNamespace()19511 public boolean isRootNamespace() { 19512 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 19513 } 19514 19515 /** 19516 * Returns this view's identifier. 19517 * 19518 * @return a positive integer used to identify the view or {@link #NO_ID} 19519 * if the view has no ID 19520 * 19521 * @see #setId(int) 19522 * @see #findViewById(int) 19523 * @attr ref android.R.styleable#View_id 19524 */ 19525 @IdRes 19526 @ViewDebug.CapturedViewProperty getId()19527 public int getId() { 19528 return mID; 19529 } 19530 19531 /** 19532 * Returns this view's tag. 19533 * 19534 * @return the Object stored in this view as a tag, or {@code null} if not 19535 * set 19536 * 19537 * @see #setTag(Object) 19538 * @see #getTag(int) 19539 */ 19540 @ViewDebug.ExportedProperty getTag()19541 public Object getTag() { 19542 return mTag; 19543 } 19544 19545 /** 19546 * Sets the tag associated with this view. A tag can be used to mark 19547 * a view in its hierarchy and does not have to be unique within the 19548 * hierarchy. Tags can also be used to store data within a view without 19549 * resorting to another data structure. 19550 * 19551 * @param tag an Object to tag the view with 19552 * 19553 * @see #getTag() 19554 * @see #setTag(int, Object) 19555 */ setTag(final Object tag)19556 public void setTag(final Object tag) { 19557 mTag = tag; 19558 } 19559 19560 /** 19561 * Returns the tag associated with this view and the specified key. 19562 * 19563 * @param key The key identifying the tag 19564 * 19565 * @return the Object stored in this view as a tag, or {@code null} if not 19566 * set 19567 * 19568 * @see #setTag(int, Object) 19569 * @see #getTag() 19570 */ getTag(int key)19571 public Object getTag(int key) { 19572 if (mKeyedTags != null) return mKeyedTags.get(key); 19573 return null; 19574 } 19575 19576 /** 19577 * Sets a tag associated with this view and a key. A tag can be used 19578 * to mark a view in its hierarchy and does not have to be unique within 19579 * the hierarchy. Tags can also be used to store data within a view 19580 * without resorting to another data structure. 19581 * 19582 * The specified key should be an id declared in the resources of the 19583 * application to ensure it is unique (see the <a 19584 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 19585 * Keys identified as belonging to 19586 * the Android framework or not associated with any package will cause 19587 * an {@link IllegalArgumentException} to be thrown. 19588 * 19589 * @param key The key identifying the tag 19590 * @param tag An Object to tag the view with 19591 * 19592 * @throws IllegalArgumentException If they specified key is not valid 19593 * 19594 * @see #setTag(Object) 19595 * @see #getTag(int) 19596 */ setTag(int key, final Object tag)19597 public void setTag(int key, final Object tag) { 19598 // If the package id is 0x00 or 0x01, it's either an undefined package 19599 // or a framework id 19600 if ((key >>> 24) < 2) { 19601 throw new IllegalArgumentException("The key must be an application-specific " 19602 + "resource id."); 19603 } 19604 19605 setKeyedTag(key, tag); 19606 } 19607 19608 /** 19609 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 19610 * framework id. 19611 * 19612 * @hide 19613 */ setTagInternal(int key, Object tag)19614 public void setTagInternal(int key, Object tag) { 19615 if ((key >>> 24) != 0x1) { 19616 throw new IllegalArgumentException("The key must be a framework-specific " 19617 + "resource id."); 19618 } 19619 19620 setKeyedTag(key, tag); 19621 } 19622 setKeyedTag(int key, Object tag)19623 private void setKeyedTag(int key, Object tag) { 19624 if (mKeyedTags == null) { 19625 mKeyedTags = new SparseArray<Object>(2); 19626 } 19627 19628 mKeyedTags.put(key, tag); 19629 } 19630 19631 /** 19632 * Prints information about this view in the log output, with the tag 19633 * {@link #VIEW_LOG_TAG}. 19634 * 19635 * @hide 19636 */ debug()19637 public void debug() { 19638 debug(0); 19639 } 19640 19641 /** 19642 * Prints information about this view in the log output, with the tag 19643 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 19644 * indentation defined by the <code>depth</code>. 19645 * 19646 * @param depth the indentation level 19647 * 19648 * @hide 19649 */ debug(int depth)19650 protected void debug(int depth) { 19651 String output = debugIndent(depth - 1); 19652 19653 output += "+ " + this; 19654 int id = getId(); 19655 if (id != -1) { 19656 output += " (id=" + id + ")"; 19657 } 19658 Object tag = getTag(); 19659 if (tag != null) { 19660 output += " (tag=" + tag + ")"; 19661 } 19662 Log.d(VIEW_LOG_TAG, output); 19663 19664 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 19665 output = debugIndent(depth) + " FOCUSED"; 19666 Log.d(VIEW_LOG_TAG, output); 19667 } 19668 19669 output = debugIndent(depth); 19670 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 19671 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 19672 + "} "; 19673 Log.d(VIEW_LOG_TAG, output); 19674 19675 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 19676 || mPaddingBottom != 0) { 19677 output = debugIndent(depth); 19678 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 19679 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 19680 Log.d(VIEW_LOG_TAG, output); 19681 } 19682 19683 output = debugIndent(depth); 19684 output += "mMeasureWidth=" + mMeasuredWidth + 19685 " mMeasureHeight=" + mMeasuredHeight; 19686 Log.d(VIEW_LOG_TAG, output); 19687 19688 output = debugIndent(depth); 19689 if (mLayoutParams == null) { 19690 output += "BAD! no layout params"; 19691 } else { 19692 output = mLayoutParams.debug(output); 19693 } 19694 Log.d(VIEW_LOG_TAG, output); 19695 19696 output = debugIndent(depth); 19697 output += "flags={"; 19698 output += View.printFlags(mViewFlags); 19699 output += "}"; 19700 Log.d(VIEW_LOG_TAG, output); 19701 19702 output = debugIndent(depth); 19703 output += "privateFlags={"; 19704 output += View.printPrivateFlags(mPrivateFlags); 19705 output += "}"; 19706 Log.d(VIEW_LOG_TAG, output); 19707 } 19708 19709 /** 19710 * Creates a string of whitespaces used for indentation. 19711 * 19712 * @param depth the indentation level 19713 * @return a String containing (depth * 2 + 3) * 2 white spaces 19714 * 19715 * @hide 19716 */ debugIndent(int depth)19717 protected static String debugIndent(int depth) { 19718 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 19719 for (int i = 0; i < (depth * 2) + 3; i++) { 19720 spaces.append(' ').append(' '); 19721 } 19722 return spaces.toString(); 19723 } 19724 19725 /** 19726 * <p>Return the offset of the widget's text baseline from the widget's top 19727 * boundary. If this widget does not support baseline alignment, this 19728 * method returns -1. </p> 19729 * 19730 * @return the offset of the baseline within the widget's bounds or -1 19731 * if baseline alignment is not supported 19732 */ 19733 @ViewDebug.ExportedProperty(category = "layout") getBaseline()19734 public int getBaseline() { 19735 return -1; 19736 } 19737 19738 /** 19739 * Returns whether the view hierarchy is currently undergoing a layout pass. This 19740 * information is useful to avoid situations such as calling {@link #requestLayout()} during 19741 * a layout pass. 19742 * 19743 * @return whether the view hierarchy is currently undergoing a layout pass 19744 */ isInLayout()19745 public boolean isInLayout() { 19746 ViewRootImpl viewRoot = getViewRootImpl(); 19747 return (viewRoot != null && viewRoot.isInLayout()); 19748 } 19749 19750 /** 19751 * Call this when something has changed which has invalidated the 19752 * layout of this view. This will schedule a layout pass of the view 19753 * tree. This should not be called while the view hierarchy is currently in a layout 19754 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 19755 * end of the current layout pass (and then layout will run again) or after the current 19756 * frame is drawn and the next layout occurs. 19757 * 19758 * <p>Subclasses which override this method should call the superclass method to 19759 * handle possible request-during-layout errors correctly.</p> 19760 */ 19761 @CallSuper requestLayout()19762 public void requestLayout() { 19763 if (mMeasureCache != null) mMeasureCache.clear(); 19764 19765 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 19766 // Only trigger request-during-layout logic if this is the view requesting it, 19767 // not the views in its parent hierarchy 19768 ViewRootImpl viewRoot = getViewRootImpl(); 19769 if (viewRoot != null && viewRoot.isInLayout()) { 19770 if (!viewRoot.requestLayoutDuringLayout(this)) { 19771 return; 19772 } 19773 } 19774 mAttachInfo.mViewRequestingLayout = this; 19775 } 19776 19777 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 19778 mPrivateFlags |= PFLAG_INVALIDATED; 19779 19780 if (mParent != null && !mParent.isLayoutRequested()) { 19781 mParent.requestLayout(); 19782 } 19783 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 19784 mAttachInfo.mViewRequestingLayout = null; 19785 } 19786 } 19787 19788 /** 19789 * Forces this view to be laid out during the next layout pass. 19790 * This method does not call requestLayout() or forceLayout() 19791 * on the parent. 19792 */ forceLayout()19793 public void forceLayout() { 19794 if (mMeasureCache != null) mMeasureCache.clear(); 19795 19796 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 19797 mPrivateFlags |= PFLAG_INVALIDATED; 19798 } 19799 19800 /** 19801 * <p> 19802 * This is called to find out how big a view should be. The parent 19803 * supplies constraint information in the width and height parameters. 19804 * </p> 19805 * 19806 * <p> 19807 * The actual measurement work of a view is performed in 19808 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 19809 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 19810 * </p> 19811 * 19812 * 19813 * @param widthMeasureSpec Horizontal space requirements as imposed by the 19814 * parent 19815 * @param heightMeasureSpec Vertical space requirements as imposed by the 19816 * parent 19817 * 19818 * @see #onMeasure(int, int) 19819 */ measure(int widthMeasureSpec, int heightMeasureSpec)19820 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 19821 boolean optical = isLayoutModeOptical(this); 19822 if (optical != isLayoutModeOptical(mParent)) { 19823 Insets insets = getOpticalInsets(); 19824 int oWidth = insets.left + insets.right; 19825 int oHeight = insets.top + insets.bottom; 19826 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 19827 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 19828 } 19829 19830 // Suppress sign extension for the low bytes 19831 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 19832 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 19833 19834 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 19835 19836 // Optimize layout by avoiding an extra EXACTLY pass when the view is 19837 // already measured as the correct size. In API 23 and below, this 19838 // extra pass is required to make LinearLayout re-distribute weight. 19839 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 19840 || heightMeasureSpec != mOldHeightMeasureSpec; 19841 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 19842 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 19843 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 19844 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 19845 final boolean needsLayout = specChanged 19846 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 19847 19848 if (forceLayout || needsLayout) { 19849 // first clears the measured dimension flag 19850 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 19851 19852 resolveRtlPropertiesIfNeeded(); 19853 19854 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 19855 if (cacheIndex < 0 || sIgnoreMeasureCache) { 19856 // measure ourselves, this should set the measured dimension flag back 19857 onMeasure(widthMeasureSpec, heightMeasureSpec); 19858 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19859 } else { 19860 long value = mMeasureCache.valueAt(cacheIndex); 19861 // Casting a long to int drops the high 32 bits, no mask needed 19862 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 19863 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 19864 } 19865 19866 // flag not set, setMeasuredDimension() was not invoked, we raise 19867 // an exception to warn the developer 19868 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 19869 throw new IllegalStateException("View with id " + getId() + ": " 19870 + getClass().getName() + "#onMeasure() did not set the" 19871 + " measured dimension by calling" 19872 + " setMeasuredDimension()"); 19873 } 19874 19875 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 19876 } 19877 19878 mOldWidthMeasureSpec = widthMeasureSpec; 19879 mOldHeightMeasureSpec = heightMeasureSpec; 19880 19881 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 19882 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 19883 } 19884 19885 /** 19886 * <p> 19887 * Measure the view and its content to determine the measured width and the 19888 * measured height. This method is invoked by {@link #measure(int, int)} and 19889 * should be overridden by subclasses to provide accurate and efficient 19890 * measurement of their contents. 19891 * </p> 19892 * 19893 * <p> 19894 * <strong>CONTRACT:</strong> When overriding this method, you 19895 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 19896 * measured width and height of this view. Failure to do so will trigger an 19897 * <code>IllegalStateException</code>, thrown by 19898 * {@link #measure(int, int)}. Calling the superclass' 19899 * {@link #onMeasure(int, int)} is a valid use. 19900 * </p> 19901 * 19902 * <p> 19903 * The base class implementation of measure defaults to the background size, 19904 * unless a larger size is allowed by the MeasureSpec. Subclasses should 19905 * override {@link #onMeasure(int, int)} to provide better measurements of 19906 * their content. 19907 * </p> 19908 * 19909 * <p> 19910 * If this method is overridden, it is the subclass's responsibility to make 19911 * sure the measured height and width are at least the view's minimum height 19912 * and width ({@link #getSuggestedMinimumHeight()} and 19913 * {@link #getSuggestedMinimumWidth()}). 19914 * </p> 19915 * 19916 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 19917 * The requirements are encoded with 19918 * {@link android.view.View.MeasureSpec}. 19919 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 19920 * The requirements are encoded with 19921 * {@link android.view.View.MeasureSpec}. 19922 * 19923 * @see #getMeasuredWidth() 19924 * @see #getMeasuredHeight() 19925 * @see #setMeasuredDimension(int, int) 19926 * @see #getSuggestedMinimumHeight() 19927 * @see #getSuggestedMinimumWidth() 19928 * @see android.view.View.MeasureSpec#getMode(int) 19929 * @see android.view.View.MeasureSpec#getSize(int) 19930 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)19931 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 19932 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 19933 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 19934 } 19935 19936 /** 19937 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 19938 * measured width and measured height. Failing to do so will trigger an 19939 * exception at measurement time.</p> 19940 * 19941 * @param measuredWidth The measured width of this view. May be a complex 19942 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 19943 * {@link #MEASURED_STATE_TOO_SMALL}. 19944 * @param measuredHeight The measured height of this view. May be a complex 19945 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 19946 * {@link #MEASURED_STATE_TOO_SMALL}. 19947 */ setMeasuredDimension(int measuredWidth, int measuredHeight)19948 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 19949 boolean optical = isLayoutModeOptical(this); 19950 if (optical != isLayoutModeOptical(mParent)) { 19951 Insets insets = getOpticalInsets(); 19952 int opticalWidth = insets.left + insets.right; 19953 int opticalHeight = insets.top + insets.bottom; 19954 19955 measuredWidth += optical ? opticalWidth : -opticalWidth; 19956 measuredHeight += optical ? opticalHeight : -opticalHeight; 19957 } 19958 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 19959 } 19960 19961 /** 19962 * Sets the measured dimension without extra processing for things like optical bounds. 19963 * Useful for reapplying consistent values that have already been cooked with adjustments 19964 * for optical bounds, etc. such as those from the measurement cache. 19965 * 19966 * @param measuredWidth The measured width of this view. May be a complex 19967 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 19968 * {@link #MEASURED_STATE_TOO_SMALL}. 19969 * @param measuredHeight The measured height of this view. May be a complex 19970 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 19971 * {@link #MEASURED_STATE_TOO_SMALL}. 19972 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)19973 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 19974 mMeasuredWidth = measuredWidth; 19975 mMeasuredHeight = measuredHeight; 19976 19977 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 19978 } 19979 19980 /** 19981 * Merge two states as returned by {@link #getMeasuredState()}. 19982 * @param curState The current state as returned from a view or the result 19983 * of combining multiple views. 19984 * @param newState The new view state to combine. 19985 * @return Returns a new integer reflecting the combination of the two 19986 * states. 19987 */ combineMeasuredStates(int curState, int newState)19988 public static int combineMeasuredStates(int curState, int newState) { 19989 return curState | newState; 19990 } 19991 19992 /** 19993 * Version of {@link #resolveSizeAndState(int, int, int)} 19994 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 19995 */ resolveSize(int size, int measureSpec)19996 public static int resolveSize(int size, int measureSpec) { 19997 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 19998 } 19999 20000 /** 20001 * Utility to reconcile a desired size and state, with constraints imposed 20002 * by a MeasureSpec. Will take the desired size, unless a different size 20003 * is imposed by the constraints. The returned value is a compound integer, 20004 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 20005 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 20006 * resulting size is smaller than the size the view wants to be. 20007 * 20008 * @param size How big the view wants to be. 20009 * @param measureSpec Constraints imposed by the parent. 20010 * @param childMeasuredState Size information bit mask for the view's 20011 * children. 20012 * @return Size information bit mask as defined by 20013 * {@link #MEASURED_SIZE_MASK} and 20014 * {@link #MEASURED_STATE_TOO_SMALL}. 20015 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)20016 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 20017 final int specMode = MeasureSpec.getMode(measureSpec); 20018 final int specSize = MeasureSpec.getSize(measureSpec); 20019 final int result; 20020 switch (specMode) { 20021 case MeasureSpec.AT_MOST: 20022 if (specSize < size) { 20023 result = specSize | MEASURED_STATE_TOO_SMALL; 20024 } else { 20025 result = size; 20026 } 20027 break; 20028 case MeasureSpec.EXACTLY: 20029 result = specSize; 20030 break; 20031 case MeasureSpec.UNSPECIFIED: 20032 default: 20033 result = size; 20034 } 20035 return result | (childMeasuredState & MEASURED_STATE_MASK); 20036 } 20037 20038 /** 20039 * Utility to return a default size. Uses the supplied size if the 20040 * MeasureSpec imposed no constraints. Will get larger if allowed 20041 * by the MeasureSpec. 20042 * 20043 * @param size Default size for this view 20044 * @param measureSpec Constraints imposed by the parent 20045 * @return The size this view should be. 20046 */ getDefaultSize(int size, int measureSpec)20047 public static int getDefaultSize(int size, int measureSpec) { 20048 int result = size; 20049 int specMode = MeasureSpec.getMode(measureSpec); 20050 int specSize = MeasureSpec.getSize(measureSpec); 20051 20052 switch (specMode) { 20053 case MeasureSpec.UNSPECIFIED: 20054 result = size; 20055 break; 20056 case MeasureSpec.AT_MOST: 20057 case MeasureSpec.EXACTLY: 20058 result = specSize; 20059 break; 20060 } 20061 return result; 20062 } 20063 20064 /** 20065 * Returns the suggested minimum height that the view should use. This 20066 * returns the maximum of the view's minimum height 20067 * and the background's minimum height 20068 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 20069 * <p> 20070 * When being used in {@link #onMeasure(int, int)}, the caller should still 20071 * ensure the returned height is within the requirements of the parent. 20072 * 20073 * @return The suggested minimum height of the view. 20074 */ getSuggestedMinimumHeight()20075 protected int getSuggestedMinimumHeight() { 20076 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 20077 20078 } 20079 20080 /** 20081 * Returns the suggested minimum width that the view should use. This 20082 * returns the maximum of the view's minimum width 20083 * and the background's minimum width 20084 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 20085 * <p> 20086 * When being used in {@link #onMeasure(int, int)}, the caller should still 20087 * ensure the returned width is within the requirements of the parent. 20088 * 20089 * @return The suggested minimum width of the view. 20090 */ getSuggestedMinimumWidth()20091 protected int getSuggestedMinimumWidth() { 20092 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 20093 } 20094 20095 /** 20096 * Returns the minimum height of the view. 20097 * 20098 * @return the minimum height the view will try to be. 20099 * 20100 * @see #setMinimumHeight(int) 20101 * 20102 * @attr ref android.R.styleable#View_minHeight 20103 */ getMinimumHeight()20104 public int getMinimumHeight() { 20105 return mMinHeight; 20106 } 20107 20108 /** 20109 * Sets the minimum height of the view. It is not guaranteed the view will 20110 * be able to achieve this minimum height (for example, if its parent layout 20111 * constrains it with less available height). 20112 * 20113 * @param minHeight The minimum height the view will try to be. 20114 * 20115 * @see #getMinimumHeight() 20116 * 20117 * @attr ref android.R.styleable#View_minHeight 20118 */ 20119 @RemotableViewMethod setMinimumHeight(int minHeight)20120 public void setMinimumHeight(int minHeight) { 20121 mMinHeight = minHeight; 20122 requestLayout(); 20123 } 20124 20125 /** 20126 * Returns the minimum width of the view. 20127 * 20128 * @return the minimum width the view will try to be. 20129 * 20130 * @see #setMinimumWidth(int) 20131 * 20132 * @attr ref android.R.styleable#View_minWidth 20133 */ getMinimumWidth()20134 public int getMinimumWidth() { 20135 return mMinWidth; 20136 } 20137 20138 /** 20139 * Sets the minimum width of the view. It is not guaranteed the view will 20140 * be able to achieve this minimum width (for example, if its parent layout 20141 * constrains it with less available width). 20142 * 20143 * @param minWidth The minimum width the view will try to be. 20144 * 20145 * @see #getMinimumWidth() 20146 * 20147 * @attr ref android.R.styleable#View_minWidth 20148 */ setMinimumWidth(int minWidth)20149 public void setMinimumWidth(int minWidth) { 20150 mMinWidth = minWidth; 20151 requestLayout(); 20152 20153 } 20154 20155 /** 20156 * Get the animation currently associated with this view. 20157 * 20158 * @return The animation that is currently playing or 20159 * scheduled to play for this view. 20160 */ getAnimation()20161 public Animation getAnimation() { 20162 return mCurrentAnimation; 20163 } 20164 20165 /** 20166 * Start the specified animation now. 20167 * 20168 * @param animation the animation to start now 20169 */ startAnimation(Animation animation)20170 public void startAnimation(Animation animation) { 20171 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 20172 setAnimation(animation); 20173 invalidateParentCaches(); 20174 invalidate(true); 20175 } 20176 20177 /** 20178 * Cancels any animations for this view. 20179 */ clearAnimation()20180 public void clearAnimation() { 20181 if (mCurrentAnimation != null) { 20182 mCurrentAnimation.detach(); 20183 } 20184 mCurrentAnimation = null; 20185 invalidateParentIfNeeded(); 20186 } 20187 20188 /** 20189 * Sets the next animation to play for this view. 20190 * If you want the animation to play immediately, use 20191 * {@link #startAnimation(android.view.animation.Animation)} instead. 20192 * This method provides allows fine-grained 20193 * control over the start time and invalidation, but you 20194 * must make sure that 1) the animation has a start time set, and 20195 * 2) the view's parent (which controls animations on its children) 20196 * will be invalidated when the animation is supposed to 20197 * start. 20198 * 20199 * @param animation The next animation, or null. 20200 */ setAnimation(Animation animation)20201 public void setAnimation(Animation animation) { 20202 mCurrentAnimation = animation; 20203 20204 if (animation != null) { 20205 // If the screen is off assume the animation start time is now instead of 20206 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 20207 // would cause the animation to start when the screen turns back on 20208 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 20209 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 20210 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 20211 } 20212 animation.reset(); 20213 } 20214 } 20215 20216 /** 20217 * Invoked by a parent ViewGroup to notify the start of the animation 20218 * currently associated with this view. If you override this method, 20219 * always call super.onAnimationStart(); 20220 * 20221 * @see #setAnimation(android.view.animation.Animation) 20222 * @see #getAnimation() 20223 */ 20224 @CallSuper onAnimationStart()20225 protected void onAnimationStart() { 20226 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 20227 } 20228 20229 /** 20230 * Invoked by a parent ViewGroup to notify the end of the animation 20231 * currently associated with this view. If you override this method, 20232 * always call super.onAnimationEnd(); 20233 * 20234 * @see #setAnimation(android.view.animation.Animation) 20235 * @see #getAnimation() 20236 */ 20237 @CallSuper onAnimationEnd()20238 protected void onAnimationEnd() { 20239 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 20240 } 20241 20242 /** 20243 * Invoked if there is a Transform that involves alpha. Subclass that can 20244 * draw themselves with the specified alpha should return true, and then 20245 * respect that alpha when their onDraw() is called. If this returns false 20246 * then the view may be redirected to draw into an offscreen buffer to 20247 * fulfill the request, which will look fine, but may be slower than if the 20248 * subclass handles it internally. The default implementation returns false. 20249 * 20250 * @param alpha The alpha (0..255) to apply to the view's drawing 20251 * @return true if the view can draw with the specified alpha. 20252 */ onSetAlpha(int alpha)20253 protected boolean onSetAlpha(int alpha) { 20254 return false; 20255 } 20256 20257 /** 20258 * This is used by the RootView to perform an optimization when 20259 * the view hierarchy contains one or several SurfaceView. 20260 * SurfaceView is always considered transparent, but its children are not, 20261 * therefore all View objects remove themselves from the global transparent 20262 * region (passed as a parameter to this function). 20263 * 20264 * @param region The transparent region for this ViewAncestor (window). 20265 * 20266 * @return Returns true if the effective visibility of the view at this 20267 * point is opaque, regardless of the transparent region; returns false 20268 * if it is possible for underlying windows to be seen behind the view. 20269 * 20270 * {@hide} 20271 */ gatherTransparentRegion(Region region)20272 public boolean gatherTransparentRegion(Region region) { 20273 final AttachInfo attachInfo = mAttachInfo; 20274 if (region != null && attachInfo != null) { 20275 final int pflags = mPrivateFlags; 20276 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 20277 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 20278 // remove it from the transparent region. 20279 final int[] location = attachInfo.mTransparentLocation; 20280 getLocationInWindow(location); 20281 // When a view has Z value, then it will be better to leave some area below the view 20282 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 20283 // the bottom part needs more offset than the left, top and right parts due to the 20284 // spot light effects. 20285 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 20286 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 20287 location[0] + mRight - mLeft + shadowOffset, 20288 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 20289 } else { 20290 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 20291 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 20292 // the background drawable's non-transparent parts from this transparent region. 20293 applyDrawableToTransparentRegion(mBackground, region); 20294 } 20295 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 20296 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 20297 // Similarly, we remove the foreground drawable's non-transparent parts. 20298 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 20299 } 20300 } 20301 } 20302 return true; 20303 } 20304 20305 /** 20306 * Play a sound effect for this view. 20307 * 20308 * <p>The framework will play sound effects for some built in actions, such as 20309 * clicking, but you may wish to play these effects in your widget, 20310 * for instance, for internal navigation. 20311 * 20312 * <p>The sound effect will only be played if sound effects are enabled by the user, and 20313 * {@link #isSoundEffectsEnabled()} is true. 20314 * 20315 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 20316 */ playSoundEffect(int soundConstant)20317 public void playSoundEffect(int soundConstant) { 20318 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 20319 return; 20320 } 20321 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 20322 } 20323 20324 /** 20325 * BZZZTT!!1! 20326 * 20327 * <p>Provide haptic feedback to the user for this view. 20328 * 20329 * <p>The framework will provide haptic feedback for some built in actions, 20330 * such as long presses, but you may wish to provide feedback for your 20331 * own widget. 20332 * 20333 * <p>The feedback will only be performed if 20334 * {@link #isHapticFeedbackEnabled()} is true. 20335 * 20336 * @param feedbackConstant One of the constants defined in 20337 * {@link HapticFeedbackConstants} 20338 */ performHapticFeedback(int feedbackConstant)20339 public boolean performHapticFeedback(int feedbackConstant) { 20340 return performHapticFeedback(feedbackConstant, 0); 20341 } 20342 20343 /** 20344 * BZZZTT!!1! 20345 * 20346 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 20347 * 20348 * @param feedbackConstant One of the constants defined in 20349 * {@link HapticFeedbackConstants} 20350 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 20351 */ performHapticFeedback(int feedbackConstant, int flags)20352 public boolean performHapticFeedback(int feedbackConstant, int flags) { 20353 if (mAttachInfo == null) { 20354 return false; 20355 } 20356 //noinspection SimplifiableIfStatement 20357 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 20358 && !isHapticFeedbackEnabled()) { 20359 return false; 20360 } 20361 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 20362 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 20363 } 20364 20365 /** 20366 * Request that the visibility of the status bar or other screen/window 20367 * decorations be changed. 20368 * 20369 * <p>This method is used to put the over device UI into temporary modes 20370 * where the user's attention is focused more on the application content, 20371 * by dimming or hiding surrounding system affordances. This is typically 20372 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 20373 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 20374 * to be placed behind the action bar (and with these flags other system 20375 * affordances) so that smooth transitions between hiding and showing them 20376 * can be done. 20377 * 20378 * <p>Two representative examples of the use of system UI visibility is 20379 * implementing a content browsing application (like a magazine reader) 20380 * and a video playing application. 20381 * 20382 * <p>The first code shows a typical implementation of a View in a content 20383 * browsing application. In this implementation, the application goes 20384 * into a content-oriented mode by hiding the status bar and action bar, 20385 * and putting the navigation elements into lights out mode. The user can 20386 * then interact with content while in this mode. Such an application should 20387 * provide an easy way for the user to toggle out of the mode (such as to 20388 * check information in the status bar or access notifications). In the 20389 * implementation here, this is done simply by tapping on the content. 20390 * 20391 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 20392 * content} 20393 * 20394 * <p>This second code sample shows a typical implementation of a View 20395 * in a video playing application. In this situation, while the video is 20396 * playing the application would like to go into a complete full-screen mode, 20397 * to use as much of the display as possible for the video. When in this state 20398 * the user can not interact with the application; the system intercepts 20399 * touching on the screen to pop the UI out of full screen mode. See 20400 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 20401 * 20402 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 20403 * content} 20404 * 20405 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 20406 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 20407 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 20408 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 20409 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 20410 */ setSystemUiVisibility(int visibility)20411 public void setSystemUiVisibility(int visibility) { 20412 if (visibility != mSystemUiVisibility) { 20413 mSystemUiVisibility = visibility; 20414 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 20415 mParent.recomputeViewAttributes(this); 20416 } 20417 } 20418 } 20419 20420 /** 20421 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 20422 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 20423 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 20424 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 20425 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 20426 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 20427 */ getSystemUiVisibility()20428 public int getSystemUiVisibility() { 20429 return mSystemUiVisibility; 20430 } 20431 20432 /** 20433 * Returns the current system UI visibility that is currently set for 20434 * the entire window. This is the combination of the 20435 * {@link #setSystemUiVisibility(int)} values supplied by all of the 20436 * views in the window. 20437 */ getWindowSystemUiVisibility()20438 public int getWindowSystemUiVisibility() { 20439 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 20440 } 20441 20442 /** 20443 * Override to find out when the window's requested system UI visibility 20444 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 20445 * This is different from the callbacks received through 20446 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 20447 * in that this is only telling you about the local request of the window, 20448 * not the actual values applied by the system. 20449 */ onWindowSystemUiVisibilityChanged(int visible)20450 public void onWindowSystemUiVisibilityChanged(int visible) { 20451 } 20452 20453 /** 20454 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 20455 * the view hierarchy. 20456 */ dispatchWindowSystemUiVisiblityChanged(int visible)20457 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 20458 onWindowSystemUiVisibilityChanged(visible); 20459 } 20460 20461 /** 20462 * Set a listener to receive callbacks when the visibility of the system bar changes. 20463 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 20464 */ setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)20465 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 20466 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 20467 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 20468 mParent.recomputeViewAttributes(this); 20469 } 20470 } 20471 20472 /** 20473 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 20474 * the view hierarchy. 20475 */ dispatchSystemUiVisibilityChanged(int visibility)20476 public void dispatchSystemUiVisibilityChanged(int visibility) { 20477 ListenerInfo li = mListenerInfo; 20478 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 20479 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 20480 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 20481 } 20482 } 20483 updateLocalSystemUiVisibility(int localValue, int localChanges)20484 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 20485 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 20486 if (val != mSystemUiVisibility) { 20487 setSystemUiVisibility(val); 20488 return true; 20489 } 20490 return false; 20491 } 20492 20493 /** @hide */ setDisabledSystemUiVisibility(int flags)20494 public void setDisabledSystemUiVisibility(int flags) { 20495 if (mAttachInfo != null) { 20496 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 20497 mAttachInfo.mDisabledSystemUiVisibility = flags; 20498 if (mParent != null) { 20499 mParent.recomputeViewAttributes(this); 20500 } 20501 } 20502 } 20503 } 20504 20505 /** 20506 * Creates an image that the system displays during the drag and drop 20507 * operation. This is called a "drag shadow". The default implementation 20508 * for a DragShadowBuilder based on a View returns an image that has exactly the same 20509 * appearance as the given View. The default also positions the center of the drag shadow 20510 * directly under the touch point. If no View is provided (the constructor with no parameters 20511 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 20512 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 20513 * default is an invisible drag shadow. 20514 * <p> 20515 * You are not required to use the View you provide to the constructor as the basis of the 20516 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 20517 * anything you want as the drag shadow. 20518 * </p> 20519 * <p> 20520 * You pass a DragShadowBuilder object to the system when you start the drag. The system 20521 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 20522 * size and position of the drag shadow. It uses this data to construct a 20523 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 20524 * so that your application can draw the shadow image in the Canvas. 20525 * </p> 20526 * 20527 * <div class="special reference"> 20528 * <h3>Developer Guides</h3> 20529 * <p>For a guide to implementing drag and drop features, read the 20530 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 20531 * </div> 20532 */ 20533 public static class DragShadowBuilder { 20534 private final WeakReference<View> mView; 20535 20536 /** 20537 * Constructs a shadow image builder based on a View. By default, the resulting drag 20538 * shadow will have the same appearance and dimensions as the View, with the touch point 20539 * over the center of the View. 20540 * @param view A View. Any View in scope can be used. 20541 */ DragShadowBuilder(View view)20542 public DragShadowBuilder(View view) { 20543 mView = new WeakReference<View>(view); 20544 } 20545 20546 /** 20547 * Construct a shadow builder object with no associated View. This 20548 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 20549 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 20550 * to supply the drag shadow's dimensions and appearance without 20551 * reference to any View object. If they are not overridden, then the result is an 20552 * invisible drag shadow. 20553 */ DragShadowBuilder()20554 public DragShadowBuilder() { 20555 mView = new WeakReference<View>(null); 20556 } 20557 20558 /** 20559 * Returns the View object that had been passed to the 20560 * {@link #View.DragShadowBuilder(View)} 20561 * constructor. If that View parameter was {@code null} or if the 20562 * {@link #View.DragShadowBuilder()} 20563 * constructor was used to instantiate the builder object, this method will return 20564 * null. 20565 * 20566 * @return The View object associate with this builder object. 20567 */ 20568 @SuppressWarnings({"JavadocReference"}) getView()20569 final public View getView() { 20570 return mView.get(); 20571 } 20572 20573 /** 20574 * Provides the metrics for the shadow image. These include the dimensions of 20575 * the shadow image, and the point within that shadow that should 20576 * be centered under the touch location while dragging. 20577 * <p> 20578 * The default implementation sets the dimensions of the shadow to be the 20579 * same as the dimensions of the View itself and centers the shadow under 20580 * the touch point. 20581 * </p> 20582 * 20583 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 20584 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 20585 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 20586 * image. 20587 * 20588 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 20589 * shadow image that should be underneath the touch point during the drag and drop 20590 * operation. Your application must set {@link android.graphics.Point#x} to the 20591 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 20592 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)20593 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 20594 final View view = mView.get(); 20595 if (view != null) { 20596 outShadowSize.set(view.getWidth(), view.getHeight()); 20597 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 20598 } else { 20599 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 20600 } 20601 } 20602 20603 /** 20604 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 20605 * based on the dimensions it received from the 20606 * {@link #onProvideShadowMetrics(Point, Point)} callback. 20607 * 20608 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 20609 */ onDrawShadow(Canvas canvas)20610 public void onDrawShadow(Canvas canvas) { 20611 final View view = mView.get(); 20612 if (view != null) { 20613 view.draw(canvas); 20614 } else { 20615 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 20616 } 20617 } 20618 } 20619 20620 /** 20621 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 20622 * startDragAndDrop()} for newer platform versions. 20623 */ startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)20624 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 20625 Object myLocalState, int flags) { 20626 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 20627 } 20628 20629 /** 20630 * Starts a drag and drop operation. When your application calls this method, it passes a 20631 * {@link android.view.View.DragShadowBuilder} object to the system. The 20632 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 20633 * to get metrics for the drag shadow, and then calls the object's 20634 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 20635 * <p> 20636 * Once the system has the drag shadow, it begins the drag and drop operation by sending 20637 * drag events to all the View objects in your application that are currently visible. It does 20638 * this either by calling the View object's drag listener (an implementation of 20639 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 20640 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 20641 * Both are passed a {@link android.view.DragEvent} object that has a 20642 * {@link android.view.DragEvent#getAction()} value of 20643 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 20644 * </p> 20645 * <p> 20646 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 20647 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 20648 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 20649 * to the View the user selected for dragging. 20650 * </p> 20651 * @param data A {@link android.content.ClipData} object pointing to the data to be 20652 * transferred by the drag and drop operation. 20653 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 20654 * drag shadow. 20655 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 20656 * drop operation. When dispatching drag events to views in the same activity this object 20657 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 20658 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 20659 * will return null). 20660 * <p> 20661 * myLocalState is a lightweight mechanism for the sending information from the dragged View 20662 * to the target Views. For example, it can contain flags that differentiate between a 20663 * a copy operation and a move operation. 20664 * </p> 20665 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 20666 * flags, or any combination of the following: 20667 * <ul> 20668 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 20669 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 20670 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 20671 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 20672 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 20673 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 20674 * </ul> 20675 * @return {@code true} if the method completes successfully, or 20676 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 20677 * do a drag, and so no drag operation is in progress. 20678 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)20679 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 20680 Object myLocalState, int flags) { 20681 if (ViewDebug.DEBUG_DRAG) { 20682 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 20683 } 20684 if (mAttachInfo == null) { 20685 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 20686 return false; 20687 } 20688 boolean okay = false; 20689 20690 Point shadowSize = new Point(); 20691 Point shadowTouchPoint = new Point(); 20692 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 20693 20694 if ((shadowSize.x < 0) || (shadowSize.y < 0) || 20695 (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 20696 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 20697 } 20698 20699 if (ViewDebug.DEBUG_DRAG) { 20700 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 20701 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 20702 } 20703 if (mAttachInfo.mDragSurface != null) { 20704 mAttachInfo.mDragSurface.release(); 20705 } 20706 mAttachInfo.mDragSurface = new Surface(); 20707 try { 20708 mAttachInfo.mDragToken = mAttachInfo.mSession.prepareDrag(mAttachInfo.mWindow, 20709 flags, shadowSize.x, shadowSize.y, mAttachInfo.mDragSurface); 20710 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "prepareDrag returned token=" 20711 + mAttachInfo.mDragToken + " surface=" + mAttachInfo.mDragSurface); 20712 if (mAttachInfo.mDragToken != null) { 20713 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 20714 try { 20715 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 20716 shadowBuilder.onDrawShadow(canvas); 20717 } finally { 20718 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 20719 } 20720 20721 final ViewRootImpl root = getViewRootImpl(); 20722 20723 // Cache the local state object for delivery with DragEvents 20724 root.setLocalDragState(myLocalState); 20725 20726 // repurpose 'shadowSize' for the last touch point 20727 root.getLastTouchPoint(shadowSize); 20728 20729 okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, mAttachInfo.mDragToken, 20730 root.getLastTouchSource(), shadowSize.x, shadowSize.y, 20731 shadowTouchPoint.x, shadowTouchPoint.y, data); 20732 if (ViewDebug.DEBUG_DRAG) Log.d(VIEW_LOG_TAG, "performDrag returned " + okay); 20733 } 20734 } catch (Exception e) { 20735 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 20736 mAttachInfo.mDragSurface.destroy(); 20737 mAttachInfo.mDragSurface = null; 20738 } 20739 20740 return okay; 20741 } 20742 20743 /** 20744 * Cancels an ongoing drag and drop operation. 20745 * <p> 20746 * A {@link android.view.DragEvent} object with 20747 * {@link android.view.DragEvent#getAction()} value of 20748 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 20749 * {@link android.view.DragEvent#getResult()} value of {@code false} 20750 * will be sent to every 20751 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 20752 * even if they are not currently visible. 20753 * </p> 20754 * <p> 20755 * This method can be called on any View in the same window as the View on which 20756 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 20757 * was called. 20758 * </p> 20759 */ cancelDragAndDrop()20760 public final void cancelDragAndDrop() { 20761 if (ViewDebug.DEBUG_DRAG) { 20762 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 20763 } 20764 if (mAttachInfo == null) { 20765 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 20766 return; 20767 } 20768 if (mAttachInfo.mDragToken != null) { 20769 try { 20770 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken); 20771 } catch (Exception e) { 20772 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 20773 } 20774 mAttachInfo.mDragToken = null; 20775 } else { 20776 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 20777 } 20778 } 20779 20780 /** 20781 * Updates the drag shadow for the ongoing drag and drop operation. 20782 * 20783 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 20784 * new drag shadow. 20785 */ updateDragShadow(DragShadowBuilder shadowBuilder)20786 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 20787 if (ViewDebug.DEBUG_DRAG) { 20788 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 20789 } 20790 if (mAttachInfo == null) { 20791 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 20792 return; 20793 } 20794 if (mAttachInfo.mDragToken != null) { 20795 try { 20796 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 20797 try { 20798 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 20799 shadowBuilder.onDrawShadow(canvas); 20800 } finally { 20801 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 20802 } 20803 } catch (Exception e) { 20804 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 20805 } 20806 } else { 20807 Log.e(VIEW_LOG_TAG, "No active drag"); 20808 } 20809 } 20810 20811 /** 20812 * Starts a move from {startX, startY}, the amount of the movement will be the offset 20813 * between {startX, startY} and the new cursor positon. 20814 * @param startX horizontal coordinate where the move started. 20815 * @param startY vertical coordinate where the move started. 20816 * @return whether moving was started successfully. 20817 * @hide 20818 */ startMovingTask(float startX, float startY)20819 public final boolean startMovingTask(float startX, float startY) { 20820 if (ViewDebug.DEBUG_POSITIONING) { 20821 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 20822 } 20823 try { 20824 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 20825 } catch (RemoteException e) { 20826 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 20827 } 20828 return false; 20829 } 20830 20831 /** 20832 * Handles drag events sent by the system following a call to 20833 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 20834 * startDragAndDrop()}. 20835 *<p> 20836 * When the system calls this method, it passes a 20837 * {@link android.view.DragEvent} object. A call to 20838 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 20839 * in DragEvent. The method uses these to determine what is happening in the drag and drop 20840 * operation. 20841 * @param event The {@link android.view.DragEvent} sent by the system. 20842 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 20843 * in DragEvent, indicating the type of drag event represented by this object. 20844 * @return {@code true} if the method was successful, otherwise {@code false}. 20845 * <p> 20846 * The method should return {@code true} in response to an action type of 20847 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 20848 * operation. 20849 * </p> 20850 * <p> 20851 * The method should also return {@code true} in response to an action type of 20852 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 20853 * {@code false} if it didn't. 20854 * </p> 20855 */ onDragEvent(DragEvent event)20856 public boolean onDragEvent(DragEvent event) { 20857 return false; 20858 } 20859 20860 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)20861 boolean dispatchDragEnterExitInPreN(DragEvent event) { 20862 return callDragEventHandler(event); 20863 } 20864 20865 /** 20866 * Detects if this View is enabled and has a drag event listener. 20867 * If both are true, then it calls the drag event listener with the 20868 * {@link android.view.DragEvent} it received. If the drag event listener returns 20869 * {@code true}, then dispatchDragEvent() returns {@code true}. 20870 * <p> 20871 * For all other cases, the method calls the 20872 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 20873 * method and returns its result. 20874 * </p> 20875 * <p> 20876 * This ensures that a drag event is always consumed, even if the View does not have a drag 20877 * event listener. However, if the View has a listener and the listener returns true, then 20878 * onDragEvent() is not called. 20879 * </p> 20880 */ dispatchDragEvent(DragEvent event)20881 public boolean dispatchDragEvent(DragEvent event) { 20882 event.mEventHandlerWasCalled = true; 20883 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 20884 event.mAction == DragEvent.ACTION_DROP) { 20885 // About to deliver an event with coordinates to this view. Notify that now this view 20886 // has drag focus. This will send exit/enter events as needed. 20887 getViewRootImpl().setDragFocus(this, event); 20888 } 20889 return callDragEventHandler(event); 20890 } 20891 callDragEventHandler(DragEvent event)20892 final boolean callDragEventHandler(DragEvent event) { 20893 final boolean result; 20894 20895 ListenerInfo li = mListenerInfo; 20896 //noinspection SimplifiableIfStatement 20897 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 20898 && li.mOnDragListener.onDrag(this, event)) { 20899 result = true; 20900 } else { 20901 result = onDragEvent(event); 20902 } 20903 20904 switch (event.mAction) { 20905 case DragEvent.ACTION_DRAG_ENTERED: { 20906 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 20907 refreshDrawableState(); 20908 } break; 20909 case DragEvent.ACTION_DRAG_EXITED: { 20910 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 20911 refreshDrawableState(); 20912 } break; 20913 case DragEvent.ACTION_DRAG_ENDED: { 20914 mPrivateFlags2 &= ~View.DRAG_MASK; 20915 refreshDrawableState(); 20916 } break; 20917 } 20918 20919 return result; 20920 } 20921 canAcceptDrag()20922 boolean canAcceptDrag() { 20923 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 20924 } 20925 20926 /** 20927 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 20928 * it is ever exposed at all. 20929 * @hide 20930 */ onCloseSystemDialogs(String reason)20931 public void onCloseSystemDialogs(String reason) { 20932 } 20933 20934 /** 20935 * Given a Drawable whose bounds have been set to draw into this view, 20936 * update a Region being computed for 20937 * {@link #gatherTransparentRegion(android.graphics.Region)} so 20938 * that any non-transparent parts of the Drawable are removed from the 20939 * given transparent region. 20940 * 20941 * @param dr The Drawable whose transparency is to be applied to the region. 20942 * @param region A Region holding the current transparency information, 20943 * where any parts of the region that are set are considered to be 20944 * transparent. On return, this region will be modified to have the 20945 * transparency information reduced by the corresponding parts of the 20946 * Drawable that are not transparent. 20947 * {@hide} 20948 */ applyDrawableToTransparentRegion(Drawable dr, Region region)20949 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 20950 if (DBG) { 20951 Log.i("View", "Getting transparent region for: " + this); 20952 } 20953 final Region r = dr.getTransparentRegion(); 20954 final Rect db = dr.getBounds(); 20955 final AttachInfo attachInfo = mAttachInfo; 20956 if (r != null && attachInfo != null) { 20957 final int w = getRight()-getLeft(); 20958 final int h = getBottom()-getTop(); 20959 if (db.left > 0) { 20960 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 20961 r.op(0, 0, db.left, h, Region.Op.UNION); 20962 } 20963 if (db.right < w) { 20964 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 20965 r.op(db.right, 0, w, h, Region.Op.UNION); 20966 } 20967 if (db.top > 0) { 20968 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 20969 r.op(0, 0, w, db.top, Region.Op.UNION); 20970 } 20971 if (db.bottom < h) { 20972 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 20973 r.op(0, db.bottom, w, h, Region.Op.UNION); 20974 } 20975 final int[] location = attachInfo.mTransparentLocation; 20976 getLocationInWindow(location); 20977 r.translate(location[0], location[1]); 20978 region.op(r, Region.Op.INTERSECT); 20979 } else { 20980 region.op(db, Region.Op.DIFFERENCE); 20981 } 20982 } 20983 checkForLongClick(int delayOffset, float x, float y)20984 private void checkForLongClick(int delayOffset, float x, float y) { 20985 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) { 20986 mHasPerformedLongPress = false; 20987 20988 if (mPendingCheckForLongPress == null) { 20989 mPendingCheckForLongPress = new CheckForLongPress(); 20990 } 20991 mPendingCheckForLongPress.setAnchor(x, y); 20992 mPendingCheckForLongPress.rememberWindowAttachCount(); 20993 postDelayed(mPendingCheckForLongPress, 20994 ViewConfiguration.getLongPressTimeout() - delayOffset); 20995 } 20996 } 20997 20998 /** 20999 * Inflate a view from an XML resource. This convenience method wraps the {@link 21000 * LayoutInflater} class, which provides a full range of options for view inflation. 21001 * 21002 * @param context The Context object for your activity or application. 21003 * @param resource The resource ID to inflate 21004 * @param root A view group that will be the parent. Used to properly inflate the 21005 * layout_* parameters. 21006 * @see LayoutInflater 21007 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)21008 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 21009 LayoutInflater factory = LayoutInflater.from(context); 21010 return factory.inflate(resource, root); 21011 } 21012 21013 /** 21014 * Scroll the view with standard behavior for scrolling beyond the normal 21015 * content boundaries. Views that call this method should override 21016 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 21017 * results of an over-scroll operation. 21018 * 21019 * Views can use this method to handle any touch or fling-based scrolling. 21020 * 21021 * @param deltaX Change in X in pixels 21022 * @param deltaY Change in Y in pixels 21023 * @param scrollX Current X scroll value in pixels before applying deltaX 21024 * @param scrollY Current Y scroll value in pixels before applying deltaY 21025 * @param scrollRangeX Maximum content scroll range along the X axis 21026 * @param scrollRangeY Maximum content scroll range along the Y axis 21027 * @param maxOverScrollX Number of pixels to overscroll by in either direction 21028 * along the X axis. 21029 * @param maxOverScrollY Number of pixels to overscroll by in either direction 21030 * along the Y axis. 21031 * @param isTouchEvent true if this scroll operation is the result of a touch event. 21032 * @return true if scrolling was clamped to an over-scroll boundary along either 21033 * axis, false otherwise. 21034 */ 21035 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)21036 protected boolean overScrollBy(int deltaX, int deltaY, 21037 int scrollX, int scrollY, 21038 int scrollRangeX, int scrollRangeY, 21039 int maxOverScrollX, int maxOverScrollY, 21040 boolean isTouchEvent) { 21041 final int overScrollMode = mOverScrollMode; 21042 final boolean canScrollHorizontal = 21043 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 21044 final boolean canScrollVertical = 21045 computeVerticalScrollRange() > computeVerticalScrollExtent(); 21046 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 21047 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 21048 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 21049 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 21050 21051 int newScrollX = scrollX + deltaX; 21052 if (!overScrollHorizontal) { 21053 maxOverScrollX = 0; 21054 } 21055 21056 int newScrollY = scrollY + deltaY; 21057 if (!overScrollVertical) { 21058 maxOverScrollY = 0; 21059 } 21060 21061 // Clamp values if at the limits and record 21062 final int left = -maxOverScrollX; 21063 final int right = maxOverScrollX + scrollRangeX; 21064 final int top = -maxOverScrollY; 21065 final int bottom = maxOverScrollY + scrollRangeY; 21066 21067 boolean clampedX = false; 21068 if (newScrollX > right) { 21069 newScrollX = right; 21070 clampedX = true; 21071 } else if (newScrollX < left) { 21072 newScrollX = left; 21073 clampedX = true; 21074 } 21075 21076 boolean clampedY = false; 21077 if (newScrollY > bottom) { 21078 newScrollY = bottom; 21079 clampedY = true; 21080 } else if (newScrollY < top) { 21081 newScrollY = top; 21082 clampedY = true; 21083 } 21084 21085 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 21086 21087 return clampedX || clampedY; 21088 } 21089 21090 /** 21091 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 21092 * respond to the results of an over-scroll operation. 21093 * 21094 * @param scrollX New X scroll value in pixels 21095 * @param scrollY New Y scroll value in pixels 21096 * @param clampedX True if scrollX was clamped to an over-scroll boundary 21097 * @param clampedY True if scrollY was clamped to an over-scroll boundary 21098 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)21099 protected void onOverScrolled(int scrollX, int scrollY, 21100 boolean clampedX, boolean clampedY) { 21101 // Intentionally empty. 21102 } 21103 21104 /** 21105 * Returns the over-scroll mode for this view. The result will be 21106 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21107 * (allow over-scrolling only if the view content is larger than the container), 21108 * or {@link #OVER_SCROLL_NEVER}. 21109 * 21110 * @return This view's over-scroll mode. 21111 */ getOverScrollMode()21112 public int getOverScrollMode() { 21113 return mOverScrollMode; 21114 } 21115 21116 /** 21117 * Set the over-scroll mode for this view. Valid over-scroll modes are 21118 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 21119 * (allow over-scrolling only if the view content is larger than the container), 21120 * or {@link #OVER_SCROLL_NEVER}. 21121 * 21122 * Setting the over-scroll mode of a view will have an effect only if the 21123 * view is capable of scrolling. 21124 * 21125 * @param overScrollMode The new over-scroll mode for this view. 21126 */ setOverScrollMode(int overScrollMode)21127 public void setOverScrollMode(int overScrollMode) { 21128 if (overScrollMode != OVER_SCROLL_ALWAYS && 21129 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 21130 overScrollMode != OVER_SCROLL_NEVER) { 21131 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 21132 } 21133 mOverScrollMode = overScrollMode; 21134 } 21135 21136 /** 21137 * Enable or disable nested scrolling for this view. 21138 * 21139 * <p>If this property is set to true the view will be permitted to initiate nested 21140 * scrolling operations with a compatible parent view in the current hierarchy. If this 21141 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 21142 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 21143 * the nested scroll.</p> 21144 * 21145 * @param enabled true to enable nested scrolling, false to disable 21146 * 21147 * @see #isNestedScrollingEnabled() 21148 */ setNestedScrollingEnabled(boolean enabled)21149 public void setNestedScrollingEnabled(boolean enabled) { 21150 if (enabled) { 21151 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 21152 } else { 21153 stopNestedScroll(); 21154 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 21155 } 21156 } 21157 21158 /** 21159 * Returns true if nested scrolling is enabled for this view. 21160 * 21161 * <p>If nested scrolling is enabled and this View class implementation supports it, 21162 * this view will act as a nested scrolling child view when applicable, forwarding data 21163 * about the scroll operation in progress to a compatible and cooperating nested scrolling 21164 * parent.</p> 21165 * 21166 * @return true if nested scrolling is enabled 21167 * 21168 * @see #setNestedScrollingEnabled(boolean) 21169 */ isNestedScrollingEnabled()21170 public boolean isNestedScrollingEnabled() { 21171 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 21172 PFLAG3_NESTED_SCROLLING_ENABLED; 21173 } 21174 21175 /** 21176 * Begin a nestable scroll operation along the given axes. 21177 * 21178 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 21179 * 21180 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 21181 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 21182 * In the case of touch scrolling the nested scroll will be terminated automatically in 21183 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 21184 * In the event of programmatic scrolling the caller must explicitly call 21185 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 21186 * 21187 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 21188 * If it returns false the caller may ignore the rest of this contract until the next scroll. 21189 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 21190 * 21191 * <p>At each incremental step of the scroll the caller should invoke 21192 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 21193 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 21194 * parent at least partially consumed the scroll and the caller should adjust the amount it 21195 * scrolls by.</p> 21196 * 21197 * <p>After applying the remainder of the scroll delta the caller should invoke 21198 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 21199 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 21200 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 21201 * </p> 21202 * 21203 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 21204 * {@link #SCROLL_AXIS_VERTICAL}. 21205 * @return true if a cooperative parent was found and nested scrolling has been enabled for 21206 * the current gesture. 21207 * 21208 * @see #stopNestedScroll() 21209 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21210 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21211 */ startNestedScroll(int axes)21212 public boolean startNestedScroll(int axes) { 21213 if (hasNestedScrollingParent()) { 21214 // Already in progress 21215 return true; 21216 } 21217 if (isNestedScrollingEnabled()) { 21218 ViewParent p = getParent(); 21219 View child = this; 21220 while (p != null) { 21221 try { 21222 if (p.onStartNestedScroll(child, this, axes)) { 21223 mNestedScrollingParent = p; 21224 p.onNestedScrollAccepted(child, this, axes); 21225 return true; 21226 } 21227 } catch (AbstractMethodError e) { 21228 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 21229 "method onStartNestedScroll", e); 21230 // Allow the search upward to continue 21231 } 21232 if (p instanceof View) { 21233 child = (View) p; 21234 } 21235 p = p.getParent(); 21236 } 21237 } 21238 return false; 21239 } 21240 21241 /** 21242 * Stop a nested scroll in progress. 21243 * 21244 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 21245 * 21246 * @see #startNestedScroll(int) 21247 */ stopNestedScroll()21248 public void stopNestedScroll() { 21249 if (mNestedScrollingParent != null) { 21250 mNestedScrollingParent.onStopNestedScroll(this); 21251 mNestedScrollingParent = null; 21252 } 21253 } 21254 21255 /** 21256 * Returns true if this view has a nested scrolling parent. 21257 * 21258 * <p>The presence of a nested scrolling parent indicates that this view has initiated 21259 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 21260 * 21261 * @return whether this view has a nested scrolling parent 21262 */ hasNestedScrollingParent()21263 public boolean hasNestedScrollingParent() { 21264 return mNestedScrollingParent != null; 21265 } 21266 21267 /** 21268 * Dispatch one step of a nested scroll in progress. 21269 * 21270 * <p>Implementations of views that support nested scrolling should call this to report 21271 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 21272 * is not currently in progress or nested scrolling is not 21273 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 21274 * 21275 * <p>Compatible View implementations should also call 21276 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 21277 * consuming a component of the scroll event themselves.</p> 21278 * 21279 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 21280 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 21281 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 21282 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 21283 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21284 * in local view coordinates of this view from before this operation 21285 * to after it completes. View implementations may use this to adjust 21286 * expected input coordinate tracking. 21287 * @return true if the event was dispatched, false if it could not be dispatched. 21288 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 21289 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)21290 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 21291 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 21292 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21293 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 21294 int startX = 0; 21295 int startY = 0; 21296 if (offsetInWindow != null) { 21297 getLocationInWindow(offsetInWindow); 21298 startX = offsetInWindow[0]; 21299 startY = offsetInWindow[1]; 21300 } 21301 21302 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 21303 dxUnconsumed, dyUnconsumed); 21304 21305 if (offsetInWindow != null) { 21306 getLocationInWindow(offsetInWindow); 21307 offsetInWindow[0] -= startX; 21308 offsetInWindow[1] -= startY; 21309 } 21310 return true; 21311 } else if (offsetInWindow != null) { 21312 // No motion, no dispatch. Keep offsetInWindow up to date. 21313 offsetInWindow[0] = 0; 21314 offsetInWindow[1] = 0; 21315 } 21316 } 21317 return false; 21318 } 21319 21320 /** 21321 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 21322 * 21323 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 21324 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 21325 * scrolling operation to consume some or all of the scroll operation before the child view 21326 * consumes it.</p> 21327 * 21328 * @param dx Horizontal scroll distance in pixels 21329 * @param dy Vertical scroll distance in pixels 21330 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 21331 * and consumed[1] the consumed dy. 21332 * @param offsetInWindow Optional. If not null, on return this will contain the offset 21333 * in local view coordinates of this view from before this operation 21334 * to after it completes. View implementations may use this to adjust 21335 * expected input coordinate tracking. 21336 * @return true if the parent consumed some or all of the scroll delta 21337 * @see #dispatchNestedScroll(int, int, int, int, int[]) 21338 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)21339 public boolean dispatchNestedPreScroll(int dx, int dy, 21340 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 21341 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21342 if (dx != 0 || dy != 0) { 21343 int startX = 0; 21344 int startY = 0; 21345 if (offsetInWindow != null) { 21346 getLocationInWindow(offsetInWindow); 21347 startX = offsetInWindow[0]; 21348 startY = offsetInWindow[1]; 21349 } 21350 21351 if (consumed == null) { 21352 if (mTempNestedScrollConsumed == null) { 21353 mTempNestedScrollConsumed = new int[2]; 21354 } 21355 consumed = mTempNestedScrollConsumed; 21356 } 21357 consumed[0] = 0; 21358 consumed[1] = 0; 21359 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 21360 21361 if (offsetInWindow != null) { 21362 getLocationInWindow(offsetInWindow); 21363 offsetInWindow[0] -= startX; 21364 offsetInWindow[1] -= startY; 21365 } 21366 return consumed[0] != 0 || consumed[1] != 0; 21367 } else if (offsetInWindow != null) { 21368 offsetInWindow[0] = 0; 21369 offsetInWindow[1] = 0; 21370 } 21371 } 21372 return false; 21373 } 21374 21375 /** 21376 * Dispatch a fling to a nested scrolling parent. 21377 * 21378 * <p>This method should be used to indicate that a nested scrolling child has detected 21379 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 21380 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 21381 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 21382 * along a scrollable axis.</p> 21383 * 21384 * <p>If a nested scrolling child view would normally fling but it is at the edge of 21385 * its own content, it can use this method to delegate the fling to its nested scrolling 21386 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 21387 * 21388 * @param velocityX Horizontal fling velocity in pixels per second 21389 * @param velocityY Vertical fling velocity in pixels per second 21390 * @param consumed true if the child consumed the fling, false otherwise 21391 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 21392 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)21393 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 21394 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21395 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 21396 } 21397 return false; 21398 } 21399 21400 /** 21401 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 21402 * 21403 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 21404 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 21405 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 21406 * before the child view consumes it. If this method returns <code>true</code>, a nested 21407 * parent view consumed the fling and this view should not scroll as a result.</p> 21408 * 21409 * <p>For a better user experience, only one view in a nested scrolling chain should consume 21410 * the fling at a time. If a parent view consumed the fling this method will return false. 21411 * Custom view implementations should account for this in two ways:</p> 21412 * 21413 * <ul> 21414 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 21415 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 21416 * position regardless.</li> 21417 * <li>If a nested parent does consume the fling, this view should not scroll at all, 21418 * even to settle back to a valid idle position.</li> 21419 * </ul> 21420 * 21421 * <p>Views should also not offer fling velocities to nested parent views along an axis 21422 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 21423 * should not offer a horizontal fling velocity to its parents since scrolling along that 21424 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 21425 * 21426 * @param velocityX Horizontal fling velocity in pixels per second 21427 * @param velocityY Vertical fling velocity in pixels per second 21428 * @return true if a nested scrolling parent consumed the fling 21429 */ dispatchNestedPreFling(float velocityX, float velocityY)21430 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 21431 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 21432 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 21433 } 21434 return false; 21435 } 21436 21437 /** 21438 * Gets a scale factor that determines the distance the view should scroll 21439 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 21440 * @return The vertical scroll scale factor. 21441 * @hide 21442 */ getVerticalScrollFactor()21443 protected float getVerticalScrollFactor() { 21444 if (mVerticalScrollFactor == 0) { 21445 TypedValue outValue = new TypedValue(); 21446 if (!mContext.getTheme().resolveAttribute( 21447 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 21448 throw new IllegalStateException( 21449 "Expected theme to define listPreferredItemHeight."); 21450 } 21451 mVerticalScrollFactor = outValue.getDimension( 21452 mContext.getResources().getDisplayMetrics()); 21453 } 21454 return mVerticalScrollFactor; 21455 } 21456 21457 /** 21458 * Gets a scale factor that determines the distance the view should scroll 21459 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 21460 * @return The horizontal scroll scale factor. 21461 * @hide 21462 */ getHorizontalScrollFactor()21463 protected float getHorizontalScrollFactor() { 21464 // TODO: Should use something else. 21465 return getVerticalScrollFactor(); 21466 } 21467 21468 /** 21469 * Return the value specifying the text direction or policy that was set with 21470 * {@link #setTextDirection(int)}. 21471 * 21472 * @return the defined text direction. It can be one of: 21473 * 21474 * {@link #TEXT_DIRECTION_INHERIT}, 21475 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 21476 * {@link #TEXT_DIRECTION_ANY_RTL}, 21477 * {@link #TEXT_DIRECTION_LTR}, 21478 * {@link #TEXT_DIRECTION_RTL}, 21479 * {@link #TEXT_DIRECTION_LOCALE}, 21480 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 21481 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 21482 * 21483 * @attr ref android.R.styleable#View_textDirection 21484 * 21485 * @hide 21486 */ 21487 @ViewDebug.ExportedProperty(category = "text", mapping = { 21488 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 21489 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 21490 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 21491 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 21492 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 21493 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 21494 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 21495 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 21496 }) getRawTextDirection()21497 public int getRawTextDirection() { 21498 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 21499 } 21500 21501 /** 21502 * Set the text direction. 21503 * 21504 * @param textDirection the direction to set. Should be one of: 21505 * 21506 * {@link #TEXT_DIRECTION_INHERIT}, 21507 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 21508 * {@link #TEXT_DIRECTION_ANY_RTL}, 21509 * {@link #TEXT_DIRECTION_LTR}, 21510 * {@link #TEXT_DIRECTION_RTL}, 21511 * {@link #TEXT_DIRECTION_LOCALE} 21512 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 21513 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 21514 * 21515 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 21516 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 21517 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 21518 * 21519 * @attr ref android.R.styleable#View_textDirection 21520 */ setTextDirection(int textDirection)21521 public void setTextDirection(int textDirection) { 21522 if (getRawTextDirection() != textDirection) { 21523 // Reset the current text direction and the resolved one 21524 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 21525 resetResolvedTextDirection(); 21526 // Set the new text direction 21527 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 21528 // Do resolution 21529 resolveTextDirection(); 21530 // Notify change 21531 onRtlPropertiesChanged(getLayoutDirection()); 21532 // Refresh 21533 requestLayout(); 21534 invalidate(true); 21535 } 21536 } 21537 21538 /** 21539 * Return the resolved text direction. 21540 * 21541 * @return the resolved text direction. Returns one of: 21542 * 21543 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 21544 * {@link #TEXT_DIRECTION_ANY_RTL}, 21545 * {@link #TEXT_DIRECTION_LTR}, 21546 * {@link #TEXT_DIRECTION_RTL}, 21547 * {@link #TEXT_DIRECTION_LOCALE}, 21548 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 21549 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 21550 * 21551 * @attr ref android.R.styleable#View_textDirection 21552 */ 21553 @ViewDebug.ExportedProperty(category = "text", mapping = { 21554 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 21555 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 21556 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 21557 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 21558 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 21559 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 21560 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 21561 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 21562 }) getTextDirection()21563 public int getTextDirection() { 21564 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 21565 } 21566 21567 /** 21568 * Resolve the text direction. 21569 * 21570 * @return true if resolution has been done, false otherwise. 21571 * 21572 * @hide 21573 */ resolveTextDirection()21574 public boolean resolveTextDirection() { 21575 // Reset any previous text direction resolution 21576 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 21577 21578 if (hasRtlSupport()) { 21579 // Set resolved text direction flag depending on text direction flag 21580 final int textDirection = getRawTextDirection(); 21581 switch(textDirection) { 21582 case TEXT_DIRECTION_INHERIT: 21583 if (!canResolveTextDirection()) { 21584 // We cannot do the resolution if there is no parent, so use the default one 21585 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21586 // Resolution will need to happen again later 21587 return false; 21588 } 21589 21590 // Parent has not yet resolved, so we still return the default 21591 try { 21592 if (!mParent.isTextDirectionResolved()) { 21593 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21594 // Resolution will need to happen again later 21595 return false; 21596 } 21597 } catch (AbstractMethodError e) { 21598 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21599 " does not fully implement ViewParent", e); 21600 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 21601 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21602 return true; 21603 } 21604 21605 // Set current resolved direction to the same value as the parent's one 21606 int parentResolvedDirection; 21607 try { 21608 parentResolvedDirection = mParent.getTextDirection(); 21609 } catch (AbstractMethodError e) { 21610 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21611 " does not fully implement ViewParent", e); 21612 parentResolvedDirection = TEXT_DIRECTION_LTR; 21613 } 21614 switch (parentResolvedDirection) { 21615 case TEXT_DIRECTION_FIRST_STRONG: 21616 case TEXT_DIRECTION_ANY_RTL: 21617 case TEXT_DIRECTION_LTR: 21618 case TEXT_DIRECTION_RTL: 21619 case TEXT_DIRECTION_LOCALE: 21620 case TEXT_DIRECTION_FIRST_STRONG_LTR: 21621 case TEXT_DIRECTION_FIRST_STRONG_RTL: 21622 mPrivateFlags2 |= 21623 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 21624 break; 21625 default: 21626 // Default resolved direction is "first strong" heuristic 21627 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21628 } 21629 break; 21630 case TEXT_DIRECTION_FIRST_STRONG: 21631 case TEXT_DIRECTION_ANY_RTL: 21632 case TEXT_DIRECTION_LTR: 21633 case TEXT_DIRECTION_RTL: 21634 case TEXT_DIRECTION_LOCALE: 21635 case TEXT_DIRECTION_FIRST_STRONG_LTR: 21636 case TEXT_DIRECTION_FIRST_STRONG_RTL: 21637 // Resolved direction is the same as text direction 21638 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 21639 break; 21640 default: 21641 // Default resolved direction is "first strong" heuristic 21642 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21643 } 21644 } else { 21645 // Default resolved direction is "first strong" heuristic 21646 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21647 } 21648 21649 // Set to resolved 21650 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 21651 return true; 21652 } 21653 21654 /** 21655 * Check if text direction resolution can be done. 21656 * 21657 * @return true if text direction resolution can be done otherwise return false. 21658 */ canResolveTextDirection()21659 public boolean canResolveTextDirection() { 21660 switch (getRawTextDirection()) { 21661 case TEXT_DIRECTION_INHERIT: 21662 if (mParent != null) { 21663 try { 21664 return mParent.canResolveTextDirection(); 21665 } catch (AbstractMethodError e) { 21666 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21667 " does not fully implement ViewParent", e); 21668 } 21669 } 21670 return false; 21671 21672 default: 21673 return true; 21674 } 21675 } 21676 21677 /** 21678 * Reset resolved text direction. Text direction will be resolved during a call to 21679 * {@link #onMeasure(int, int)}. 21680 * 21681 * @hide 21682 */ resetResolvedTextDirection()21683 public void resetResolvedTextDirection() { 21684 // Reset any previous text direction resolution 21685 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 21686 // Set to default value 21687 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 21688 } 21689 21690 /** 21691 * @return true if text direction is inherited. 21692 * 21693 * @hide 21694 */ isTextDirectionInherited()21695 public boolean isTextDirectionInherited() { 21696 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 21697 } 21698 21699 /** 21700 * @return true if text direction is resolved. 21701 */ isTextDirectionResolved()21702 public boolean isTextDirectionResolved() { 21703 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 21704 } 21705 21706 /** 21707 * Return the value specifying the text alignment or policy that was set with 21708 * {@link #setTextAlignment(int)}. 21709 * 21710 * @return the defined text alignment. It can be one of: 21711 * 21712 * {@link #TEXT_ALIGNMENT_INHERIT}, 21713 * {@link #TEXT_ALIGNMENT_GRAVITY}, 21714 * {@link #TEXT_ALIGNMENT_CENTER}, 21715 * {@link #TEXT_ALIGNMENT_TEXT_START}, 21716 * {@link #TEXT_ALIGNMENT_TEXT_END}, 21717 * {@link #TEXT_ALIGNMENT_VIEW_START}, 21718 * {@link #TEXT_ALIGNMENT_VIEW_END} 21719 * 21720 * @attr ref android.R.styleable#View_textAlignment 21721 * 21722 * @hide 21723 */ 21724 @ViewDebug.ExportedProperty(category = "text", mapping = { 21725 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 21726 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 21727 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 21728 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 21729 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 21730 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 21731 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 21732 }) 21733 @TextAlignment getRawTextAlignment()21734 public int getRawTextAlignment() { 21735 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 21736 } 21737 21738 /** 21739 * Set the text alignment. 21740 * 21741 * @param textAlignment The text alignment to set. Should be one of 21742 * 21743 * {@link #TEXT_ALIGNMENT_INHERIT}, 21744 * {@link #TEXT_ALIGNMENT_GRAVITY}, 21745 * {@link #TEXT_ALIGNMENT_CENTER}, 21746 * {@link #TEXT_ALIGNMENT_TEXT_START}, 21747 * {@link #TEXT_ALIGNMENT_TEXT_END}, 21748 * {@link #TEXT_ALIGNMENT_VIEW_START}, 21749 * {@link #TEXT_ALIGNMENT_VIEW_END} 21750 * 21751 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 21752 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 21753 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 21754 * 21755 * @attr ref android.R.styleable#View_textAlignment 21756 */ setTextAlignment(@extAlignment int textAlignment)21757 public void setTextAlignment(@TextAlignment int textAlignment) { 21758 if (textAlignment != getRawTextAlignment()) { 21759 // Reset the current and resolved text alignment 21760 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 21761 resetResolvedTextAlignment(); 21762 // Set the new text alignment 21763 mPrivateFlags2 |= 21764 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 21765 // Do resolution 21766 resolveTextAlignment(); 21767 // Notify change 21768 onRtlPropertiesChanged(getLayoutDirection()); 21769 // Refresh 21770 requestLayout(); 21771 invalidate(true); 21772 } 21773 } 21774 21775 /** 21776 * Return the resolved text alignment. 21777 * 21778 * @return the resolved text alignment. Returns one of: 21779 * 21780 * {@link #TEXT_ALIGNMENT_GRAVITY}, 21781 * {@link #TEXT_ALIGNMENT_CENTER}, 21782 * {@link #TEXT_ALIGNMENT_TEXT_START}, 21783 * {@link #TEXT_ALIGNMENT_TEXT_END}, 21784 * {@link #TEXT_ALIGNMENT_VIEW_START}, 21785 * {@link #TEXT_ALIGNMENT_VIEW_END} 21786 * 21787 * @attr ref android.R.styleable#View_textAlignment 21788 */ 21789 @ViewDebug.ExportedProperty(category = "text", mapping = { 21790 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 21791 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 21792 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 21793 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 21794 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 21795 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 21796 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 21797 }) 21798 @TextAlignment getTextAlignment()21799 public int getTextAlignment() { 21800 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 21801 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 21802 } 21803 21804 /** 21805 * Resolve the text alignment. 21806 * 21807 * @return true if resolution has been done, false otherwise. 21808 * 21809 * @hide 21810 */ resolveTextAlignment()21811 public boolean resolveTextAlignment() { 21812 // Reset any previous text alignment resolution 21813 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 21814 21815 if (hasRtlSupport()) { 21816 // Set resolved text alignment flag depending on text alignment flag 21817 final int textAlignment = getRawTextAlignment(); 21818 switch (textAlignment) { 21819 case TEXT_ALIGNMENT_INHERIT: 21820 // Check if we can resolve the text alignment 21821 if (!canResolveTextAlignment()) { 21822 // We cannot do the resolution if there is no parent so use the default 21823 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21824 // Resolution will need to happen again later 21825 return false; 21826 } 21827 21828 // Parent has not yet resolved, so we still return the default 21829 try { 21830 if (!mParent.isTextAlignmentResolved()) { 21831 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21832 // Resolution will need to happen again later 21833 return false; 21834 } 21835 } catch (AbstractMethodError e) { 21836 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21837 " does not fully implement ViewParent", e); 21838 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 21839 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21840 return true; 21841 } 21842 21843 int parentResolvedTextAlignment; 21844 try { 21845 parentResolvedTextAlignment = mParent.getTextAlignment(); 21846 } catch (AbstractMethodError e) { 21847 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21848 " does not fully implement ViewParent", e); 21849 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 21850 } 21851 switch (parentResolvedTextAlignment) { 21852 case TEXT_ALIGNMENT_GRAVITY: 21853 case TEXT_ALIGNMENT_TEXT_START: 21854 case TEXT_ALIGNMENT_TEXT_END: 21855 case TEXT_ALIGNMENT_CENTER: 21856 case TEXT_ALIGNMENT_VIEW_START: 21857 case TEXT_ALIGNMENT_VIEW_END: 21858 // Resolved text alignment is the same as the parent resolved 21859 // text alignment 21860 mPrivateFlags2 |= 21861 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 21862 break; 21863 default: 21864 // Use default resolved text alignment 21865 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21866 } 21867 break; 21868 case TEXT_ALIGNMENT_GRAVITY: 21869 case TEXT_ALIGNMENT_TEXT_START: 21870 case TEXT_ALIGNMENT_TEXT_END: 21871 case TEXT_ALIGNMENT_CENTER: 21872 case TEXT_ALIGNMENT_VIEW_START: 21873 case TEXT_ALIGNMENT_VIEW_END: 21874 // Resolved text alignment is the same as text alignment 21875 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 21876 break; 21877 default: 21878 // Use default resolved text alignment 21879 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21880 } 21881 } else { 21882 // Use default resolved text alignment 21883 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21884 } 21885 21886 // Set the resolved 21887 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 21888 return true; 21889 } 21890 21891 /** 21892 * Check if text alignment resolution can be done. 21893 * 21894 * @return true if text alignment resolution can be done otherwise return false. 21895 */ canResolveTextAlignment()21896 public boolean canResolveTextAlignment() { 21897 switch (getRawTextAlignment()) { 21898 case TEXT_DIRECTION_INHERIT: 21899 if (mParent != null) { 21900 try { 21901 return mParent.canResolveTextAlignment(); 21902 } catch (AbstractMethodError e) { 21903 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21904 " does not fully implement ViewParent", e); 21905 } 21906 } 21907 return false; 21908 21909 default: 21910 return true; 21911 } 21912 } 21913 21914 /** 21915 * Reset resolved text alignment. Text alignment will be resolved during a call to 21916 * {@link #onMeasure(int, int)}. 21917 * 21918 * @hide 21919 */ resetResolvedTextAlignment()21920 public void resetResolvedTextAlignment() { 21921 // Reset any previous text alignment resolution 21922 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 21923 // Set to default 21924 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 21925 } 21926 21927 /** 21928 * @return true if text alignment is inherited. 21929 * 21930 * @hide 21931 */ isTextAlignmentInherited()21932 public boolean isTextAlignmentInherited() { 21933 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 21934 } 21935 21936 /** 21937 * @return true if text alignment is resolved. 21938 */ isTextAlignmentResolved()21939 public boolean isTextAlignmentResolved() { 21940 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 21941 } 21942 21943 /** 21944 * Generate a value suitable for use in {@link #setId(int)}. 21945 * This value will not collide with ID values generated at build time by aapt for R.id. 21946 * 21947 * @return a generated ID value 21948 */ generateViewId()21949 public static int generateViewId() { 21950 for (;;) { 21951 final int result = sNextGeneratedId.get(); 21952 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 21953 int newValue = result + 1; 21954 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 21955 if (sNextGeneratedId.compareAndSet(result, newValue)) { 21956 return result; 21957 } 21958 } 21959 } 21960 21961 /** 21962 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 21963 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 21964 * a normal View or a ViewGroup with 21965 * {@link android.view.ViewGroup#isTransitionGroup()} true. 21966 * @hide 21967 */ captureTransitioningViews(List<View> transitioningViews)21968 public void captureTransitioningViews(List<View> transitioningViews) { 21969 if (getVisibility() == View.VISIBLE) { 21970 transitioningViews.add(this); 21971 } 21972 } 21973 21974 /** 21975 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 21976 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 21977 * @hide 21978 */ findNamedViews(Map<String, View> namedElements)21979 public void findNamedViews(Map<String, View> namedElements) { 21980 if (getVisibility() == VISIBLE || mGhostView != null) { 21981 String transitionName = getTransitionName(); 21982 if (transitionName != null) { 21983 namedElements.put(transitionName, this); 21984 } 21985 } 21986 } 21987 21988 /** 21989 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 21990 * The default implementation does not care the location or event types, but some subclasses 21991 * may use it (such as WebViews). 21992 * @param event The MotionEvent from a mouse 21993 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 21994 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 21995 * @see PointerIcon 21996 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)21997 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 21998 final float x = event.getX(pointerIndex); 21999 final float y = event.getY(pointerIndex); 22000 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 22001 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 22002 } 22003 return mPointerIcon; 22004 } 22005 22006 /** 22007 * Set the pointer icon for the current view. 22008 * Passing {@code null} will restore the pointer icon to its default value. 22009 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 22010 */ setPointerIcon(PointerIcon pointerIcon)22011 public void setPointerIcon(PointerIcon pointerIcon) { 22012 mPointerIcon = pointerIcon; 22013 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 22014 return; 22015 } 22016 try { 22017 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 22018 } catch (RemoteException e) { 22019 } 22020 } 22021 22022 /** 22023 * Gets the pointer icon for the current view. 22024 */ getPointerIcon()22025 public PointerIcon getPointerIcon() { 22026 return mPointerIcon; 22027 } 22028 22029 // 22030 // Properties 22031 // 22032 /** 22033 * A Property wrapper around the <code>alpha</code> functionality handled by the 22034 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 22035 */ 22036 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 22037 @Override 22038 public void setValue(View object, float value) { 22039 object.setAlpha(value); 22040 } 22041 22042 @Override 22043 public Float get(View object) { 22044 return object.getAlpha(); 22045 } 22046 }; 22047 22048 /** 22049 * A Property wrapper around the <code>translationX</code> functionality handled by the 22050 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 22051 */ 22052 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 22053 @Override 22054 public void setValue(View object, float value) { 22055 object.setTranslationX(value); 22056 } 22057 22058 @Override 22059 public Float get(View object) { 22060 return object.getTranslationX(); 22061 } 22062 }; 22063 22064 /** 22065 * A Property wrapper around the <code>translationY</code> functionality handled by the 22066 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 22067 */ 22068 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 22069 @Override 22070 public void setValue(View object, float value) { 22071 object.setTranslationY(value); 22072 } 22073 22074 @Override 22075 public Float get(View object) { 22076 return object.getTranslationY(); 22077 } 22078 }; 22079 22080 /** 22081 * A Property wrapper around the <code>translationZ</code> functionality handled by the 22082 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 22083 */ 22084 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 22085 @Override 22086 public void setValue(View object, float value) { 22087 object.setTranslationZ(value); 22088 } 22089 22090 @Override 22091 public Float get(View object) { 22092 return object.getTranslationZ(); 22093 } 22094 }; 22095 22096 /** 22097 * A Property wrapper around the <code>x</code> functionality handled by the 22098 * {@link View#setX(float)} and {@link View#getX()} methods. 22099 */ 22100 public static final Property<View, Float> X = new FloatProperty<View>("x") { 22101 @Override 22102 public void setValue(View object, float value) { 22103 object.setX(value); 22104 } 22105 22106 @Override 22107 public Float get(View object) { 22108 return object.getX(); 22109 } 22110 }; 22111 22112 /** 22113 * A Property wrapper around the <code>y</code> functionality handled by the 22114 * {@link View#setY(float)} and {@link View#getY()} methods. 22115 */ 22116 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 22117 @Override 22118 public void setValue(View object, float value) { 22119 object.setY(value); 22120 } 22121 22122 @Override 22123 public Float get(View object) { 22124 return object.getY(); 22125 } 22126 }; 22127 22128 /** 22129 * A Property wrapper around the <code>z</code> functionality handled by the 22130 * {@link View#setZ(float)} and {@link View#getZ()} methods. 22131 */ 22132 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 22133 @Override 22134 public void setValue(View object, float value) { 22135 object.setZ(value); 22136 } 22137 22138 @Override 22139 public Float get(View object) { 22140 return object.getZ(); 22141 } 22142 }; 22143 22144 /** 22145 * A Property wrapper around the <code>rotation</code> functionality handled by the 22146 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 22147 */ 22148 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 22149 @Override 22150 public void setValue(View object, float value) { 22151 object.setRotation(value); 22152 } 22153 22154 @Override 22155 public Float get(View object) { 22156 return object.getRotation(); 22157 } 22158 }; 22159 22160 /** 22161 * A Property wrapper around the <code>rotationX</code> functionality handled by the 22162 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 22163 */ 22164 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 22165 @Override 22166 public void setValue(View object, float value) { 22167 object.setRotationX(value); 22168 } 22169 22170 @Override 22171 public Float get(View object) { 22172 return object.getRotationX(); 22173 } 22174 }; 22175 22176 /** 22177 * A Property wrapper around the <code>rotationY</code> functionality handled by the 22178 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 22179 */ 22180 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 22181 @Override 22182 public void setValue(View object, float value) { 22183 object.setRotationY(value); 22184 } 22185 22186 @Override 22187 public Float get(View object) { 22188 return object.getRotationY(); 22189 } 22190 }; 22191 22192 /** 22193 * A Property wrapper around the <code>scaleX</code> functionality handled by the 22194 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 22195 */ 22196 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 22197 @Override 22198 public void setValue(View object, float value) { 22199 object.setScaleX(value); 22200 } 22201 22202 @Override 22203 public Float get(View object) { 22204 return object.getScaleX(); 22205 } 22206 }; 22207 22208 /** 22209 * A Property wrapper around the <code>scaleY</code> functionality handled by the 22210 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 22211 */ 22212 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 22213 @Override 22214 public void setValue(View object, float value) { 22215 object.setScaleY(value); 22216 } 22217 22218 @Override 22219 public Float get(View object) { 22220 return object.getScaleY(); 22221 } 22222 }; 22223 22224 /** 22225 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 22226 * Each MeasureSpec represents a requirement for either the width or the height. 22227 * A MeasureSpec is comprised of a size and a mode. There are three possible 22228 * modes: 22229 * <dl> 22230 * <dt>UNSPECIFIED</dt> 22231 * <dd> 22232 * The parent has not imposed any constraint on the child. It can be whatever size 22233 * it wants. 22234 * </dd> 22235 * 22236 * <dt>EXACTLY</dt> 22237 * <dd> 22238 * The parent has determined an exact size for the child. The child is going to be 22239 * given those bounds regardless of how big it wants to be. 22240 * </dd> 22241 * 22242 * <dt>AT_MOST</dt> 22243 * <dd> 22244 * The child can be as large as it wants up to the specified size. 22245 * </dd> 22246 * </dl> 22247 * 22248 * MeasureSpecs are implemented as ints to reduce object allocation. This class 22249 * is provided to pack and unpack the <size, mode> tuple into the int. 22250 */ 22251 public static class MeasureSpec { 22252 private static final int MODE_SHIFT = 30; 22253 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 22254 22255 /** @hide */ 22256 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 22257 @Retention(RetentionPolicy.SOURCE) 22258 public @interface MeasureSpecMode {} 22259 22260 /** 22261 * Measure specification mode: The parent has not imposed any constraint 22262 * on the child. It can be whatever size it wants. 22263 */ 22264 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 22265 22266 /** 22267 * Measure specification mode: The parent has determined an exact size 22268 * for the child. The child is going to be given those bounds regardless 22269 * of how big it wants to be. 22270 */ 22271 public static final int EXACTLY = 1 << MODE_SHIFT; 22272 22273 /** 22274 * Measure specification mode: The child can be as large as it wants up 22275 * to the specified size. 22276 */ 22277 public static final int AT_MOST = 2 << MODE_SHIFT; 22278 22279 /** 22280 * Creates a measure specification based on the supplied size and mode. 22281 * 22282 * The mode must always be one of the following: 22283 * <ul> 22284 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 22285 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 22286 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 22287 * </ul> 22288 * 22289 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 22290 * implementation was such that the order of arguments did not matter 22291 * and overflow in either value could impact the resulting MeasureSpec. 22292 * {@link android.widget.RelativeLayout} was affected by this bug. 22293 * Apps targeting API levels greater than 17 will get the fixed, more strict 22294 * behavior.</p> 22295 * 22296 * @param size the size of the measure specification 22297 * @param mode the mode of the measure specification 22298 * @return the measure specification based on size and mode 22299 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)22300 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 22301 @MeasureSpecMode int mode) { 22302 if (sUseBrokenMakeMeasureSpec) { 22303 return size + mode; 22304 } else { 22305 return (size & ~MODE_MASK) | (mode & MODE_MASK); 22306 } 22307 } 22308 22309 /** 22310 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 22311 * will automatically get a size of 0. Older apps expect this. 22312 * 22313 * @hide internal use only for compatibility with system widgets and older apps 22314 */ makeSafeMeasureSpec(int size, int mode)22315 public static int makeSafeMeasureSpec(int size, int mode) { 22316 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 22317 return 0; 22318 } 22319 return makeMeasureSpec(size, mode); 22320 } 22321 22322 /** 22323 * Extracts the mode from the supplied measure specification. 22324 * 22325 * @param measureSpec the measure specification to extract the mode from 22326 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 22327 * {@link android.view.View.MeasureSpec#AT_MOST} or 22328 * {@link android.view.View.MeasureSpec#EXACTLY} 22329 */ 22330 @MeasureSpecMode getMode(int measureSpec)22331 public static int getMode(int measureSpec) { 22332 //noinspection ResourceType 22333 return (measureSpec & MODE_MASK); 22334 } 22335 22336 /** 22337 * Extracts the size from the supplied measure specification. 22338 * 22339 * @param measureSpec the measure specification to extract the size from 22340 * @return the size in pixels defined in the supplied measure specification 22341 */ getSize(int measureSpec)22342 public static int getSize(int measureSpec) { 22343 return (measureSpec & ~MODE_MASK); 22344 } 22345 adjust(int measureSpec, int delta)22346 static int adjust(int measureSpec, int delta) { 22347 final int mode = getMode(measureSpec); 22348 int size = getSize(measureSpec); 22349 if (mode == UNSPECIFIED) { 22350 // No need to adjust size for UNSPECIFIED mode. 22351 return makeMeasureSpec(size, UNSPECIFIED); 22352 } 22353 size += delta; 22354 if (size < 0) { 22355 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 22356 ") spec: " + toString(measureSpec) + " delta: " + delta); 22357 size = 0; 22358 } 22359 return makeMeasureSpec(size, mode); 22360 } 22361 22362 /** 22363 * Returns a String representation of the specified measure 22364 * specification. 22365 * 22366 * @param measureSpec the measure specification to convert to a String 22367 * @return a String with the following format: "MeasureSpec: MODE SIZE" 22368 */ toString(int measureSpec)22369 public static String toString(int measureSpec) { 22370 int mode = getMode(measureSpec); 22371 int size = getSize(measureSpec); 22372 22373 StringBuilder sb = new StringBuilder("MeasureSpec: "); 22374 22375 if (mode == UNSPECIFIED) 22376 sb.append("UNSPECIFIED "); 22377 else if (mode == EXACTLY) 22378 sb.append("EXACTLY "); 22379 else if (mode == AT_MOST) 22380 sb.append("AT_MOST "); 22381 else 22382 sb.append(mode).append(" "); 22383 22384 sb.append(size); 22385 return sb.toString(); 22386 } 22387 } 22388 22389 private final class CheckForLongPress implements Runnable { 22390 private int mOriginalWindowAttachCount; 22391 private float mX; 22392 private float mY; 22393 22394 @Override run()22395 public void run() { 22396 if (isPressed() && (mParent != null) 22397 && mOriginalWindowAttachCount == mWindowAttachCount) { 22398 if (performLongClick(mX, mY)) { 22399 mHasPerformedLongPress = true; 22400 } 22401 } 22402 } 22403 setAnchor(float x, float y)22404 public void setAnchor(float x, float y) { 22405 mX = x; 22406 mY = y; 22407 } 22408 rememberWindowAttachCount()22409 public void rememberWindowAttachCount() { 22410 mOriginalWindowAttachCount = mWindowAttachCount; 22411 } 22412 } 22413 22414 private final class CheckForTap implements Runnable { 22415 public float x; 22416 public float y; 22417 22418 @Override run()22419 public void run() { 22420 mPrivateFlags &= ~PFLAG_PREPRESSED; 22421 setPressed(true, x, y); 22422 checkForLongClick(ViewConfiguration.getTapTimeout(), x, y); 22423 } 22424 } 22425 22426 private final class PerformClick implements Runnable { 22427 @Override run()22428 public void run() { 22429 performClick(); 22430 } 22431 } 22432 22433 /** 22434 * This method returns a ViewPropertyAnimator object, which can be used to animate 22435 * specific properties on this View. 22436 * 22437 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 22438 */ animate()22439 public ViewPropertyAnimator animate() { 22440 if (mAnimator == null) { 22441 mAnimator = new ViewPropertyAnimator(this); 22442 } 22443 return mAnimator; 22444 } 22445 22446 /** 22447 * Sets the name of the View to be used to identify Views in Transitions. 22448 * Names should be unique in the View hierarchy. 22449 * 22450 * @param transitionName The name of the View to uniquely identify it for Transitions. 22451 */ setTransitionName(String transitionName)22452 public final void setTransitionName(String transitionName) { 22453 mTransitionName = transitionName; 22454 } 22455 22456 /** 22457 * Returns the name of the View to be used to identify Views in Transitions. 22458 * Names should be unique in the View hierarchy. 22459 * 22460 * <p>This returns null if the View has not been given a name.</p> 22461 * 22462 * @return The name used of the View to be used to identify Views in Transitions or null 22463 * if no name has been given. 22464 */ 22465 @ViewDebug.ExportedProperty getTransitionName()22466 public String getTransitionName() { 22467 return mTransitionName; 22468 } 22469 22470 /** 22471 * @hide 22472 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)22473 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 22474 // Do nothing. 22475 } 22476 22477 /** 22478 * Interface definition for a callback to be invoked when a hardware key event is 22479 * dispatched to this view. The callback will be invoked before the key event is 22480 * given to the view. This is only useful for hardware keyboards; a software input 22481 * method has no obligation to trigger this listener. 22482 */ 22483 public interface OnKeyListener { 22484 /** 22485 * Called when a hardware key is dispatched to a view. This allows listeners to 22486 * get a chance to respond before the target view. 22487 * <p>Key presses in software keyboards will generally NOT trigger this method, 22488 * although some may elect to do so in some situations. Do not assume a 22489 * software input method has to be key-based; even if it is, it may use key presses 22490 * in a different way than you expect, so there is no way to reliably catch soft 22491 * input key presses. 22492 * 22493 * @param v The view the key has been dispatched to. 22494 * @param keyCode The code for the physical key that was pressed 22495 * @param event The KeyEvent object containing full information about 22496 * the event. 22497 * @return True if the listener has consumed the event, false otherwise. 22498 */ onKey(View v, int keyCode, KeyEvent event)22499 boolean onKey(View v, int keyCode, KeyEvent event); 22500 } 22501 22502 /** 22503 * Interface definition for a callback to be invoked when a touch event is 22504 * dispatched to this view. The callback will be invoked before the touch 22505 * event is given to the view. 22506 */ 22507 public interface OnTouchListener { 22508 /** 22509 * Called when a touch event is dispatched to a view. This allows listeners to 22510 * get a chance to respond before the target view. 22511 * 22512 * @param v The view the touch event has been dispatched to. 22513 * @param event The MotionEvent object containing full information about 22514 * the event. 22515 * @return True if the listener has consumed the event, false otherwise. 22516 */ onTouch(View v, MotionEvent event)22517 boolean onTouch(View v, MotionEvent event); 22518 } 22519 22520 /** 22521 * Interface definition for a callback to be invoked when a hover event is 22522 * dispatched to this view. The callback will be invoked before the hover 22523 * event is given to the view. 22524 */ 22525 public interface OnHoverListener { 22526 /** 22527 * Called when a hover event is dispatched to a view. This allows listeners to 22528 * get a chance to respond before the target view. 22529 * 22530 * @param v The view the hover event has been dispatched to. 22531 * @param event The MotionEvent object containing full information about 22532 * the event. 22533 * @return True if the listener has consumed the event, false otherwise. 22534 */ onHover(View v, MotionEvent event)22535 boolean onHover(View v, MotionEvent event); 22536 } 22537 22538 /** 22539 * Interface definition for a callback to be invoked when a generic motion event is 22540 * dispatched to this view. The callback will be invoked before the generic motion 22541 * event is given to the view. 22542 */ 22543 public interface OnGenericMotionListener { 22544 /** 22545 * Called when a generic motion event is dispatched to a view. This allows listeners to 22546 * get a chance to respond before the target view. 22547 * 22548 * @param v The view the generic motion event has been dispatched to. 22549 * @param event The MotionEvent object containing full information about 22550 * the event. 22551 * @return True if the listener has consumed the event, false otherwise. 22552 */ onGenericMotion(View v, MotionEvent event)22553 boolean onGenericMotion(View v, MotionEvent event); 22554 } 22555 22556 /** 22557 * Interface definition for a callback to be invoked when a view has been clicked and held. 22558 */ 22559 public interface OnLongClickListener { 22560 /** 22561 * Called when a view has been clicked and held. 22562 * 22563 * @param v The view that was clicked and held. 22564 * 22565 * @return true if the callback consumed the long click, false otherwise. 22566 */ onLongClick(View v)22567 boolean onLongClick(View v); 22568 } 22569 22570 /** 22571 * Interface definition for a callback to be invoked when a drag is being dispatched 22572 * to this view. The callback will be invoked before the hosting view's own 22573 * onDrag(event) method. If the listener wants to fall back to the hosting view's 22574 * onDrag(event) behavior, it should return 'false' from this callback. 22575 * 22576 * <div class="special reference"> 22577 * <h3>Developer Guides</h3> 22578 * <p>For a guide to implementing drag and drop features, read the 22579 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 22580 * </div> 22581 */ 22582 public interface OnDragListener { 22583 /** 22584 * Called when a drag event is dispatched to a view. This allows listeners 22585 * to get a chance to override base View behavior. 22586 * 22587 * @param v The View that received the drag event. 22588 * @param event The {@link android.view.DragEvent} object for the drag event. 22589 * @return {@code true} if the drag event was handled successfully, or {@code false} 22590 * if the drag event was not handled. Note that {@code false} will trigger the View 22591 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 22592 */ onDrag(View v, DragEvent event)22593 boolean onDrag(View v, DragEvent event); 22594 } 22595 22596 /** 22597 * Interface definition for a callback to be invoked when the focus state of 22598 * a view changed. 22599 */ 22600 public interface OnFocusChangeListener { 22601 /** 22602 * Called when the focus state of a view has changed. 22603 * 22604 * @param v The view whose state has changed. 22605 * @param hasFocus The new focus state of v. 22606 */ onFocusChange(View v, boolean hasFocus)22607 void onFocusChange(View v, boolean hasFocus); 22608 } 22609 22610 /** 22611 * Interface definition for a callback to be invoked when a view is clicked. 22612 */ 22613 public interface OnClickListener { 22614 /** 22615 * Called when a view has been clicked. 22616 * 22617 * @param v The view that was clicked. 22618 */ onClick(View v)22619 void onClick(View v); 22620 } 22621 22622 /** 22623 * Interface definition for a callback to be invoked when a view is context clicked. 22624 */ 22625 public interface OnContextClickListener { 22626 /** 22627 * Called when a view is context clicked. 22628 * 22629 * @param v The view that has been context clicked. 22630 * @return true if the callback consumed the context click, false otherwise. 22631 */ onContextClick(View v)22632 boolean onContextClick(View v); 22633 } 22634 22635 /** 22636 * Interface definition for a callback to be invoked when the context menu 22637 * for this view is being built. 22638 */ 22639 public interface OnCreateContextMenuListener { 22640 /** 22641 * Called when the context menu for this view is being built. It is not 22642 * safe to hold onto the menu after this method returns. 22643 * 22644 * @param menu The context menu that is being built 22645 * @param v The view for which the context menu is being built 22646 * @param menuInfo Extra information about the item for which the 22647 * context menu should be shown. This information will vary 22648 * depending on the class of v. 22649 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)22650 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 22651 } 22652 22653 /** 22654 * Interface definition for a callback to be invoked when the status bar changes 22655 * visibility. This reports <strong>global</strong> changes to the system UI 22656 * state, not what the application is requesting. 22657 * 22658 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 22659 */ 22660 public interface OnSystemUiVisibilityChangeListener { 22661 /** 22662 * Called when the status bar changes visibility because of a call to 22663 * {@link View#setSystemUiVisibility(int)}. 22664 * 22665 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 22666 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 22667 * This tells you the <strong>global</strong> state of these UI visibility 22668 * flags, not what your app is currently applying. 22669 */ onSystemUiVisibilityChange(int visibility)22670 public void onSystemUiVisibilityChange(int visibility); 22671 } 22672 22673 /** 22674 * Interface definition for a callback to be invoked when this view is attached 22675 * or detached from its window. 22676 */ 22677 public interface OnAttachStateChangeListener { 22678 /** 22679 * Called when the view is attached to a window. 22680 * @param v The view that was attached 22681 */ onViewAttachedToWindow(View v)22682 public void onViewAttachedToWindow(View v); 22683 /** 22684 * Called when the view is detached from a window. 22685 * @param v The view that was detached 22686 */ onViewDetachedFromWindow(View v)22687 public void onViewDetachedFromWindow(View v); 22688 } 22689 22690 /** 22691 * Listener for applying window insets on a view in a custom way. 22692 * 22693 * <p>Apps may choose to implement this interface if they want to apply custom policy 22694 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 22695 * is set, its 22696 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 22697 * method will be called instead of the View's own 22698 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 22699 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 22700 * the View's normal behavior as part of its own.</p> 22701 */ 22702 public interface OnApplyWindowInsetsListener { 22703 /** 22704 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 22705 * on a View, this listener method will be called instead of the view's own 22706 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 22707 * 22708 * @param v The view applying window insets 22709 * @param insets The insets to apply 22710 * @return The insets supplied, minus any insets that were consumed 22711 */ onApplyWindowInsets(View v, WindowInsets insets)22712 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 22713 } 22714 22715 private final class UnsetPressedState implements Runnable { 22716 @Override run()22717 public void run() { 22718 setPressed(false); 22719 } 22720 } 22721 22722 /** 22723 * Base class for derived classes that want to save and restore their own 22724 * state in {@link android.view.View#onSaveInstanceState()}. 22725 */ 22726 public static class BaseSavedState extends AbsSavedState { 22727 String mStartActivityRequestWhoSaved; 22728 22729 /** 22730 * Constructor used when reading from a parcel. Reads the state of the superclass. 22731 * 22732 * @param source parcel to read from 22733 */ BaseSavedState(Parcel source)22734 public BaseSavedState(Parcel source) { 22735 this(source, null); 22736 } 22737 22738 /** 22739 * Constructor used when reading from a parcel using a given class loader. 22740 * Reads the state of the superclass. 22741 * 22742 * @param source parcel to read from 22743 * @param loader ClassLoader to use for reading 22744 */ BaseSavedState(Parcel source, ClassLoader loader)22745 public BaseSavedState(Parcel source, ClassLoader loader) { 22746 super(source, loader); 22747 mStartActivityRequestWhoSaved = source.readString(); 22748 } 22749 22750 /** 22751 * Constructor called by derived classes when creating their SavedState objects 22752 * 22753 * @param superState The state of the superclass of this view 22754 */ BaseSavedState(Parcelable superState)22755 public BaseSavedState(Parcelable superState) { 22756 super(superState); 22757 } 22758 22759 @Override writeToParcel(Parcel out, int flags)22760 public void writeToParcel(Parcel out, int flags) { 22761 super.writeToParcel(out, flags); 22762 out.writeString(mStartActivityRequestWhoSaved); 22763 } 22764 22765 public static final Parcelable.Creator<BaseSavedState> CREATOR 22766 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 22767 @Override 22768 public BaseSavedState createFromParcel(Parcel in) { 22769 return new BaseSavedState(in); 22770 } 22771 22772 @Override 22773 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 22774 return new BaseSavedState(in, loader); 22775 } 22776 22777 @Override 22778 public BaseSavedState[] newArray(int size) { 22779 return new BaseSavedState[size]; 22780 } 22781 }; 22782 } 22783 22784 /** 22785 * A set of information given to a view when it is attached to its parent 22786 * window. 22787 */ 22788 final static class AttachInfo { 22789 interface Callbacks { playSoundEffect(int effectId)22790 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)22791 boolean performHapticFeedback(int effectId, boolean always); 22792 } 22793 22794 /** 22795 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 22796 * to a Handler. This class contains the target (View) to invalidate and 22797 * the coordinates of the dirty rectangle. 22798 * 22799 * For performance purposes, this class also implements a pool of up to 22800 * POOL_LIMIT objects that get reused. This reduces memory allocations 22801 * whenever possible. 22802 */ 22803 static class InvalidateInfo { 22804 private static final int POOL_LIMIT = 10; 22805 22806 private static final SynchronizedPool<InvalidateInfo> sPool = 22807 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 22808 22809 View target; 22810 22811 int left; 22812 int top; 22813 int right; 22814 int bottom; 22815 obtain()22816 public static InvalidateInfo obtain() { 22817 InvalidateInfo instance = sPool.acquire(); 22818 return (instance != null) ? instance : new InvalidateInfo(); 22819 } 22820 recycle()22821 public void recycle() { 22822 target = null; 22823 sPool.release(this); 22824 } 22825 } 22826 22827 final IWindowSession mSession; 22828 22829 final IWindow mWindow; 22830 22831 final IBinder mWindowToken; 22832 22833 final Display mDisplay; 22834 22835 final Callbacks mRootCallbacks; 22836 22837 IWindowId mIWindowId; 22838 WindowId mWindowId; 22839 22840 /** 22841 * The top view of the hierarchy. 22842 */ 22843 View mRootView; 22844 22845 IBinder mPanelParentWindowToken; 22846 22847 boolean mHardwareAccelerated; 22848 boolean mHardwareAccelerationRequested; 22849 ThreadedRenderer mHardwareRenderer; 22850 List<RenderNode> mPendingAnimatingRenderNodes; 22851 22852 /** 22853 * The state of the display to which the window is attached, as reported 22854 * by {@link Display#getState()}. Note that the display state constants 22855 * declared by {@link Display} do not exactly line up with the screen state 22856 * constants declared by {@link View} (there are more display states than 22857 * screen states). 22858 */ 22859 int mDisplayState = Display.STATE_UNKNOWN; 22860 22861 /** 22862 * Scale factor used by the compatibility mode 22863 */ 22864 float mApplicationScale; 22865 22866 /** 22867 * Indicates whether the application is in compatibility mode 22868 */ 22869 boolean mScalingRequired; 22870 22871 /** 22872 * Left position of this view's window 22873 */ 22874 int mWindowLeft; 22875 22876 /** 22877 * Top position of this view's window 22878 */ 22879 int mWindowTop; 22880 22881 /** 22882 * Indicates whether views need to use 32-bit drawing caches 22883 */ 22884 boolean mUse32BitDrawingCache; 22885 22886 /** 22887 * For windows that are full-screen but using insets to layout inside 22888 * of the screen areas, these are the current insets to appear inside 22889 * the overscan area of the display. 22890 */ 22891 final Rect mOverscanInsets = new Rect(); 22892 22893 /** 22894 * For windows that are full-screen but using insets to layout inside 22895 * of the screen decorations, these are the current insets for the 22896 * content of the window. 22897 */ 22898 final Rect mContentInsets = new Rect(); 22899 22900 /** 22901 * For windows that are full-screen but using insets to layout inside 22902 * of the screen decorations, these are the current insets for the 22903 * actual visible parts of the window. 22904 */ 22905 final Rect mVisibleInsets = new Rect(); 22906 22907 /** 22908 * For windows that are full-screen but using insets to layout inside 22909 * of the screen decorations, these are the current insets for the 22910 * stable system windows. 22911 */ 22912 final Rect mStableInsets = new Rect(); 22913 22914 /** 22915 * For windows that include areas that are not covered by real surface these are the outsets 22916 * for real surface. 22917 */ 22918 final Rect mOutsets = new Rect(); 22919 22920 /** 22921 * In multi-window we force show the navigation bar. Because we don't want that the surface 22922 * size changes in this mode, we instead have a flag whether the navigation bar size should 22923 * always be consumed, so the app is treated like there is no virtual navigation bar at all. 22924 */ 22925 boolean mAlwaysConsumeNavBar; 22926 22927 /** 22928 * The internal insets given by this window. This value is 22929 * supplied by the client (through 22930 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 22931 * be given to the window manager when changed to be used in laying 22932 * out windows behind it. 22933 */ 22934 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 22935 = new ViewTreeObserver.InternalInsetsInfo(); 22936 22937 /** 22938 * Set to true when mGivenInternalInsets is non-empty. 22939 */ 22940 boolean mHasNonEmptyGivenInternalInsets; 22941 22942 /** 22943 * All views in the window's hierarchy that serve as scroll containers, 22944 * used to determine if the window can be resized or must be panned 22945 * to adjust for a soft input area. 22946 */ 22947 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 22948 22949 final KeyEvent.DispatcherState mKeyDispatchState 22950 = new KeyEvent.DispatcherState(); 22951 22952 /** 22953 * Indicates whether the view's window currently has the focus. 22954 */ 22955 boolean mHasWindowFocus; 22956 22957 /** 22958 * The current visibility of the window. 22959 */ 22960 int mWindowVisibility; 22961 22962 /** 22963 * Indicates the time at which drawing started to occur. 22964 */ 22965 long mDrawingTime; 22966 22967 /** 22968 * Indicates whether or not ignoring the DIRTY_MASK flags. 22969 */ 22970 boolean mIgnoreDirtyState; 22971 22972 /** 22973 * This flag tracks when the mIgnoreDirtyState flag is set during draw(), 22974 * to avoid clearing that flag prematurely. 22975 */ 22976 boolean mSetIgnoreDirtyState = false; 22977 22978 /** 22979 * Indicates whether the view's window is currently in touch mode. 22980 */ 22981 boolean mInTouchMode; 22982 22983 /** 22984 * Indicates whether the view has requested unbuffered input dispatching for the current 22985 * event stream. 22986 */ 22987 boolean mUnbufferedDispatchRequested; 22988 22989 /** 22990 * Indicates that ViewAncestor should trigger a global layout change 22991 * the next time it performs a traversal 22992 */ 22993 boolean mRecomputeGlobalAttributes; 22994 22995 /** 22996 * Always report new attributes at next traversal. 22997 */ 22998 boolean mForceReportNewAttributes; 22999 23000 /** 23001 * Set during a traveral if any views want to keep the screen on. 23002 */ 23003 boolean mKeepScreenOn; 23004 23005 /** 23006 * Set during a traveral if the light center needs to be updated. 23007 */ 23008 boolean mNeedsUpdateLightCenter; 23009 23010 /** 23011 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 23012 */ 23013 int mSystemUiVisibility; 23014 23015 /** 23016 * Hack to force certain system UI visibility flags to be cleared. 23017 */ 23018 int mDisabledSystemUiVisibility; 23019 23020 /** 23021 * Last global system UI visibility reported by the window manager. 23022 */ 23023 int mGlobalSystemUiVisibility = -1; 23024 23025 /** 23026 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 23027 * attached. 23028 */ 23029 boolean mHasSystemUiListeners; 23030 23031 /** 23032 * Set if the window has requested to extend into the overscan region 23033 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 23034 */ 23035 boolean mOverscanRequested; 23036 23037 /** 23038 * Set if the visibility of any views has changed. 23039 */ 23040 boolean mViewVisibilityChanged; 23041 23042 /** 23043 * Set to true if a view has been scrolled. 23044 */ 23045 boolean mViewScrollChanged; 23046 23047 /** 23048 * Set to true if high contrast mode enabled 23049 */ 23050 boolean mHighContrastText; 23051 23052 /** 23053 * Set to true if a pointer event is currently being handled. 23054 */ 23055 boolean mHandlingPointerEvent; 23056 23057 /** 23058 * Global to the view hierarchy used as a temporary for dealing with 23059 * x/y points in the transparent region computations. 23060 */ 23061 final int[] mTransparentLocation = new int[2]; 23062 23063 /** 23064 * Global to the view hierarchy used as a temporary for dealing with 23065 * x/y points in the ViewGroup.invalidateChild implementation. 23066 */ 23067 final int[] mInvalidateChildLocation = new int[2]; 23068 23069 /** 23070 * Global to the view hierarchy used as a temporary for dealing with 23071 * computing absolute on-screen location. 23072 */ 23073 final int[] mTmpLocation = new int[2]; 23074 23075 /** 23076 * Global to the view hierarchy used as a temporary for dealing with 23077 * x/y location when view is transformed. 23078 */ 23079 final float[] mTmpTransformLocation = new float[2]; 23080 23081 /** 23082 * The view tree observer used to dispatch global events like 23083 * layout, pre-draw, touch mode change, etc. 23084 */ 23085 final ViewTreeObserver mTreeObserver = new ViewTreeObserver(); 23086 23087 /** 23088 * A Canvas used by the view hierarchy to perform bitmap caching. 23089 */ 23090 Canvas mCanvas; 23091 23092 /** 23093 * The view root impl. 23094 */ 23095 final ViewRootImpl mViewRootImpl; 23096 23097 /** 23098 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 23099 * handler can be used to pump events in the UI events queue. 23100 */ 23101 final Handler mHandler; 23102 23103 /** 23104 * Temporary for use in computing invalidate rectangles while 23105 * calling up the hierarchy. 23106 */ 23107 final Rect mTmpInvalRect = new Rect(); 23108 23109 /** 23110 * Temporary for use in computing hit areas with transformed views 23111 */ 23112 final RectF mTmpTransformRect = new RectF(); 23113 23114 /** 23115 * Temporary for use in computing hit areas with transformed views 23116 */ 23117 final RectF mTmpTransformRect1 = new RectF(); 23118 23119 /** 23120 * Temporary list of rectanges. 23121 */ 23122 final List<RectF> mTmpRectList = new ArrayList<>(); 23123 23124 /** 23125 * Temporary for use in transforming invalidation rect 23126 */ 23127 final Matrix mTmpMatrix = new Matrix(); 23128 23129 /** 23130 * Temporary for use in transforming invalidation rect 23131 */ 23132 final Transformation mTmpTransformation = new Transformation(); 23133 23134 /** 23135 * Temporary for use in querying outlines from OutlineProviders 23136 */ 23137 final Outline mTmpOutline = new Outline(); 23138 23139 /** 23140 * Temporary list for use in collecting focusable descendents of a view. 23141 */ 23142 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 23143 23144 /** 23145 * The id of the window for accessibility purposes. 23146 */ 23147 int mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED_ITEM_ID; 23148 23149 /** 23150 * Flags related to accessibility processing. 23151 * 23152 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 23153 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 23154 */ 23155 int mAccessibilityFetchFlags; 23156 23157 /** 23158 * The drawable for highlighting accessibility focus. 23159 */ 23160 Drawable mAccessibilityFocusDrawable; 23161 23162 /** 23163 * Show where the margins, bounds and layout bounds are for each view. 23164 */ 23165 boolean mDebugLayout = SystemProperties.getBoolean(DEBUG_LAYOUT_PROPERTY, false); 23166 23167 /** 23168 * Point used to compute visible regions. 23169 */ 23170 final Point mPoint = new Point(); 23171 23172 /** 23173 * Used to track which View originated a requestLayout() call, used when 23174 * requestLayout() is called during layout. 23175 */ 23176 View mViewRequestingLayout; 23177 23178 /** 23179 * Used to track views that need (at least) a partial relayout at their current size 23180 * during the next traversal. 23181 */ 23182 List<View> mPartialLayoutViews = new ArrayList<>(); 23183 23184 /** 23185 * Swapped with mPartialLayoutViews during layout to avoid concurrent 23186 * modification. Lazily assigned during ViewRootImpl layout. 23187 */ 23188 List<View> mEmptyPartialLayoutViews; 23189 23190 /** 23191 * Used to track the identity of the current drag operation. 23192 */ 23193 IBinder mDragToken; 23194 23195 /** 23196 * The drag shadow surface for the current drag operation. 23197 */ 23198 public Surface mDragSurface; 23199 23200 /** 23201 * Creates a new set of attachment information with the specified 23202 * events handler and thread. 23203 * 23204 * @param handler the events handler the view must use 23205 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer)23206 AttachInfo(IWindowSession session, IWindow window, Display display, 23207 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) { 23208 mSession = session; 23209 mWindow = window; 23210 mWindowToken = window.asBinder(); 23211 mDisplay = display; 23212 mViewRootImpl = viewRootImpl; 23213 mHandler = handler; 23214 mRootCallbacks = effectPlayer; 23215 } 23216 } 23217 23218 /** 23219 * <p>ScrollabilityCache holds various fields used by a View when scrolling 23220 * is supported. This avoids keeping too many unused fields in most 23221 * instances of View.</p> 23222 */ 23223 private static class ScrollabilityCache implements Runnable { 23224 23225 /** 23226 * Scrollbars are not visible 23227 */ 23228 public static final int OFF = 0; 23229 23230 /** 23231 * Scrollbars are visible 23232 */ 23233 public static final int ON = 1; 23234 23235 /** 23236 * Scrollbars are fading away 23237 */ 23238 public static final int FADING = 2; 23239 23240 public boolean fadeScrollBars; 23241 23242 public int fadingEdgeLength; 23243 public int scrollBarDefaultDelayBeforeFade; 23244 public int scrollBarFadeDuration; 23245 23246 public int scrollBarSize; 23247 public ScrollBarDrawable scrollBar; 23248 public float[] interpolatorValues; 23249 public View host; 23250 23251 public final Paint paint; 23252 public final Matrix matrix; 23253 public Shader shader; 23254 23255 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 23256 23257 private static final float[] OPAQUE = { 255 }; 23258 private static final float[] TRANSPARENT = { 0.0f }; 23259 23260 /** 23261 * When fading should start. This time moves into the future every time 23262 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 23263 */ 23264 public long fadeStartTime; 23265 23266 23267 /** 23268 * The current state of the scrollbars: ON, OFF, or FADING 23269 */ 23270 public int state = OFF; 23271 23272 private int mLastColor; 23273 23274 public final Rect mScrollBarBounds = new Rect(); 23275 23276 public static final int NOT_DRAGGING = 0; 23277 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 23278 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 23279 public int mScrollBarDraggingState = NOT_DRAGGING; 23280 23281 public float mScrollBarDraggingPos = 0; 23282 ScrollabilityCache(ViewConfiguration configuration, View host)23283 public ScrollabilityCache(ViewConfiguration configuration, View host) { 23284 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 23285 scrollBarSize = configuration.getScaledScrollBarSize(); 23286 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 23287 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 23288 23289 paint = new Paint(); 23290 matrix = new Matrix(); 23291 // use use a height of 1, and then wack the matrix each time we 23292 // actually use it. 23293 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23294 paint.setShader(shader); 23295 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23296 23297 this.host = host; 23298 } 23299 setFadeColor(int color)23300 public void setFadeColor(int color) { 23301 if (color != mLastColor) { 23302 mLastColor = color; 23303 23304 if (color != 0) { 23305 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 23306 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 23307 paint.setShader(shader); 23308 // Restore the default transfer mode (src_over) 23309 paint.setXfermode(null); 23310 } else { 23311 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 23312 paint.setShader(shader); 23313 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 23314 } 23315 } 23316 } 23317 run()23318 public void run() { 23319 long now = AnimationUtils.currentAnimationTimeMillis(); 23320 if (now >= fadeStartTime) { 23321 23322 // the animation fades the scrollbars out by changing 23323 // the opacity (alpha) from fully opaque to fully 23324 // transparent 23325 int nextFrame = (int) now; 23326 int framesCount = 0; 23327 23328 Interpolator interpolator = scrollBarInterpolator; 23329 23330 // Start opaque 23331 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 23332 23333 // End transparent 23334 nextFrame += scrollBarFadeDuration; 23335 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 23336 23337 state = FADING; 23338 23339 // Kick off the fade animation 23340 host.invalidate(true); 23341 } 23342 } 23343 } 23344 23345 /** 23346 * Resuable callback for sending 23347 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 23348 */ 23349 private class SendViewScrolledAccessibilityEvent implements Runnable { 23350 public volatile boolean mIsPending; 23351 run()23352 public void run() { 23353 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); 23354 mIsPending = false; 23355 } 23356 } 23357 23358 /** 23359 * <p> 23360 * This class represents a delegate that can be registered in a {@link View} 23361 * to enhance accessibility support via composition rather via inheritance. 23362 * It is specifically targeted to widget developers that extend basic View 23363 * classes i.e. classes in package android.view, that would like their 23364 * applications to be backwards compatible. 23365 * </p> 23366 * <div class="special reference"> 23367 * <h3>Developer Guides</h3> 23368 * <p>For more information about making applications accessible, read the 23369 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 23370 * developer guide.</p> 23371 * </div> 23372 * <p> 23373 * A scenario in which a developer would like to use an accessibility delegate 23374 * is overriding a method introduced in a later API version then the minimal API 23375 * version supported by the application. For example, the method 23376 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 23377 * in API version 4 when the accessibility APIs were first introduced. If a 23378 * developer would like his application to run on API version 4 devices (assuming 23379 * all other APIs used by the application are version 4 or lower) and take advantage 23380 * of this method, instead of overriding the method which would break the application's 23381 * backwards compatibility, he can override the corresponding method in this 23382 * delegate and register the delegate in the target View if the API version of 23383 * the system is high enough i.e. the API version is same or higher to the API 23384 * version that introduced 23385 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 23386 * </p> 23387 * <p> 23388 * Here is an example implementation: 23389 * </p> 23390 * <code><pre><p> 23391 * if (Build.VERSION.SDK_INT >= 14) { 23392 * // If the API version is equal of higher than the version in 23393 * // which onInitializeAccessibilityNodeInfo was introduced we 23394 * // register a delegate with a customized implementation. 23395 * View view = findViewById(R.id.view_id); 23396 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 23397 * public void onInitializeAccessibilityNodeInfo(View host, 23398 * AccessibilityNodeInfo info) { 23399 * // Let the default implementation populate the info. 23400 * super.onInitializeAccessibilityNodeInfo(host, info); 23401 * // Set some other information. 23402 * info.setEnabled(host.isEnabled()); 23403 * } 23404 * }); 23405 * } 23406 * </code></pre></p> 23407 * <p> 23408 * This delegate contains methods that correspond to the accessibility methods 23409 * in View. If a delegate has been specified the implementation in View hands 23410 * off handling to the corresponding method in this delegate. The default 23411 * implementation the delegate methods behaves exactly as the corresponding 23412 * method in View for the case of no accessibility delegate been set. Hence, 23413 * to customize the behavior of a View method, clients can override only the 23414 * corresponding delegate method without altering the behavior of the rest 23415 * accessibility related methods of the host view. 23416 * </p> 23417 * <p> 23418 * <strong>Note:</strong> On platform versions prior to 23419 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 23420 * views in the {@code android.widget.*} package are called <i>before</i> 23421 * host methods. This prevents certain properties such as class name from 23422 * being modified by overriding 23423 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 23424 * as any changes will be overwritten by the host class. 23425 * <p> 23426 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 23427 * methods are called <i>after</i> host methods, which all properties to be 23428 * modified without being overwritten by the host class. 23429 */ 23430 public static class AccessibilityDelegate { 23431 23432 /** 23433 * Sends an accessibility event of the given type. If accessibility is not 23434 * enabled this method has no effect. 23435 * <p> 23436 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 23437 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 23438 * been set. 23439 * </p> 23440 * 23441 * @param host The View hosting the delegate. 23442 * @param eventType The type of the event to send. 23443 * 23444 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 23445 */ sendAccessibilityEvent(View host, int eventType)23446 public void sendAccessibilityEvent(View host, int eventType) { 23447 host.sendAccessibilityEventInternal(eventType); 23448 } 23449 23450 /** 23451 * Performs the specified accessibility action on the view. For 23452 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 23453 * <p> 23454 * The default implementation behaves as 23455 * {@link View#performAccessibilityAction(int, Bundle) 23456 * View#performAccessibilityAction(int, Bundle)} for the case of 23457 * no accessibility delegate been set. 23458 * </p> 23459 * 23460 * @param action The action to perform. 23461 * @return Whether the action was performed. 23462 * 23463 * @see View#performAccessibilityAction(int, Bundle) 23464 * View#performAccessibilityAction(int, Bundle) 23465 */ performAccessibilityAction(View host, int action, Bundle args)23466 public boolean performAccessibilityAction(View host, int action, Bundle args) { 23467 return host.performAccessibilityActionInternal(action, args); 23468 } 23469 23470 /** 23471 * Sends an accessibility event. This method behaves exactly as 23472 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 23473 * empty {@link AccessibilityEvent} and does not perform a check whether 23474 * accessibility is enabled. 23475 * <p> 23476 * The default implementation behaves as 23477 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 23478 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 23479 * the case of no accessibility delegate been set. 23480 * </p> 23481 * 23482 * @param host The View hosting the delegate. 23483 * @param event The event to send. 23484 * 23485 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 23486 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 23487 */ sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)23488 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 23489 host.sendAccessibilityEventUncheckedInternal(event); 23490 } 23491 23492 /** 23493 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 23494 * to its children for adding their text content to the event. 23495 * <p> 23496 * The default implementation behaves as 23497 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 23498 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 23499 * the case of no accessibility delegate been set. 23500 * </p> 23501 * 23502 * @param host The View hosting the delegate. 23503 * @param event The event. 23504 * @return True if the event population was completed. 23505 * 23506 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 23507 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 23508 */ dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)23509 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 23510 return host.dispatchPopulateAccessibilityEventInternal(event); 23511 } 23512 23513 /** 23514 * Gives a chance to the host View to populate the accessibility event with its 23515 * text content. 23516 * <p> 23517 * The default implementation behaves as 23518 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 23519 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 23520 * the case of no accessibility delegate been set. 23521 * </p> 23522 * 23523 * @param host The View hosting the delegate. 23524 * @param event The accessibility event which to populate. 23525 * 23526 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 23527 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 23528 */ onPopulateAccessibilityEvent(View host, AccessibilityEvent event)23529 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 23530 host.onPopulateAccessibilityEventInternal(event); 23531 } 23532 23533 /** 23534 * Initializes an {@link AccessibilityEvent} with information about the 23535 * the host View which is the event source. 23536 * <p> 23537 * The default implementation behaves as 23538 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 23539 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 23540 * the case of no accessibility delegate been set. 23541 * </p> 23542 * 23543 * @param host The View hosting the delegate. 23544 * @param event The event to initialize. 23545 * 23546 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 23547 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 23548 */ onInitializeAccessibilityEvent(View host, AccessibilityEvent event)23549 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 23550 host.onInitializeAccessibilityEventInternal(event); 23551 } 23552 23553 /** 23554 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 23555 * <p> 23556 * The default implementation behaves as 23557 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 23558 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 23559 * the case of no accessibility delegate been set. 23560 * </p> 23561 * 23562 * @param host The View hosting the delegate. 23563 * @param info The instance to initialize. 23564 * 23565 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 23566 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 23567 */ onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)23568 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 23569 host.onInitializeAccessibilityNodeInfoInternal(info); 23570 } 23571 23572 /** 23573 * Called when a child of the host View has requested sending an 23574 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 23575 * to augment the event. 23576 * <p> 23577 * The default implementation behaves as 23578 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 23579 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 23580 * the case of no accessibility delegate been set. 23581 * </p> 23582 * 23583 * @param host The View hosting the delegate. 23584 * @param child The child which requests sending the event. 23585 * @param event The event to be sent. 23586 * @return True if the event should be sent 23587 * 23588 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 23589 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 23590 */ onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)23591 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 23592 AccessibilityEvent event) { 23593 return host.onRequestSendAccessibilityEventInternal(child, event); 23594 } 23595 23596 /** 23597 * Gets the provider for managing a virtual view hierarchy rooted at this View 23598 * and reported to {@link android.accessibilityservice.AccessibilityService}s 23599 * that explore the window content. 23600 * <p> 23601 * The default implementation behaves as 23602 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 23603 * the case of no accessibility delegate been set. 23604 * </p> 23605 * 23606 * @return The provider. 23607 * 23608 * @see AccessibilityNodeProvider 23609 */ getAccessibilityNodeProvider(View host)23610 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 23611 return null; 23612 } 23613 23614 /** 23615 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 23616 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 23617 * This method is responsible for obtaining an accessibility node info from a 23618 * pool of reusable instances and calling 23619 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 23620 * view to initialize the former. 23621 * <p> 23622 * <strong>Note:</strong> The client is responsible for recycling the obtained 23623 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 23624 * creation. 23625 * </p> 23626 * <p> 23627 * The default implementation behaves as 23628 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 23629 * the case of no accessibility delegate been set. 23630 * </p> 23631 * @return A populated {@link AccessibilityNodeInfo}. 23632 * 23633 * @see AccessibilityNodeInfo 23634 * 23635 * @hide 23636 */ createAccessibilityNodeInfo(View host)23637 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 23638 return host.createAccessibilityNodeInfoInternal(); 23639 } 23640 } 23641 23642 private class MatchIdPredicate implements Predicate<View> { 23643 public int mId; 23644 23645 @Override apply(View view)23646 public boolean apply(View view) { 23647 return (view.mID == mId); 23648 } 23649 } 23650 23651 private class MatchLabelForPredicate implements Predicate<View> { 23652 private int mLabeledId; 23653 23654 @Override apply(View view)23655 public boolean apply(View view) { 23656 return (view.mLabelForId == mLabeledId); 23657 } 23658 } 23659 23660 private class SendViewStateChangedAccessibilityEvent implements Runnable { 23661 private int mChangeTypes = 0; 23662 private boolean mPosted; 23663 private boolean mPostedWithDelay; 23664 private long mLastEventTimeMillis; 23665 23666 @Override run()23667 public void run() { 23668 mPosted = false; 23669 mPostedWithDelay = false; 23670 mLastEventTimeMillis = SystemClock.uptimeMillis(); 23671 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 23672 final AccessibilityEvent event = AccessibilityEvent.obtain(); 23673 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 23674 event.setContentChangeTypes(mChangeTypes); 23675 sendAccessibilityEventUnchecked(event); 23676 } 23677 mChangeTypes = 0; 23678 } 23679 runOrPost(int changeType)23680 public void runOrPost(int changeType) { 23681 mChangeTypes |= changeType; 23682 23683 // If this is a live region or the child of a live region, collect 23684 // all events from this frame and send them on the next frame. 23685 if (inLiveRegion()) { 23686 // If we're already posted with a delay, remove that. 23687 if (mPostedWithDelay) { 23688 removeCallbacks(this); 23689 mPostedWithDelay = false; 23690 } 23691 // Only post if we're not already posted. 23692 if (!mPosted) { 23693 post(this); 23694 mPosted = true; 23695 } 23696 return; 23697 } 23698 23699 if (mPosted) { 23700 return; 23701 } 23702 23703 final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis; 23704 final long minEventIntevalMillis = 23705 ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); 23706 if (timeSinceLastMillis >= minEventIntevalMillis) { 23707 removeCallbacks(this); 23708 run(); 23709 } else { 23710 postDelayed(this, minEventIntevalMillis - timeSinceLastMillis); 23711 mPostedWithDelay = true; 23712 } 23713 } 23714 } 23715 inLiveRegion()23716 private boolean inLiveRegion() { 23717 if (getAccessibilityLiveRegion() != View.ACCESSIBILITY_LIVE_REGION_NONE) { 23718 return true; 23719 } 23720 23721 ViewParent parent = getParent(); 23722 while (parent instanceof View) { 23723 if (((View) parent).getAccessibilityLiveRegion() 23724 != View.ACCESSIBILITY_LIVE_REGION_NONE) { 23725 return true; 23726 } 23727 parent = parent.getParent(); 23728 } 23729 23730 return false; 23731 } 23732 23733 /** 23734 * Dump all private flags in readable format, useful for documentation and 23735 * sanity checking. 23736 */ dumpFlags()23737 private static void dumpFlags() { 23738 final HashMap<String, String> found = Maps.newHashMap(); 23739 try { 23740 for (Field field : View.class.getDeclaredFields()) { 23741 final int modifiers = field.getModifiers(); 23742 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 23743 if (field.getType().equals(int.class)) { 23744 final int value = field.getInt(null); 23745 dumpFlag(found, field.getName(), value); 23746 } else if (field.getType().equals(int[].class)) { 23747 final int[] values = (int[]) field.get(null); 23748 for (int i = 0; i < values.length; i++) { 23749 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 23750 } 23751 } 23752 } 23753 } 23754 } catch (IllegalAccessException e) { 23755 throw new RuntimeException(e); 23756 } 23757 23758 final ArrayList<String> keys = Lists.newArrayList(); 23759 keys.addAll(found.keySet()); 23760 Collections.sort(keys); 23761 for (String key : keys) { 23762 Log.d(VIEW_LOG_TAG, found.get(key)); 23763 } 23764 } 23765 dumpFlag(HashMap<String, String> found, String name, int value)23766 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 23767 // Sort flags by prefix, then by bits, always keeping unique keys 23768 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 23769 final int prefix = name.indexOf('_'); 23770 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 23771 final String output = bits + " " + name; 23772 found.put(key, output); 23773 } 23774 23775 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)23776 public void encode(@NonNull ViewHierarchyEncoder stream) { 23777 stream.beginObject(this); 23778 encodeProperties(stream); 23779 stream.endObject(); 23780 } 23781 23782 /** {@hide} */ 23783 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)23784 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 23785 Object resolveId = ViewDebug.resolveId(getContext(), mID); 23786 if (resolveId instanceof String) { 23787 stream.addProperty("id", (String) resolveId); 23788 } else { 23789 stream.addProperty("id", mID); 23790 } 23791 23792 stream.addProperty("misc:transformation.alpha", 23793 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 23794 stream.addProperty("misc:transitionName", getTransitionName()); 23795 23796 // layout 23797 stream.addProperty("layout:left", mLeft); 23798 stream.addProperty("layout:right", mRight); 23799 stream.addProperty("layout:top", mTop); 23800 stream.addProperty("layout:bottom", mBottom); 23801 stream.addProperty("layout:width", getWidth()); 23802 stream.addProperty("layout:height", getHeight()); 23803 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 23804 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 23805 stream.addProperty("layout:hasTransientState", hasTransientState()); 23806 stream.addProperty("layout:baseline", getBaseline()); 23807 23808 // layout params 23809 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 23810 if (layoutParams != null) { 23811 stream.addPropertyKey("layoutParams"); 23812 layoutParams.encode(stream); 23813 } 23814 23815 // scrolling 23816 stream.addProperty("scrolling:scrollX", mScrollX); 23817 stream.addProperty("scrolling:scrollY", mScrollY); 23818 23819 // padding 23820 stream.addProperty("padding:paddingLeft", mPaddingLeft); 23821 stream.addProperty("padding:paddingRight", mPaddingRight); 23822 stream.addProperty("padding:paddingTop", mPaddingTop); 23823 stream.addProperty("padding:paddingBottom", mPaddingBottom); 23824 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 23825 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 23826 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 23827 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 23828 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 23829 23830 // measurement 23831 stream.addProperty("measurement:minHeight", mMinHeight); 23832 stream.addProperty("measurement:minWidth", mMinWidth); 23833 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 23834 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 23835 23836 // drawing 23837 stream.addProperty("drawing:elevation", getElevation()); 23838 stream.addProperty("drawing:translationX", getTranslationX()); 23839 stream.addProperty("drawing:translationY", getTranslationY()); 23840 stream.addProperty("drawing:translationZ", getTranslationZ()); 23841 stream.addProperty("drawing:rotation", getRotation()); 23842 stream.addProperty("drawing:rotationX", getRotationX()); 23843 stream.addProperty("drawing:rotationY", getRotationY()); 23844 stream.addProperty("drawing:scaleX", getScaleX()); 23845 stream.addProperty("drawing:scaleY", getScaleY()); 23846 stream.addProperty("drawing:pivotX", getPivotX()); 23847 stream.addProperty("drawing:pivotY", getPivotY()); 23848 stream.addProperty("drawing:opaque", isOpaque()); 23849 stream.addProperty("drawing:alpha", getAlpha()); 23850 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 23851 stream.addProperty("drawing:shadow", hasShadow()); 23852 stream.addProperty("drawing:solidColor", getSolidColor()); 23853 stream.addProperty("drawing:layerType", mLayerType); 23854 stream.addProperty("drawing:willNotDraw", willNotDraw()); 23855 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 23856 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 23857 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 23858 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 23859 23860 // focus 23861 stream.addProperty("focus:hasFocus", hasFocus()); 23862 stream.addProperty("focus:isFocused", isFocused()); 23863 stream.addProperty("focus:isFocusable", isFocusable()); 23864 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 23865 23866 stream.addProperty("misc:clickable", isClickable()); 23867 stream.addProperty("misc:pressed", isPressed()); 23868 stream.addProperty("misc:selected", isSelected()); 23869 stream.addProperty("misc:touchMode", isInTouchMode()); 23870 stream.addProperty("misc:hovered", isHovered()); 23871 stream.addProperty("misc:activated", isActivated()); 23872 23873 stream.addProperty("misc:visibility", getVisibility()); 23874 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 23875 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 23876 23877 stream.addProperty("misc:enabled", isEnabled()); 23878 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 23879 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 23880 23881 // theme attributes 23882 Resources.Theme theme = getContext().getTheme(); 23883 if (theme != null) { 23884 stream.addPropertyKey("theme"); 23885 theme.encode(stream); 23886 } 23887 23888 // view attribute information 23889 int n = mAttributes != null ? mAttributes.length : 0; 23890 stream.addProperty("meta:__attrCount__", n/2); 23891 for (int i = 0; i < n; i += 2) { 23892 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 23893 } 23894 23895 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 23896 23897 // text 23898 stream.addProperty("text:textDirection", getTextDirection()); 23899 stream.addProperty("text:textAlignment", getTextAlignment()); 23900 23901 // accessibility 23902 CharSequence contentDescription = getContentDescription(); 23903 stream.addProperty("accessibility:contentDescription", 23904 contentDescription == null ? "" : contentDescription.toString()); 23905 stream.addProperty("accessibility:labelFor", getLabelFor()); 23906 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 23907 } 23908 23909 /** 23910 * Determine if this view is rendered on a round wearable device and is the main view 23911 * on the screen. 23912 */ shouldDrawRoundScrollbar()23913 boolean shouldDrawRoundScrollbar() { 23914 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 23915 return false; 23916 } 23917 23918 final View rootView = getRootView(); 23919 final WindowInsets insets = getRootWindowInsets(); 23920 23921 int height = getHeight(); 23922 int width = getWidth(); 23923 int displayHeight = rootView.getHeight(); 23924 int displayWidth = rootView.getWidth(); 23925 23926 if (height != displayHeight || width != displayWidth) { 23927 return false; 23928 } 23929 23930 getLocationInWindow(mAttachInfo.mTmpLocation); 23931 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 23932 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 23933 } 23934 } 23935